Merge "Fix Array Index out of bounds error." into oc-dev
diff --git a/api/removed.txt b/api/removed.txt
index 1873499..e7b573b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -29,6 +29,8 @@
   }
 
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public deprecated PictureInPictureArgs();
+    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
     method public void copyOnlySet(android.app.PictureInPictureArgs);
@@ -41,6 +43,9 @@
     method public boolean hasSetAspectRatio();
     method public boolean hasSourceBoundsHint();
     method public boolean hasSourceBoundsHintInsets();
+    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
+    method public deprecated void setAspectRatio(float);
+    method public deprecated void setSourceRectHint(android.graphics.Rect);
     method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
     method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 60865a3..15de5c4 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -29,6 +29,8 @@
   }
 
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public deprecated PictureInPictureArgs();
+    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
     method public void copyOnlySet(android.app.PictureInPictureArgs);
@@ -41,6 +43,9 @@
     method public boolean hasSetAspectRatio();
     method public boolean hasSourceBoundsHint();
     method public boolean hasSourceBoundsHintInsets();
+    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
+    method public deprecated void setAspectRatio(float);
+    method public deprecated void setSourceRectHint(android.graphics.Rect);
     method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
     method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 1873499..e7b573b 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -29,6 +29,8 @@
   }
 
   public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public deprecated PictureInPictureArgs();
+    ctor public deprecated PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
     method public void copyOnlySet(android.app.PictureInPictureArgs);
@@ -41,6 +43,9 @@
     method public boolean hasSetAspectRatio();
     method public boolean hasSourceBoundsHint();
     method public boolean hasSourceBoundsHintInsets();
+    method public deprecated void setActions(java.util.List<android.app.RemoteAction>);
+    method public deprecated void setAspectRatio(float);
+    method public deprecated void setSourceRectHint(android.graphics.Rect);
     method public deprecated void setSourceRectHintInsets(android.graphics.Rect);
     method public void truncateActions(int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
diff --git a/core/java/android/app/AuthenticationRequiredException.java b/core/java/android/app/AuthenticationRequiredException.java
index 8960979..04e5e0a 100644
--- a/core/java/android/app/AuthenticationRequiredException.java
+++ b/core/java/android/app/AuthenticationRequiredException.java
@@ -56,10 +56,7 @@
      *            {@link Activity#setResult(int)} before finishing to
      *            communicate the final status of the recovery. For example,
      *            apps that observe {@link Activity#RESULT_OK} may choose to
-     *            immediately retry their operation. If this exception was
-     *            thrown from a {@link ContentProvider}, you should also send
-     *            any relevant {@link ContentResolver#notifyChange} events to
-     *            trigger reloading of data.
+     *            immediately retry their operation.
      */
     public AuthenticationRequiredException(Throwable cause, PendingIntent userAction) {
         super(cause.getMessage());
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index bbcf7ba..b84161c 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1218,6 +1218,7 @@
             private Intent mCurIntent;
             private final boolean mOrdered;
             private boolean mDispatched;
+            private Throwable mPreviousRunStacktrace; // To investigate b/37809561. STOPSHIP remove.
 
             public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                     boolean ordered, boolean sticky, int sendingUser) {
@@ -1243,11 +1244,14 @@
                 final IActivityManager mgr = ActivityManager.getService();
                 final Intent intent = mCurIntent;
                 if (intent == null) {
-                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
+                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
+                            + ": run() previously called at "
+                            + Log.getStackTraceString(mPreviousRunStacktrace));
                 }
 
                 mCurIntent = null;
                 mDispatched = true;
+                mPreviousRunStacktrace = new Throwable("Previous stacktrace");
                 if (receiver == null || intent == null || mForgotten) {
                     if (mRegistered && ordered) {
                         if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c8b8c6c..2e56bcf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4358,6 +4358,8 @@
             mN.mLargeIcon = null;
             Bitmap largeIconLegacy = mN.largeIcon;
             mN.largeIcon = null;
+            ArrayList<Action> actions = mActions;
+            mActions = new ArrayList<>();
             Bundle publicExtras = new Bundle();
             publicExtras.putBoolean(EXTRA_SHOW_WHEN,
                     savedBundle.getBoolean(EXTRA_SHOW_WHEN));
@@ -4373,6 +4375,7 @@
             mN.extras = savedBundle;
             mN.mLargeIcon = largeIcon;
             mN.largeIcon = largeIconLegacy;
+            mActions = actions;
             mStyle = style;
             return view;
         }
diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java
index 88e6b99..d7317f4 100644
--- a/core/java/android/app/PictureInPictureArgs.java
+++ b/core/java/android/app/PictureInPictureArgs.java
@@ -133,7 +133,20 @@
     @Nullable
     private Rect mSourceRectHintInsets;
 
-    private PictureInPictureArgs() {
+    /**
+     * @hide
+     */
+    @Deprecated
+    public PictureInPictureArgs() {
+    }
+
+    /**
+     * @hide
+     */
+    @Deprecated
+    public PictureInPictureArgs(float aspectRatio, List<RemoteAction> actions) {
+        setAspectRatio(aspectRatio);
+        setActions(actions);
     }
 
     private PictureInPictureArgs(Parcel in) {
@@ -160,6 +173,40 @@
     }
 
     /**
+     * @hide
+     */
+    @Deprecated
+    public void setAspectRatio(float aspectRatio) {
+        // Temporary workaround
+        mAspectRatio = new Rational((int) (aspectRatio * 1000000000), 1000000000);
+    }
+
+    /**
+     * @hide
+     */
+    @Deprecated
+    public void setActions(List<RemoteAction> actions) {
+        if (mUserActions != null) {
+            mUserActions = null;
+        }
+        if (actions != null) {
+            mUserActions = new ArrayList<>(actions);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Deprecated
+    public void setSourceRectHint(Rect launchBounds) {
+        if (launchBounds == null) {
+            mSourceRectHint = null;
+        } else {
+            mSourceRectHint = new Rect(launchBounds);
+        }
+    }
+
+    /**
      * Copies the set parameters from the other picture-in-picture args.
      * @hide
      */
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
index a503a46..6747004 100644
--- a/core/java/android/app/RecoverableSecurityException.java
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -76,10 +76,7 @@
      *            {@link Activity#setResult(int)} before finishing to
      *            communicate the final status of the recovery. For example,
      *            apps that observe {@link Activity#RESULT_OK} may choose to
-     *            immediately retry their operation. If this exception was
-     *            thrown from a {@link ContentProvider}, you should also send
-     *            any relevant {@link ContentResolver#notifyChange} events to
-     *            trigger reloading of data.
+     *            immediately retry their operation.
      */
     public RecoverableSecurityException(Throwable cause, CharSequence userMessage,
             RemoteAction userAction) {
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c427268..e8ad69d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1703,7 +1703,7 @@
      *             an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
      *             if {@code autoConnect} is set to true.
      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
-     *             on the service's main thread.
+     *             on an un-specified background thread.
      * @throws NullPointerException if callback is null
      */
     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
@@ -1712,9 +1712,6 @@
         if (callback == null)
             throw new NullPointerException("callback is null");
 
-        if (handler == null)
-            handler = new Handler(Looper.getMainLooper());
-
         // TODO(Bluetooth) check whether platform support BLE
         //     Do the check here or in GattServer?
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 0f01d62..5fabbb6 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -156,7 +156,7 @@
                 }
                 mClientIf = clientIf;
                 if (status != GATT_SUCCESS) {
-                    mHandler.post(new Runnable() {
+                    runOrQueueCallback(new Runnable() {
                         @Override
                         public void run() {
                             if (mCallback != null) {
@@ -191,7 +191,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -213,7 +213,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -238,7 +238,7 @@
                 int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
                                                BluetoothProfile.STATE_DISCONNECTED;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -300,7 +300,7 @@
                     }
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -352,7 +352,7 @@
 
                 if (status == 0) characteristic.setValue(value);
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -401,7 +401,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -430,7 +430,7 @@
 
                 characteristic.setValue(value);
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -477,7 +477,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -523,7 +523,7 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -549,7 +549,7 @@
                     mDeviceBusy = false;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -570,7 +570,7 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -592,7 +592,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -616,7 +616,7 @@
                     return;
                 }
 
-                mHandler.post(new Runnable() {
+                runOrQueueCallback(new Runnable() {
                     @Override
                     public void run() {
                         if (mCallback != null) {
@@ -703,6 +703,22 @@
     }
 
     /**
+     * Queue the runnable on a {@link Handler} provided by the user, or execute the runnable
+     * immediately if no Handler was provided.
+     */
+    private void runOrQueueCallback(final Runnable cb) {
+        if (mHandler == null) {
+          try {
+            cb.run();
+          } catch (Exception ex) {
+            Log.w(TAG, "Unhandled exception in callback", ex);
+          }
+        } else {
+          mHandler.post(cb);
+        }
+    }
+
+    /**
      * Register an application callback to start using GATT.
      *
      * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index aaaff0c..4e11233 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -26,6 +26,7 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.PackageManager.InstallReason;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.FileBridge;
@@ -948,7 +949,7 @@
         /** {@hide} */
         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
         /** {@hide} */
-        public int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+        public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
         /** {@hide} */
         public long sizeBytes = -1;
         /** {@hide} */
@@ -1146,7 +1147,10 @@
             }
         }
 
-        public void setInstallReason(int installReason) {
+        /**
+         * Set the reason for installing this package.
+         */
+        public void setInstallReason(@InstallReason int installReason) {
             this.installReason = installReason;
         }
 
@@ -1236,7 +1240,7 @@
         /** {@hide} */
         public int mode;
         /** {@hide} */
-        public int installReason;
+        public @InstallReason int installReason;
         /** {@hide} */
         public long sizeBytes;
         /** {@hide} */
@@ -1324,9 +1328,9 @@
         /**
          * Return the reason for installing this package.
          *
-         * @see PackageManager#INSTALL_REASON_UNKNOWN
+         * @return The install reason.
          */
-        public int getInstallReason() {
+        public @InstallReason int getInstallReason() {
             return installReason;
         }
 
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 44addfc..a01b8ed 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -87,16 +87,6 @@
     public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
 
     /**
-     * Used by the window manager to override the button brightness based on the
-     * current foreground activity.
-     *
-     * This method must only be called by the window manager.
-     *
-     * @param brightness The overridden brightness, or -1 to disable the override.
-     */
-    public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness);
-
-    /**
      * Used by the window manager to override the user activity timeout based on the
      * current foreground activity.  It can only be used to make the timeout shorter
      * than usual, not longer.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f215ae7..024738a 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6789,7 +6789,8 @@
          * Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
          * @hide
          */
-        public static final String NIGHT_DISPLAY_CUSTOM_START_TIME = "night_display_custom_start_time";
+        public static final String NIGHT_DISPLAY_CUSTOM_START_TIME =
+                "night_display_custom_start_time";
 
         /**
          * Custom time when Night display is scheduled to deactivate.
@@ -6799,6 +6800,14 @@
         public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
 
         /**
+         * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
+         * whether to apply the current activated state after a reboot or user change.
+         * @hide
+         */
+        public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
+                "night_display_last_activated_time";
+
+        /**
          * Names of the service components that the current user has explicitly allowed to
          * be a VR mode listener, separated by ':'.
          *
@@ -7024,6 +7033,7 @@
             NIGHT_DISPLAY_CUSTOM_END_TIME,
             NIGHT_DISPLAY_COLOR_TEMPERATURE,
             NIGHT_DISPLAY_AUTO_MODE,
+            NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
             NIGHT_DISPLAY_ACTIVATED,
             SYNC_PARENT_SOUNDS,
             CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index ebf1c01..209ff09 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -607,6 +607,7 @@
         @Nullable
         public static Intent create(Context context, String type, String text) {
             type = type.trim().toLowerCase(Locale.ENGLISH);
+            text = text.trim();
             switch (type) {
                 case TextClassifier.TYPE_EMAIL:
                     return new Intent(Intent.ACTION_SENDTO)
@@ -618,6 +619,9 @@
                     return new Intent(Intent.ACTION_VIEW)
                             .setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
                 case TextClassifier.TYPE_URL:
+                    if (!text.startsWith("https://") && !text.startsWith("http://")) {
+                        text = "http://" + text;
+                    }
                     return new Intent(Intent.ACTION_VIEW, Uri.parse(text))
                             .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
                 default:
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 569fe01..1457d02 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -49,6 +49,7 @@
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 
 import com.google.android.collect.Lists;
 
@@ -335,6 +336,11 @@
      * @param isSelectable whether the item is selectable
      */
     public void addHeaderView(View v, Object data, boolean isSelectable) {
+        Preconditions.checkState(
+                v.getParent() == null,
+                "The specified child already has a parent. "
+                + "You must call removeView() on the child's parent first.");
+
         final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
@@ -429,6 +435,11 @@
      * @param isSelectable true if the footer view can be selected
      */
     public void addFooterView(View v, Object data, boolean isSelectable) {
+        Preconditions.checkState(
+                v.getParent() == null,
+                "The specified child already has a parent. "
+                + "You must call removeView() on the child's parent first.");
+
         final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4507917..c9d172f 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,6 +33,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
@@ -310,6 +311,13 @@
         /** End index relative to mTrimmedText */
         private int mRelativeEnd;
 
+        /** Information about the last classified text to avoid re-running a query. */
+        private CharSequence mLastClassificationText;
+        private int mLastClassificationSelectionStart;
+        private int mLastClassificationSelectionEnd;
+        private LocaleList mLastClassificationLocales;
+        private SelectionResult mLastClassificationResult;
+
         TextClassificationHelper(TextClassifier textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             reset(textClassifier, text, selectionStart, selectionEnd, locales);
@@ -328,12 +336,25 @@
 
         @WorkerThread
         public SelectionResult classifyText() {
-            trimText();
-            return new SelectionResult(
-                    mSelectionStart,
-                    mSelectionEnd,
-                    mTextClassifier.classifyText(
-                            mTrimmedText, mRelativeStart, mRelativeEnd, mLocales));
+            if (!Objects.equals(mText, mLastClassificationText)
+                    || mSelectionStart != mLastClassificationSelectionStart
+                    || mSelectionEnd != mLastClassificationSelectionEnd
+                    || !Objects.equals(mLocales, mLastClassificationLocales)) {
+
+                mLastClassificationText = mText;
+                mLastClassificationSelectionStart = mSelectionStart;
+                mLastClassificationSelectionEnd = mSelectionEnd;
+                mLastClassificationLocales = mLocales;
+
+                trimText();
+                mLastClassificationResult = new SelectionResult(
+                        mSelectionStart,
+                        mSelectionEnd,
+                        mTextClassifier.classifyText(
+                                mTrimmedText, mRelativeStart, mRelativeEnd, mLocales));
+
+            }
+            return mLastClassificationResult;
         }
 
         @WorkerThread
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 7b2efea..58a2b0f 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -708,18 +708,20 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (isInPlaybackState() && mMediaController != null) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN
+                && isInPlaybackState() && mMediaController != null) {
             toggleMediaControlsVisiblity();
         }
-        return false;
+        return super.onTouchEvent(ev);
     }
 
     @Override
     public boolean onTrackballEvent(MotionEvent ev) {
-        if (isInPlaybackState() && mMediaController != null) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN
+                && isInPlaybackState() && mMediaController != null) {
             toggleMediaControlsVisiblity();
         }
-        return false;
+        return super.onTrackballEvent(ev);
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index e8bebb7..ee5f6fd 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -97,7 +97,8 @@
             final List<ResolveInfo> infos = mpm.queryIntentActivities(intent,
                     PackageManager.MATCH_DEFAULT_ONLY
                             | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
-                            | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0));
+                            | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0)
+                            | PackageManager.MATCH_INSTANT);
             if (infos != null) {
                 if (resolvedComponents == null) {
                     resolvedComponents = new ArrayList<>();
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 372607d..369bb7f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -526,7 +526,7 @@
 /*
  * Reads a "property" into "buffer". If the property is non-empty, it
  * is treated as a dex2oat compiler option that should be
- * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=assume-verified".
  *
  * The "compilerArg" is a prefix for the option such as "--compiler-filter=".
  *
@@ -774,7 +774,7 @@
                                "-Xmx", "-Ximage-compiler-option");
     if (skip_compilation) {
         addOption("-Ximage-compiler-option");
-        addOption("--compiler-filter=verify-none");
+        addOption("--compiler-filter=assume-verified");
     } else {
         parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                             "--compiler-filter=", "-Ximage-compiler-option");
@@ -805,7 +805,7 @@
                                "-Xmx", "-Xcompiler-option");
     if (skip_compilation) {
         addOption("-Xcompiler-option");
-        addOption("--compiler-filter=verify-none");
+        addOption("--compiler-filter=assume-verified");
 
         // We skip compilation when a minimal runtime is brought up for decryption. In that case
         // /data is temporarily backed by a tmpfs, which is usually small.
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
index 5ed6ce5..bc9f44d 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -16,17 +16,26 @@
 
 package android.text;
 
-import junit.framework.TestCase;
-
 import static android.text.Layout.Alignment.ALIGN_NORMAL;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
- * Tests DynamciLayout updateBlocks method.
+ * Tests DynamicLayout updateBlocks method.
  *
  * Requires disabling access checks in the vm since this calls package-private APIs.
  *
  */
-public class DynamicLayoutBlocksTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DynamicLayoutBlocksTest {
     private DynamicLayout dl = new DynamicLayout("", new TextPaint(), 0, ALIGN_NORMAL, 0, 0, false);
     private static final int ___ = DynamicLayout.INVALID_BLOCK_INDEX;
 
@@ -88,6 +97,7 @@
         assertState(sizes, ids);
     }
 
+    @Test
     public void testFrom0() {
         defineInitialState( new int[] { 0 }, new int[] { 123 });
 
@@ -101,6 +111,7 @@
         assertState( new int[] { 10 } );
     }
 
+    @Test
     public void testFrom1ReplaceByEmpty() {
         defineInitialState( new int[] { 100 }, new int[] { 123 });
 
@@ -126,6 +137,7 @@
         assertState( new int[] { 100 } );
     }
 
+    @Test
     public void testFrom1ReplaceFromFirstLine() {
         defineInitialState( new int[] { 100 }, new int[] { 123 });
 
@@ -142,6 +154,7 @@
         assertState( new int[] { 20 } );
     }
 
+    @Test
     public void testFrom1ReplaceFromCenter() {
         defineInitialState( new int[] { 100 }, new int[] { 123 });
 
@@ -158,6 +171,7 @@
         assertState( new int[] { 20, 50 } );
     }
 
+    @Test
     public void testFrom1ReplaceFromEnd() {
         defineInitialState( new int[] { 100 }, new int[] { 123 });
 
@@ -171,6 +185,7 @@
         assertState( new int[] { 100, 10 } );
     }
 
+    @Test
     public void testFrom2ReplaceFromFirstLine() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -187,6 +202,7 @@
         assertState( new int[] { 50 }, new int[] { ___ } );
     }
 
+    @Test
     public void testFrom2ReplaceFromFirstBlock() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -203,6 +219,7 @@
         assertState( new int[] { 3, 50 }, new int[] { ___, ___ } );
     }
 
+    @Test
     public void testFrom2ReplaceFromBottomBoundary() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -216,6 +233,7 @@
         assertState( new int[] { 10, 50 }, new int[] { ___, ___ } );
     }
 
+    @Test
     public void testFrom2ReplaceFromTopBoundary() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -229,6 +247,7 @@
         assertState( new int[] { 11, 50 }, new int[] { 123, ___ } );
     }
 
+    @Test
     public void testFrom2ReplaceFromSecondBlock() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -242,6 +261,7 @@
         assertState( new int[] { 11, 14-11, 50 }, new int[] { 123, ___, ___ } );
     }
 
+    @Test
     public void testFrom2RemoveFromFirst() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -258,6 +278,7 @@
         assertState( new int[] { 0 }, new int[] { ___ } );
     }
 
+    @Test
     public void testFrom2RemoveFromFirstBlock() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -274,6 +295,7 @@
         assertState( new int[] { 4 }, new int[] { ___ } );
     }
 
+    @Test
     public void testFrom2RemoveFromSecondBlock() {
         defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
 
@@ -284,6 +306,7 @@
         assertState( new int[] { 11, 14-11 }, new int[] { 123, ___ } );
     }
 
+    @Test
     public void testFrom3ReplaceFromFirstBlock() {
         defineInitialState( new int[] { 10, 30, 60 }, new int[] { 123, 456, 789 });
 
@@ -306,6 +329,7 @@
         assertState( new int[] { 3, 50 }, new int[] { ___, ___ } );
     }
 
+    @Test
     public void testFrom3ReplaceFromSecondBlock() {
         defineInitialState( new int[] { 10, 30, 60 }, new int[] { 123, 456, 789 });
 
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index 9362ed9..da6dc7e 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -17,16 +17,28 @@
 package android.text;
 
 import static android.text.Layout.Alignment.ALIGN_NORMAL;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.ReplacementSpan;
-import junit.framework.TestCase;
 
-public class DynamicLayoutTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DynamicLayoutTest {
     private static final int WIDTH = 10000;
 
+    @Test
     public void testGetBlocksAlwaysNeedToBeRedrawn_en() {
         final SpannableStringBuilder builder = new SpannableStringBuilder();
         final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
@@ -42,19 +54,7 @@
         assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
     }
 
-
-    private static class MockReplacementSpan extends ReplacementSpan {
-        @Override
-        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
-            return 10;
-        }
-
-        @Override
-        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
-                int y, int bottom, Paint paint) {
-        }
-    }
-
+    @Test
     public void testGetBlocksAlwaysNeedToBeRedrawn_replacementSpan() {
         final SpannableStringBuilder builder = new SpannableStringBuilder();
         final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
@@ -66,11 +66,17 @@
         builder.append("hijk lmn\n");
         assertNull(layout.getBlocksAlwaysNeedToBeRedrawn());
 
-        builder.setSpan(new MockReplacementSpan(), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        ReplacementSpan mockReplacementSpan = mock(ReplacementSpan.class);
+        when(mockReplacementSpan.getSize(any(), any(), any(), any(), any()))
+            .thenReturn(10);
+        doNothing().when(mockReplacementSpan)
+            .draw(any(), any(), any(), any(), any(), any(), any(), any(), any());
+
+        builder.setSpan(mockReplacementSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         assertNotNull(layout.getBlocksAlwaysNeedToBeRedrawn());
         assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
 
-        builder.setSpan(new MockReplacementSpan(), 9, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        builder.setSpan(mockReplacementSpan, 9, 13, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(0));
         assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().contains(1));
 
@@ -83,6 +89,7 @@
         assertTrue(layout.getBlocksAlwaysNeedToBeRedrawn().isEmpty());
     }
 
+    @Test
     public void testGetBlocksAlwaysNeedToBeRedrawn_thai() {
         final SpannableStringBuilder builder = new SpannableStringBuilder();
         final DynamicLayout layout = new DynamicLayout(builder, new TextPaint(), WIDTH,
diff --git a/core/tests/coretests/src/android/text/PackedIntVectorTest.java b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
index 1aab8af..9df0f89 100644
--- a/core/tests/coretests/src/android/text/PackedIntVectorTest.java
+++ b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
@@ -16,17 +16,23 @@
 
 package android.text;
 
-import android.support.test.filters.SmallTest;
+import static org.junit.Assert.assertEquals;
 
-import junit.framework.TestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * PackedIntVectorTest tests the features of android.util.PackedIntVector.
  */
-public class PackedIntVectorTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PackedIntVectorTest {
 
-    @SmallTest
-    public void testBasic() throws Exception {
+    @Test
+    public void testBasic() {
         for (int width = 0; width < 10; width++) {
             PackedIntVector p = new PackedIntVector(width);
             int[] ins = new int[width];
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index d6f0244..5ed6250 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -16,15 +16,20 @@
 
 package android.text;
 
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.MediumTest;
 
-public abstract class SpannableTest extends InstrumentationTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public abstract class SpannableTest {
 
     protected abstract Spannable newSpannableWithText(String text);
 
-    @MediumTest
+    @Test
     public void testGetSpans() {
         Spannable spannable = newSpannableWithText("abcdef");
         Object emptySpan = new Object();
diff --git a/core/tests/coretests/src/android/text/SpannedTest.java b/core/tests/coretests/src/android/text/SpannedTest.java
index 911da4b..60cddb08 100644
--- a/core/tests/coretests/src/android/text/SpannedTest.java
+++ b/core/tests/coretests/src/android/text/SpannedTest.java
@@ -16,34 +16,40 @@
 
 package android.text;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Typeface;
 import android.os.Parcel;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.CharacterStyle;
 import android.text.style.StyleSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.TypefaceSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * SpannedTest tests some features of Spanned
  */
-public class SpannedTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannedTest {
     private int mExpect;
 
-    @SmallTest
-    public void testSpannableString() throws Exception {
+    @Test
+    public void testSpannableString() {
         checkPriority(new SpannableString("the quick brown fox"));
     }
 
-    @SmallTest
-    public void testSpannableStringBuilder() throws Exception {
+    @Test
+    public void testSpannableStringBuilder() {
         checkPriority2(new SpannableStringBuilder("the quick brown fox"));
     }
 
-    @SmallTest
-    public void testAppend() throws Exception {
+    @Test
+    public void testAppend() {
         Object o = new Object();
         SpannableString ss = new SpannableString("Test");
         ss.setSpan(o, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -61,7 +67,7 @@
         assertEquals(1, ssb.getSpans(4, 8, Object.class).length);
     }
 
-    @SmallTest
+    @Test
     public void testWrapParcel() {
         SpannableString s = new SpannableString("Hello there world");
         CharacterStyle mark = new StyleSpan(Typeface.BOLD);
@@ -129,16 +135,16 @@
 
         mExpect = 0;
 
-        s.setSpan(new Watcher(2), 0, s.length(), 
+        s.setSpan(new Watcher(2), 0, s.length(),
                   Spannable.SPAN_INCLUSIVE_INCLUSIVE |
                   (2 << Spannable.SPAN_PRIORITY_SHIFT));
-        s.setSpan(new Watcher(4), 0, s.length(), 
+        s.setSpan(new Watcher(4), 0, s.length(),
                   Spannable.SPAN_INCLUSIVE_INCLUSIVE |
                   (4 << Spannable.SPAN_PRIORITY_SHIFT));
-        s.setSpan(new Watcher(1), 0, s.length(), 
+        s.setSpan(new Watcher(1), 0, s.length(),
                   Spannable.SPAN_INCLUSIVE_INCLUSIVE |
                   (1 << Spannable.SPAN_PRIORITY_SHIFT));
-        s.setSpan(new Watcher(3), 0, s.length(), 
+        s.setSpan(new Watcher(3), 0, s.length(),
                   Spannable.SPAN_INCLUSIVE_INCLUSIVE |
                   (3 << Spannable.SPAN_PRIORITY_SHIFT));
 
@@ -162,10 +168,13 @@
             mSequence = sequence;
         }
 
-        public void onSpanChanged(Spannable b, Object o, int s, int e,
-                                  int st, int en) { }
+        @Override
+        public void onSpanChanged(Spannable b, Object o, int s, int e, int st, int en) { }
+
+        @Override
         public void onSpanRemoved(Spannable b, Object o, int s, int e) { }
 
+        @Override
         public void onSpanAdded(Spannable b, Object o, int s, int e) {
             if (mExpect != 0) {
                 assertEquals(mSequence, mExpect);
@@ -173,16 +182,18 @@
             }
         }
 
-        public void beforeTextChanged(CharSequence s, int start, int count,
-                                      int after) { }
-        public void onTextChanged(CharSequence s, int start, int before,
-                                      int count) {
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
             if (mExpect != 0) {
                 assertEquals(mSequence, mExpect);
                 mExpect = mSequence - 1;
             }
         }
 
+        @Override
         public void afterTextChanged(Editable s) { }
     }
 }
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index a9865f8..d16cce8 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -16,15 +16,21 @@
 
 package android.text;
 
+import static org.junit.Assert.assertEquals;
+
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Quick check of native bidi implementation.
  */
-public class StaticLayoutBidiTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutBidiTest {
 
     public static final int REQ_DL = 2; // Layout.DIR_REQUEST_DEFAULT_LTR;
     public static final int REQ_DR = -2; // Layout.DIR_REQUEST_DEFAULT_RTL;
@@ -39,47 +45,47 @@
     public static final String GIMEL = "\u05d2";
     public static final String DALET = "\u05d3";
 
-    @SmallTest
+    @Test
     public void testAllLtr() {
         expectNativeBidi(REQ_DL, "a test", "000000", L);
     }
 
-    @SmallTest
+    @Test
     public void testLtrRtl() {
         expectNativeBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
     }
 
-    @SmallTest
+    @Test
     public void testAllRtl() {
         expectNativeBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
     }
 
-    @SmallTest
+    @Test
     public void testRtlLtr() {
         expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
     }
 
-    @SmallTest
+    @Test
     public void testRAllLtr() {
         expectNativeBidi(REQ_R, "a test", "222222", R);
     }
 
-    @SmallTest
+    @Test
     public void testRLtrRtl() {
         expectNativeBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "2221111", R);
     }
 
-    @SmallTest
+    @Test
     public void testLAllRtl() {
         expectNativeBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
     }
 
-    @SmallTest
+    @Test
     public void testLRtlLtr() {
         expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
     }
 
-    @SmallTest
+    @Test
     public void testNativeBidi() {
         expectNativeBidi(REQ_L,  ALEF + BET + GIMEL + " abc", "1110000", L);
     }
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
index 2300c63..e0b4776 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -16,16 +16,21 @@
 
 package android.text;
 
+import static org.junit.Assert.fail;
+
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Directions;
 import android.text.StaticLayoutTest.LayoutBuilder;
 
-import junit.framework.TestCase;
-
 import java.util.Arrays;
 import java.util.Formatter;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class StaticLayoutDirectionsTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutDirectionsTest {
     private static final char ALEF = '\u05d0';
 
     private static Directions dirs(int ... dirs) {
@@ -107,7 +112,7 @@
         return new String(chars, 0, chars.length);
     }
 
-    @SmallTest
+    @Test
     public void testDirections() {
         StringBuilder buf = new StringBuilder("\n");
         Formatter f = new Formatter(buf);
@@ -122,7 +127,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testTrailingWhitespace() {
         LayoutBuilder b = StaticLayoutTest.builder();
         b.setText(pseudoBidiToReal("Ab   c"));
@@ -137,7 +142,7 @@
         expectDirections("split line", expected, result);
     }
 
-    @SmallTest
+    @Test
     public void testNextToRightOf() {
         LayoutBuilder b = StaticLayoutTest.builder();
         b.setText(pseudoBidiToReal("aA1B2"));
@@ -161,7 +166,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testNextToLeftOf() {
         LayoutBuilder b = StaticLayoutTest.builder();
         b.setText(pseudoBidiToReal("aA1B2"));
@@ -178,40 +183,6 @@
         }
     }
 
-    // utility, not really a test
-    /*
-    public void testMeasureText1() {
-        LayoutBuilder b = StaticLayoutTest.builder();
-        String text = "ABC"; // "abAB"
-        b.setText(pseudoBidiToReal(text));
-        Layout l = b.build();
-        Directions directions = l.getLineDirections(0);
-
-        TextPaint workPaint = new TextPaint();
-
-        int dir = -1; // LEFT_TO_RIGHT
-        boolean trailing = true;
-        boolean alt = true;
-        do {
-            dir = -dir;
-            do {
-                trailing = !trailing;
-                for (int offset = 0, end = b.text.length(); offset <= end; ++offset) {
-                    float width = Layout.measureText(b.paint,
-                            workPaint,
-                            b.text,
-                            0, offset, end,
-                            dir, directions,
-                            trailing, false,
-                            null);
-                    Log.i("BIDI", "dir: " + dir + " trail: " + trailing +
-                            " offset: " + offset + " width: " + width);
-                }
-            } while (!trailing);
-        } while (dir > 0);
-    }
-    */
-
     // utility for displaying arrays in hex
     private static String hexArray(int[] array) {
         StringBuilder sb = new StringBuilder();
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 436840c..b7ca219 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -16,25 +16,30 @@
 
 package android.text;
 
+import static android.text.Layout.Alignment.ALIGN_NORMAL;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Paint.FontMetricsInt;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.method.EditorState;
 import android.util.Log;
 
-import junit.framework.TestCase;
-
-import static android.text.Layout.Alignment.ALIGN_NORMAL;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests StaticLayout vertical metrics behavior.
  */
-public class StaticLayoutTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutTest {
     /**
      * Basic test showing expected behavior and relationship between font
      * metrics and line metrics.
      */
-    @SmallTest
+    @Test
     public void testGetters1() {
         LayoutBuilder b = builder();
         FontMetricsInt fmi = b.paint.getFontMetricsInt();
@@ -60,7 +65,7 @@
      * Basic test showing effect of includePad = true with 1 line.
      * Top and bottom padding are affected, as is the line descent and height.
      */
-    @SmallTest
+    @Test
     public void testGetters2() {
         LayoutBuilder b = builder()
             .setIncludePad(true);
@@ -75,7 +80,7 @@
      * Basic test showing effect of includePad = true wrapping to 2 lines.
      * Ascent of top line and descent of bottom line are affected.
      */
-    @SmallTest
+    @Test
     public void testGetters3() {
         LayoutBuilder b = builder()
             .setIncludePad(true)
@@ -92,7 +97,7 @@
      * Basic test showing effect of includePad = true wrapping to 3 lines.
      * First line ascent is top, bottom line descent is bottom.
      */
-    @SmallTest
+    @Test
     public void testGetters4() {
         LayoutBuilder b = builder()
             .setText("This is a longer test")
@@ -112,7 +117,7 @@
      * large text. See effect of leading. Currently, we don't expect there to
      * even be non-zero leading.
      */
-    @SmallTest
+    @Test
     public void testGetters5() {
         LayoutBuilder b = builder()
             .setText("This is a longer test")
@@ -139,7 +144,7 @@
      * Basic test showing effect of includePad = true, spacingAdd = 2, wrapping
      * to 3 lines.
      */
-    @SmallTest
+    @Test
     public void testGetters6() {
         int spacingAdd = 2; // int so expressions return int
         LayoutBuilder b = builder()
@@ -160,7 +165,7 @@
      * Basic test showing effect of includePad = true, spacingAdd = 2,
      * spacingMult = 1.5, wrapping to 3 lines.
      */
-    @SmallTest
+    @Test
     public void testGetters7() {
         LayoutBuilder b = builder()
             .setText("This is a longer test")
@@ -182,7 +187,7 @@
      * Basic test showing effect of includePad = true, spacingAdd = 0,
      * spacingMult = 0.8 when wrapping to 3 lines.
      */
-    @SmallTest
+    @Test
     public void testGetters8() {
         LayoutBuilder b = builder()
             .setText("This is a longer test")
@@ -336,6 +341,7 @@
      * Tests for keycap, variation selectors, flags are in CTS.
      * See {@link android.text.cts.StaticLayoutTest}.
      */
+    @Test
     public void testEmojiOffset() {
         EditorState state = new EditorState();
         TextPaint paint = new TextPaint();
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
index 7e07acb..f6888e3 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -16,15 +16,23 @@
 
 package android.text;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for text measuring methods of StaticLayout.
  */
-public class StaticLayoutTextMeasuringTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutTextMeasuringTest {
     private static final float SPACE_MULTI = 1.0f;
     private static final float SPACE_ADD = 0.0f;
     private static final int DEFAULT_OUTER_WIDTH = 150;
@@ -32,37 +40,36 @@
 
     private TextPaint mDefaultPaint;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         if (mDefaultPaint == null) {
             mDefaultPaint = new TextPaint();
         }
     }
 
-    @SmallTest
+    @Test
     public void testGetPrimaryHorizontal_zwnbsp() {
         // a, ZERO WIDTH NO-BREAK SPACE
         String testString = "a\uFEFF";
         StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
                 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
 
-        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
-        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0), 0f);
+        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1), 0f);
     }
 
-    @SmallTest
+    @Test
     public void testGetPrimaryHorizontal_devanagari() {
         // DEVANAGARI LETTER KA, DEVANAGARI VOWEL SIGN AA
         String testString = "\u0915\u093E";
         StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
                 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
 
-        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
-        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0), 0f);
+        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1), 0f);
     }
 
-    @SmallTest
+    @Test
     public void testGetPrimaryHorizontal_flagEmoji() {
         // REGIONAL INDICATOR SYMBOL LETTER U, REGIONAL INDICATOR SYMBOL LETTER S, REGIONAL
         // INDICATOR SYMBOL LETTER Z
@@ -71,12 +78,12 @@
         StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
                 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
 
-        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
-        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(1));
-        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(2));
-        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(3));
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0), 0f);
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(1), 0f);
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(2), 0f);
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(3), 0f);
 
         assertTrue(layout.getPrimaryHorizontal(6) > layout.getPrimaryHorizontal(4));
-        assertEquals(layout.getPrimaryHorizontal(6), layout.getPrimaryHorizontal(5));
+        assertEquals(layout.getPrimaryHorizontal(6), layout.getPrimaryHorizontal(5), 0f);
     }
 }
diff --git a/core/tests/coretests/src/android/text/TextLayoutTest.java b/core/tests/coretests/src/android/text/TextLayoutTest.java
index f3a28b4..8963189 100644
--- a/core/tests/coretests/src/android/text/TextLayoutTest.java
+++ b/core/tests/coretests/src/android/text/TextLayoutTest.java
@@ -17,31 +17,34 @@
 package android.text;
 
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextLayoutTest {
+    private String mString;
+    private TextPaint mPaint;
 
-public class TextLayoutTest extends TestCase {
-
-    protected String mString;
-    protected TextPaint mPaint;
-
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mString = "The quick brown fox";
         mPaint = new TextPaint();
     }
 
-    @SmallTest
-    public void testStaticLayout() throws Exception {
-        Layout l = new StaticLayout(mString, mPaint, 200,
+    @Test
+    public void testStaticLayout() {
+        new StaticLayout(mString, mPaint, 200,
                 Layout.Alignment.ALIGN_NORMAL, 1, 0,
                 true);
     }
 
-    @SmallTest
-    public void testDynamicLayoutTest() throws Exception {
-        Layout l = new DynamicLayout(mString, mPaint, 200,
+    @Test
+    public void testDynamicLayoutTest() {
+        new DynamicLayout(mString, mPaint, 200,
                 Layout.Alignment.ALIGN_NORMAL, 1, 0,
                 true);
     }
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 26aabdb..312c4fb 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -16,6 +16,14 @@
 
 package android.text;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.runner.AndroidJUnit4;
 import com.google.android.collect.Lists;
 
 import android.os.Parcel;
@@ -27,19 +35,21 @@
 import android.text.util.Rfc822Tokenizer;
 import android.view.View;
 
-import junit.framework.TestCase;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * TextUtilsTest tests {@link TextUtils}.
  */
-public class TextUtilsTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextUtilsTest {
 
-    @SmallTest
-    public void testBasic() throws Exception {
+    @Test
+    public void testBasic() {
         assertEquals("", TextUtils.concat());
         assertEquals("foo", TextUtils.concat("foo"));
         assertEquals("foobar", TextUtils.concat("foo", "bar"));
@@ -71,8 +81,8 @@
         assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString);
     }
 
-    @SmallTest
-    public void testTemplateString() throws Exception {
+    @Test
+    public void testTemplateString() {
         CharSequence result;
 
         result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.",
@@ -136,7 +146,7 @@
 
     /** Fail unless text+spans contains a span 'spanName' with the given start and end. */
     private void checkContains(Spanned text, String[] spans, String spanName,
-                               int start, int end) throws Exception {
+                               int start, int end) {
         for (String i: spans) {
             if (i.equals(spanName)) {
                 assertEquals(start, text.getSpanStart(i));
@@ -147,8 +157,8 @@
         fail();
     }
 
-    @SmallTest
-    public void testTemplateSpan() throws Exception {
+    @Test
+    public void testTemplateSpan() {
         SpannableString template;
         Spanned result;
         String[] spans;
@@ -186,27 +196,27 @@
         checkContains(result, spans, "during+after", 1, 2);
     }
 
-    @SmallTest
+    @Test
     public void testStringSplitterSimple() {
         stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"});
     }
 
-    @SmallTest
+    @Test
     public void testStringSplitterEmpty() {
         stringSplitterTestHelper("", new String[] {});
     }
 
-    @SmallTest
+    @Test
     public void testStringSplitterWithLeadingEmptyString() {
         stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"});
     }
 
-    @SmallTest
+    @Test
     public void testStringSplitterWithInternalEmptyString() {
         stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"});
     }
 
-    @SmallTest
+    @Test
     public void testStringSplitterWithTrailingEmptyString() {
         // A single trailing emtpy string should be ignored.
         stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"});
@@ -222,7 +232,7 @@
         MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{}));
     }
 
-    @SmallTest
+    @Test
     public void testTrim() {
         String[] strings = { "abc", " abc", "  abc", "abc ", "abc  ",
                              " abc ", "  abc  ", "\nabc\n", "\nabc", "abc\n" };
@@ -232,7 +242,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testRfc822TokenizerFullAddress() {
         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
         assertNotNull(tokens);
@@ -242,7 +252,7 @@
         assertEquals("something",tokens[0].getComment());
     }
 
-    @SmallTest
+    @Test
     public void testRfc822TokenizeItemWithError() {
         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("\"Foo Bar\\");
         assertNotNull(tokens);
@@ -250,7 +260,7 @@
         assertEquals("Foo Bar", tokens[0].getAddress());
     }
 
-    @SmallTest
+    @Test
     public void testRfc822FindToken() {
         Rfc822Tokenizer tokenizer = new Rfc822Tokenizer();
         //                0           1         2           3         4
@@ -262,12 +272,13 @@
         assertEquals(46, tokenizer.findTokenEnd(address, 25));
     }
 
-    @SmallTest
+    @Test
     public void testRfc822FindTokenWithError() {
         assertEquals(9, new Rfc822Tokenizer().findTokenEnd("\"Foo Bar\\", 0));
     }
 
     @LargeTest
+    @Test
     public void testEllipsize() {
         CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
         CharSequence s2 = new Wrapper(s1);
@@ -327,7 +338,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testDelimitedStringContains() {
         assertFalse(TextUtils.delimitedStringContains("", ',', null));
         assertFalse(TextUtils.delimitedStringContains(null, ',', ""));
@@ -347,7 +358,7 @@
         assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceCreator() {
         Parcel p = Parcel.obtain();
         TextUtils.writeToParcel(null, p, 0);
@@ -360,7 +371,7 @@
         assertEquals("conversion to/from parcel failed", "test", text);
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceCreatorNull() {
         Parcel p;
         CharSequence text;
@@ -371,7 +382,7 @@
         assertNull("null CharSequence should generate null from parcel", text);
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceCreatorSpannable() {
         Parcel p;
         CharSequence text;
@@ -382,7 +393,7 @@
         assertEquals("conversion to/from parcel failed", "test", text.toString());
     }
 
-    @SmallTest
+    @Test
     public void testCharSequenceCreatorString() {
         Parcel p;
         CharSequence text;
@@ -404,10 +415,12 @@
             mString = s;
         }
 
+        @Override
         public int length() {
             return mString.length();
         }
 
+        @Override
         public char charAt(int off) {
             return mString.charAt(off);
         }
@@ -417,12 +430,13 @@
             return mString.toString();
         }
 
+        @Override
         public CharSequence subSequence(int start, int end) {
             return new Wrapper(mString.subSequence(start, end));
         }
     }
 
-    @LargeTest
+    @Test
     public void testRemoveEmptySpans() {
         MockSpanned spanned = new MockSpanned();
 
@@ -484,14 +498,17 @@
             }
         }
 
+        @Override
         public char charAt(int arg0) {
             return 0;
         }
 
+        @Override
         public int length() {
             return 0;
         }
 
+        @Override
         public CharSequence subSequence(int arg0, int arg1) {
             return null;
         }
@@ -522,7 +539,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testGetLayoutDirectionFromLocale() {
         assertEquals(View.LAYOUT_DIRECTION_LTR, TextUtils.getLayoutDirectionFromLocale(null));
         assertEquals(View.LAYOUT_DIRECTION_LTR,
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
index b0f55d6..ec2c96c 100644
--- a/core/tests/coretests/src/android/text/VariationParserTest.java
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -16,17 +16,24 @@
 
 package android.text;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
 import android.graphics.fonts.FontVariationAxis;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class VariationParserTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VariationParserTest {
     private static final String[] INVALID_STYLE_VALUES = {
         "", "x", "\t", "\n"
     };
 
-    @SmallTest
+    @Test
     public void testFromFontVariationSetting_InvalidStyleValue() {
         // Test with invalid styleValue
         for (String invalidStyle : INVALID_STYLE_VALUES) {
@@ -39,7 +46,8 @@
         }
         for (String invalidStyle : INVALID_STYLE_VALUES) {
             try {
-                FontVariationAxis.fromFontVariationSettings("'wght' 1, 'wdth' " + invalidStyle);
+                FontVariationAxis.fromFontVariationSettings("'wght' 1, 'wdth' "
+                    + invalidStyle);
                 fail();
             } catch (IllegalArgumentException e) {
                 // pass
@@ -47,10 +55,13 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testOpenTypeTagValue() {
-      assertEquals(0x77647468, (new FontVariationAxis("wdth", 0).getOpenTypeTagValue()));
-      assertEquals(0x41582020, (new FontVariationAxis("AX  ", 0).getOpenTypeTagValue()));
-      assertEquals(0x20202020, (new FontVariationAxis("    ", 0).getOpenTypeTagValue()));
+      assertEquals(0x77647468,
+          new FontVariationAxis("wdth", 0).getOpenTypeTagValue());
+      assertEquals(0x41582020,
+          new FontVariationAxis("AX  ", 0).getOpenTypeTagValue());
+      assertEquals(0x20202020,
+          new FontVariationAxis("    ", 0).getOpenTypeTagValue());
     }
 }
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 93bc911..15c86f0 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -16,14 +16,21 @@
 
 package android.text.format;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DateFormatTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DateFormatTest {
 
-    @SmallTest
-    public void testHasDesignator() throws Exception {
+    @Test
+    public void testHasDesignator() {
         assertTrue(DateFormat.hasDesignator("hh:mm:ss", DateFormat.MINUTE));
         assertTrue(DateFormat.hasDesignator("myyyy", DateFormat.MINUTE));
         assertTrue(DateFormat.hasDesignator("mmm", DateFormat.MINUTE));
@@ -31,8 +38,8 @@
         assertFalse(DateFormat.hasDesignator("hh:MM:ss", DateFormat.MINUTE));
     }
 
-    @SmallTest
-    public void testHasDesignatorEscaped() throws Exception {
+    @Test
+    public void testHasDesignatorEscaped() {
         assertTrue(DateFormat.hasDesignator("hh:mm 'LOL'", DateFormat.MINUTE));
 
         assertFalse(DateFormat.hasDesignator("hh:mm 'yyyy'", DateFormat.YEAR));
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index de43fc6..9271cb4 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -16,45 +16,40 @@
 
 package android.text.format;
 
+import static org.junit.Assert.assertEquals;
+
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.LocaleList;
 import android.support.test.filters.SmallTest;
-
-import junit.framework.TestCase;
+import android.support.test.runner.AndroidJUnit4;
 
 import java.util.Locale;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DateUtilsTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DateUtilsTest {
 
     private static final LocaleList LOCALE_LIST_US = new LocaleList(Locale.US);
     private LocaleList mOriginalLocales;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mOriginalLocales = Resources.getSystem().getConfiguration().getLocales();
         setLocales(LOCALE_LIST_US);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         setLocales(mOriginalLocales);
-        super.tearDown();
     }
 
-    private void setLocales(LocaleList locales) {
-        final Resources systemResources = Resources.getSystem();
-        final Configuration config = new Configuration(systemResources.getConfiguration());
-        config.setLocales(locales);
-        // This is not very safe to call, but since DateUtils.formatDuration() is a static method
-        // (it gets its format strings from the system resources), we can't pass a modified Context
-        // to it.
-        systemResources.updateConfiguration(config, null);
-    }
-
-    @SmallTest
-    public void test_formatDuration_seconds() throws Exception {
+    @Test
+    public void test_formatDuration_seconds() {
         assertEquals("0 seconds", DateUtils.formatDuration(0));
         assertEquals("0 seconds", DateUtils.formatDuration(1));
         assertEquals("0 seconds", DateUtils.formatDuration(499));
@@ -75,8 +70,8 @@
         assertEquals("2s", DateUtils.formatDuration(1500, DateUtils.LENGTH_SHORTEST));
     }
 
-    @SmallTest
-    public void test_formatDuration_Minutes() throws Exception {
+    @Test
+    public void test_formatDuration_Minutes() {
         assertEquals("59 seconds", DateUtils.formatDuration(59000));
         assertEquals("60 seconds", DateUtils.formatDuration(59500));
         assertEquals("1 minute", DateUtils.formatDuration(60000));
@@ -92,8 +87,8 @@
         assertEquals("2m", DateUtils.formatDuration(120000, DateUtils.LENGTH_SHORTEST));
     }
 
-    @SmallTest
-    public void test_formatDuration_Hours() throws Exception {
+    @Test
+    public void test_formatDuration_Hours() {
         assertEquals("59 minutes", DateUtils.formatDuration(3540000));
         assertEquals("1 hour", DateUtils.formatDuration(3600000));
         assertEquals("48 hours", DateUtils.formatDuration(172800000));
@@ -107,4 +102,15 @@
         assertEquals("1h", DateUtils.formatDuration(3600000, DateUtils.LENGTH_SHORTEST));
         assertEquals("48h", DateUtils.formatDuration(172800000, DateUtils.LENGTH_SHORTEST));
     }
+
+    private void setLocales(LocaleList locales) {
+        final Resources systemResources = Resources.getSystem();
+        final Configuration config = new Configuration(systemResources.getConfiguration());
+        config.setLocales(locales);
+        // This is not very safe to call, but since DateUtils.formatDuration() is a static method
+        // (it gets its format strings from the system resources), we can't pass a modified Context
+        // to it.
+        systemResources.updateConfiguration(config, null);
+    }
+
 }
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 2293094..a4ce911 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -16,43 +16,43 @@
 
 package android.text.format;
 
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.Formatter.BytesResult;
 
 import java.util.Locale;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class FormatterTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FormatterTest {
     private Locale mOriginalLocale;
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mOriginalLocale = mContext.getResources().getConfiguration().locale;
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+        mOriginalLocale = mContext.getResources()
+            .getConfiguration().locale;
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() {
         if (mOriginalLocale != null) {
             setLocale(mOriginalLocale);
         }
-        super.tearDown();
     }
 
-    private void setLocale(Locale locale) {
-        Resources res = getContext().getResources();
-        Configuration config = res.getConfiguration();
-        config.locale = locale;
-        res.updateConfiguration(config, res.getDisplayMetrics());
-
-        Locale.setDefault(locale);
-    }
-
-    @SmallTest
+    @Test
     public void testFormatBytes() {
         setLocale(Locale.ENGLISH);
 
@@ -90,7 +90,7 @@
         checkFormatBytes(-914, false, "-0.91", -910);
 
         // Missing FLAG_CALCULATE_ROUNDED case.
-        BytesResult r = Formatter.formatBytes(getContext().getResources(), 1, 0);
+        BytesResult r = Formatter.formatBytes(mContext.getResources(), 1, 0);
         assertEquals("1", r.value);
         assertEquals(0, r.roundedBytes); // Didn't pass FLAG_CALCULATE_ROUNDED
 
@@ -101,9 +101,18 @@
 
     private void checkFormatBytes(long bytes, boolean useShort,
             String expectedString, long expectedRounded) {
-        BytesResult r = Formatter.formatBytes(getContext().getResources(), bytes,
+        BytesResult r = Formatter.formatBytes(mContext.getResources(), bytes,
                 Formatter.FLAG_CALCULATE_ROUNDED | (useShort ? Formatter.FLAG_SHORTER : 0));
         assertEquals(expectedString, r.value);
         assertEquals(expectedRounded, r.roundedBytes);
     }
+
+    private void setLocale(Locale locale) {
+        Resources res = mContext.getResources();
+        Configuration config = res.getConfiguration();
+        config.locale = locale;
+        res.updateConfiguration(config, res.getDisplayMetrics());
+
+        Locale.setDefault(locale);
+    }
 }
diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java
index f6dd0d4..8983d15 100644
--- a/core/tests/coretests/src/android/text/format/TimeTest.java
+++ b/core/tests/coretests/src/android/text/format/TimeTest.java
@@ -16,17 +16,25 @@
 
 package android.text.format;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.support.test.filters.SmallTest;
 import android.support.test.filters.Suppress;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.util.TimeFormatException;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class TimeTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimeTest {
 
-    @SmallTest
-    public void testNormalize0() throws Exception {
+    @Test
+    public void testNormalize0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.parse("20060432T010203");
         t.normalize(false /* use isDst */);
@@ -174,8 +182,8 @@
             new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0),
     };
 
-    @SmallTest
-    public void testNormalize1() throws Exception {
+    @Test
+    public void testNormalize1() {
         Time local = new Time("America/Los_Angeles");
 
         int len = dayTests.length;
@@ -265,70 +273,70 @@
         }
     }
 
-    @SmallTest
-    public void testSwitchTimezone0() throws Exception {
+    @Test
+    public void testSwitchTimezone0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.parse("20061005T120000");
         t.switchTimezone("America/Los_Angeles");
         // System.out.println("got: " + t);
     }
 
-    @SmallTest
-    public void testCtor0() throws Exception {
+    @Test
+    public void testCtor0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         assertEquals(Time.TIMEZONE_UTC, t.timezone);
     }
 
-    @SmallTest
-    public void testGetActualMaximum0() throws Exception {
+    @Test
+    public void testGetActualMaximum0() {
         Time t = new Time(Time.TIMEZONE_UTC);
-        int r = t.getActualMaximum(Time.SECOND);
+        t.getActualMaximum(Time.SECOND);
         // System.out.println("r=" + r);
     }
 
-    @SmallTest
-    public void testClear0() throws Exception {
+    @Test
+    public void testClear0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.clear(Time.TIMEZONE_UTC);
     }
 
-    @SmallTest
-    public void testCompare0() throws Exception {
+    @Test
+    public void testCompare0() {
         Time a = new Time(Time.TIMEZONE_UTC);
         Time b = new Time("America/Los_Angeles");
         int r = Time.compare(a, b);
         // System.out.println("r=" + r);
     }
 
-    @SmallTest
-    public void testFormat0() throws Exception {
+    @Test
+    public void testFormat0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         String r = t.format("%Y%m%dT%H%M%S");
         // System.out.println("r='" + r + "'");
     }
 
-    @SmallTest
-    public void testToString0() throws Exception {
+    @Test
+    public void testToString0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         String r = t.toString();
         // System.out.println("r='" + r + "'");
     }
 
-    @SmallTest
-    public void testGetCurrentTimezone0() throws Exception {
+    @Test
+    public void testGetCurrentTimezone0() {
         String r = Time.getCurrentTimezone();
         // System.out.println("r='" + r + "'");
     }
 
-    @SmallTest
-    public void testSetToNow0() throws Exception {
+    @Test
+    public void testSetToNow0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.setToNow();
         // System.out.println("t=" + t);
     }
 
-    @SmallTest
-    public void testMillis0() throws Exception {
+    @Test
+    public void testMillis0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.set(0, 0, 0, 1, 1, 2006);
         long r = t.toMillis(true /* ignore isDst */);
@@ -338,23 +346,23 @@
         // System.out.println("r=" + r);
     }
 
-    @SmallTest
-    public void testMillis1() throws Exception {
+    @Test
+    public void testMillis1() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.set(1, 0, 0, 1, 0, 1970);
         long r = t.toMillis(true /* ignore isDst */);
         // System.out.println("r=" + r);
     }
 
-    @SmallTest
-    public void testParse0() throws Exception {
+    @Test
+    public void testParse0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.parse("12345678T901234");
         // System.out.println("t=" + t);
     }
 
-    @SmallTest
-    public void testParse33390() throws Exception {
+    @Test
+    public void testParse33390() {
         Time t = new Time(Time.TIMEZONE_UTC);
 
         t.parse3339("1980-05-23");
@@ -435,8 +443,8 @@
         }
     }
 
-    @SmallTest
-    public void testSet0() throws Exception {
+    @Test
+    public void testSet0() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.set(1000L);
         // System.out.println("t.year=" + t.year);
@@ -449,13 +457,13 @@
         // System.out.println("t=" + t);
     }
 
-    @SmallTest
-    public void testSet1() throws Exception {
+    @Test
+    public void testSet1() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.set(1, 2, 3, 4, 5, 6);
         // System.out.println("t=" + t);
     }
-    
+
     // Timezones that cover the world.  Some GMT offsets occur more than
     // once in case some cities decide to change their GMT offset.
     private static final String[] mTimeZones = {
@@ -518,9 +526,9 @@
         "Pacific/Honolulu",
         "Pacific/Midway",
     };
-    
+
     @Suppress
-    public void disableTestGetJulianDay() throws Exception {
+    public void disableTestGetJulianDay() {
         Time time = new Time();
 
         // For each day of the year, and for each timezone, get the Julian
@@ -560,11 +568,11 @@
             }
         }
     }
-    
+
     @Suppress
-    public void disableTestSetJulianDay() throws Exception {
+    public void disableTestSetJulianDay() {
         Time time = new Time();
-        
+
         // For each day of the year in 2008, and for each timezone,
         // test that we can set the Julian day correctly.
         for (int monthDay = 1; monthDay <= 366; monthDay++) {
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index 864b48a..6e41831 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -17,9 +17,13 @@
 package android.text.method;
 
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test backspace key handling of {@link android.text.method.BaseKeyListener}.
@@ -27,6 +31,8 @@
  * Only contains edge cases. For normal cases, see {@see android.text.method.cts.BackspaceTest}.
  * TODO: introduce test cases for surrogate pairs and replacement span.
  */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class BackspaceTest extends KeyListenerTestCase {
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
@@ -49,7 +55,7 @@
         state.mSelectionEnd = mTextView.getSelectionEnd();
     }
 
-    @SmallTest
+    @Test
     public void testCombiningEnclosingKeycaps() {
         EditorState state = new EditorState();
 
@@ -77,7 +83,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testVariationSelector() {
         EditorState state = new EditorState();
 
@@ -141,7 +147,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testEmojiZWJSequence() {
         EditorState state = new EditorState();
 
@@ -221,7 +227,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testFlags() {
         EditorState state = new EditorState();
 
@@ -283,7 +289,7 @@
         state.assertEquals("'a' |");
     }
 
-    @SmallTest
+    @Test
     public void testEmojiModifier() {
         EditorState state = new EditorState();
 
@@ -312,7 +318,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testMixedEdgeCases() {
         EditorState state = new EditorState();
 
diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java
index bbbbd6d..12bb8c8 100644
--- a/core/tests/coretests/src/android/text/method/EditorState.java
+++ b/core/tests/coretests/src/android/text/method/EditorState.java
@@ -16,6 +16,11 @@
 
 package android.text.method;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.text.Editable;
@@ -59,19 +64,6 @@
     public EditorState() {
     }
 
-    /**
-     * A mocked {@link android.text.style.ReplacementSpan} for testing purpose.
-     */
-    private static class MockReplacementSpan extends ReplacementSpan {
-        public int getSize(Paint paint, CharSequence text, int start, int end,
-                Paint.FontMetricsInt fm) {
-            return 0;
-        }
-        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
-                int y, int bottom, Paint paint) {
-        }
-    }
-
     // Returns true if the code point is ASCII and graph.
     private boolean isGraphicAscii(int codePoint) {
         return 0x20 < codePoint && codePoint < 0x7F;
@@ -169,7 +161,14 @@
                 throw new IllegalArgumentException(
                         "ReplacementSpan start position appears after end position.");
             }
-            spannable.setSpan(new MockReplacementSpan(), replacementSpanStart, replacementSpanEnd,
+
+            ReplacementSpan mockReplacementSpan = mock(ReplacementSpan.class);
+            when(mockReplacementSpan.getSize(any(), any(), any(), any(), any()))
+                .thenReturn(0);
+            doNothing().when(mockReplacementSpan)
+                .draw(any(), any(), any(), any(), any(), any(), any(), any(), any());
+
+            spannable.setSpan(mockReplacementSpan, replacementSpanStart, replacementSpanEnd,
                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         }
         mText = Editable.Factory.getInstance().newEditable(spannable);
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 839d380..6914e21 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -17,16 +17,23 @@
 package android.text.method;
 
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test forward delete key handling of  {@link android.text.method.BaseKeyListener}.
  *
  * Only contains edge cases. For normal cases, see {@see android.text.method.cts.ForwardDeleteTest}.
  * TODO: introduce test cases for surrogate pairs and replacement span.
  */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class ForwardDeleteTest extends KeyListenerTestCase {
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
@@ -49,7 +56,7 @@
         state.mSelectionEnd = mTextView.getSelectionEnd();
     }
 
-    @SmallTest
+    @Test
     public void testCombiningEnclosingKeycaps() {
         EditorState state = new EditorState();
 
@@ -69,7 +76,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testVariationSelector() {
         EditorState state = new EditorState();
 
@@ -117,7 +124,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testEmojiZeroWidthJoinerSequence() {
         EditorState state = new EditorState();
 
@@ -160,7 +167,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testFlags() {
         EditorState state = new EditorState();
 
@@ -217,7 +224,7 @@
         state.assertEquals("| 'b'");
     }
 
-    @SmallTest
+    @Test
     public void testEmojiModifier() {
         EditorState state = new EditorState();
 
@@ -246,7 +253,7 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
+    @Test
     public void testMixedEdgeCases() {
         EditorState state = new EditorState();
 
@@ -354,6 +361,8 @@
         // ZERO WIDTH JOINER + regional indicator symbol
         state.setByString("| U+1F469 U+200D U+1F1FA");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Regional indicator symbol + end with ZERO WIDTH JOINER
@@ -364,6 +373,8 @@
         // Regional indicator symbol + ZERO WIDTH JOINER
         state.setByString("| U+1F1FA U+200D U+1F469");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Start with ZERO WIDTH JOINER + emoji modifier
@@ -384,6 +395,8 @@
         // Emoji modifier + ZERO WIDTH JOINER
         state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
         forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
         state.assertEquals("|");
 
         // Regional indicator symbol + emoji modifier
diff --git a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
index f005d7b..99a0091 100644
--- a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
+++ b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
@@ -17,25 +17,19 @@
 package android.text.method;
 
 import android.app.Instrumentation;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
 import android.view.KeyEvent;
 import android.widget.EditText;
 
-import com.android.frameworks.coretests.R;
-
-public abstract class KeyListenerTestCase extends InstrumentationTestCase {
-
+public abstract class KeyListenerTestCase {
     protected Instrumentation mInstrumentation;
     protected EditText mTextView;
 
     public KeyListenerTestCase() {
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mInstrumentation = getInstrumentation();
+    protected void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mTextView = new EditText(mInstrumentation.getContext());
     }
 
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
index 66cf65f..3499a74 100644
--- a/core/tests/coretests/src/android/text/method/WordIteratorTest.java
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -16,16 +16,25 @@
 
 package android.text.method;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
 
 import java.text.BreakIterator;
 import java.util.Locale;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 // TODO(Bug: 24062099): Add more tests for non-ascii text.
-public class WordIteratorTest  extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WordIteratorTest {
 
-    @SmallTest
+    @Test
     public void testSetCharSequence() {
         final String text = "text";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -48,7 +57,7 @@
         wordIterator.setCharSequence(text, text.length(), text.length());
     }
 
-    @SmallTest
+    @Test
     public void testWindowWidth() {
         final String text = "aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -65,7 +74,7 @@
         assertEquals(BreakIterator.DONE, wordIterator.following(expectedWindowEnd));
     }
 
-    @SmallTest
+    @Test
     public void testPreceding() {
         final String text = "abc def-ghi. jkl";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -105,7 +114,7 @@
         assertEquals(text.indexOf('j'), wordIterator.preceding(text.indexOf('l')));
     }
 
-    @SmallTest
+    @Test
     public void testFollowing() {
         final String text = "abc def-ghi. jkl";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -145,7 +154,7 @@
         assertEquals(BreakIterator.DONE, wordIterator.following(text.length()));
     }
 
-    @SmallTest
+    @Test
     public void testIsBoundary() {
         final String text = "abc def-ghi. jkl";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -173,7 +182,7 @@
         assertTrue(wordIterator.isBoundary(text.length()));
     }
 
-    @SmallTest
+    @Test
     public void testNextBoundary() {
         final String text = "abc def-ghi. jkl";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -220,7 +229,7 @@
         assertEquals(BreakIterator.DONE, currentOffset);
     }
 
-    @SmallTest
+    @Test
     public void testPrevBoundary() {
         final String text = "abc def-ghi. jkl";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -266,7 +275,7 @@
         assertEquals(BreakIterator.DONE, currentOffset);
     }
 
-    @SmallTest
+    @Test
     public void testGetBeginning() {
         {
             final String text = "abc def-ghi. jkl";
@@ -340,7 +349,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testGetEnd() {
         {
             final String text = "abc def-ghi. jkl";
@@ -415,7 +424,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testGetPunctuationBeginning() {
         final String text = "abc!? (^^;) def";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -450,7 +459,7 @@
         assertEquals(text.indexOf(';'), wordIterator.getPunctuationBeginning(text.length()));
     }
 
-    @SmallTest
+    @Test
     public void testGetPunctuationEnd() {
         final String text = "abc!? (^^;) def";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -482,7 +491,7 @@
         assertEquals(BreakIterator.DONE, wordIterator.getPunctuationEnd(text.length()));
     }
 
-    @SmallTest
+    @Test
     public void testIsAfterPunctuation() {
         final String text = "abc!? (^^;) def";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -498,7 +507,7 @@
         assertFalse(wordIterator.isAfterPunctuation(text.length() + 1));
     }
 
-    @SmallTest
+    @Test
     public void testIsOnPunctuation() {
         final String text = "abc!? (^^;) def";
         WordIterator wordIterator = new WordIterator(Locale.ENGLISH);
@@ -517,7 +526,7 @@
         assertFalse(wordIterator.isOnPunctuation(text.length() + 1));
     }
 
-    @SmallTest
+    @Test
     public void testApostropheMiddleOfWord() {
         // These tests confirm that the word "isn't" is treated like one word.
         final String text = "isn't he";
diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java
index 487f4e9..23c34085 100644
--- a/core/tests/coretests/src/android/text/util/LinkifyTest.java
+++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java
@@ -16,45 +16,49 @@
 
 package android.text.util;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.LocaleList;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.LinkMovementMethod;
 import android.widget.TextView;
 
 import java.util.Locale;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * LinkifyTest tests {@link Linkify}.
  */
-public class LinkifyTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LinkifyTest {
 
     private static final LocaleList LOCALE_LIST_US = new LocaleList(Locale.US);
     private LocaleList mOriginalLocales;
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
         mOriginalLocales = LocaleList.getDefault();
         LocaleList.setDefault(LOCALE_LIST_US);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         LocaleList.setDefault(mOriginalLocales);
-        super.tearDown();
     }
 
-    private Context createUsEnglishContext() {
-        final Configuration overrideConfig = new Configuration();
-        overrideConfig.setLocales(LOCALE_LIST_US);
-        return getContext().createConfigurationContext(overrideConfig);
-    }
-
-    @SmallTest
-    public void testNothing() throws Exception {
+    @Test
+    public void testNothing() {
         TextView tv;
 
         tv = new TextView(createUsEnglishContext());
@@ -64,8 +68,8 @@
         assertTrue(tv.getUrls().length == 0);
     }
 
-    @SmallTest
-    public void testNormal() throws Exception {
+    @Test
+    public void testNormal() {
         TextView tv;
 
         tv = new TextView(createUsEnglishContext());
@@ -76,8 +80,8 @@
         assertTrue(tv.getUrls().length == 2);
     }
 
-    @SmallTest
-    public void testUnclickable() throws Exception {
+    @Test
+    public void testUnclickable() {
         TextView tv;
 
         tv = new TextView(createUsEnglishContext());
@@ -88,4 +92,10 @@
         assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod);
         assertTrue(tv.getUrls().length == 2);
     }
+
+    private Context createUsEnglishContext() {
+        final Configuration overrideConfig = new Configuration();
+        overrideConfig.setLocales(LOCALE_LIST_US);
+        return mContext.createConfigurationContext(overrideConfig);
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index f59e4fc..742fd60 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -118,7 +118,7 @@
         if (isTextClassifierDisabled()) return;
 
         String text = "Visit http://www.android.com for more information";
-        String classifiedText = "http://www.android.com";
+        String classifiedText = "www.android.com";
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
         assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
@@ -193,7 +193,19 @@
             public boolean matches(Object o) {
                 if (o instanceof TextClassification) {
                     TextClassification result = (TextClassification) o;
-                    return text.equals(result.getText())
+                    final boolean typeRequirementSatisfied;
+                    switch (type) {
+                        case TextClassifier.TYPE_URL:
+                            String scheme = result.getIntent().getData().getScheme();
+                            typeRequirementSatisfied = "http".equalsIgnoreCase(scheme)
+                                    || "https".equalsIgnoreCase(scheme);
+                            break;
+                        default:
+                            typeRequirementSatisfied = true;
+                    }
+
+                    return typeRequirementSatisfied
+                            && text.equals(result.getText())
                             && result.getEntityCount() > 0
                             && type.equals(result.getEntity(0));
                     // TODO: Include other properties.
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 6bc5e91..9bd5994 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -36,6 +36,7 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.R;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.TelephonyProperties;
@@ -364,7 +365,8 @@
 
         // Construct Notification
         if (mNiNotificationBuilder == null) {
-            mNiNotificationBuilder = new Notification.Builder(mContext)
+            mNiNotificationBuilder = new Notification.Builder(mContext,
+                SystemNotificationChannels.NETWORK_ALERTS)
                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
                     .setWhen(0)
                     .setOngoing(true)
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 2ef1cf5..c309133 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -34,6 +34,7 @@
             <intent-filter>
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
+                <action android:name="android.intent.action.LOCALE_CHANGED" />
             </intent-filter>
         </receiver>
         <service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 7fd1601..0213306 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -112,8 +112,6 @@
 
     private static void onShowCaptivePortalNotification(Intent intent, Context context) {
         logd("onShowCaptivePortalNotification");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
         Intent portalIntent = new Intent(context, CaptivePortalLoginActivity.class);
         portalIntent.putExtras(intent);
         portalIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
@@ -123,7 +121,8 @@
         Notification notification = getNotification(context, R.string.portal_notification_id,
                 R.string.portal_notification_detail, pendingIntent);
         try {
-            notificationMgr.notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
+            context.getSystemService(NotificationManager.class)
+                    .notify(PORTAL_NOTIFICATION_TAG, PORTAL_NOTIFICATION_ID, notification);
         } catch (NullPointerException npe) {
             loge("setNotificationVisible: " + npe);
         }
@@ -131,12 +130,11 @@
 
     private static void onShowNoDataServiceNotification(Context context) {
         logd("onShowNoDataServiceNotification");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
         Notification notification = getNotification(context, R.string.no_data_notification_id,
                 R.string.no_data_notification_detail, null);
         try {
-            notificationMgr.notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
+            context.getSystemService(NotificationManager.class)
+                    .notify(NO_DATA_NOTIFICATION_TAG, NO_DATA_NOTIFICATION_ID, notification);
         } catch (NullPointerException npe) {
             loge("setNotificationVisible: " + npe);
         }
@@ -144,26 +142,16 @@
 
     private static void onCancelAllNotifications(Context context) {
         logd("onCancelAllNotifications");
-        final NotificationManager notificationMgr = context.getSystemService(
-                NotificationManager.class);
-        notificationMgr.cancelAll();
+        context.getSystemService(NotificationManager.class).cancelAll();
     }
 
     private static Notification getNotification(Context context, int titleId, int textId,
                                          PendingIntent pendingIntent) {
         final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
-        final NotificationManager notificationManager = context.getSystemService(
-                NotificationManager.class);
         final Resources resources = context.getResources();
         final Bundle extras = Bundle.forPair(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                 resources.getString(R.string.android_system_label));
-        /* Creates the notification channel and registers it with NotificationManager. If a channel
-         * with the same ID is already registered, NotificationManager will ignore this call.
-         */
-        notificationManager.createNotificationChannel(new NotificationChannel(
-                NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
-                resources.getString(R.string.mobile_data_status_notification_channel_name),
-                NotificationManager.IMPORTANCE_DEFAULT));
+        createNotificationChannels(context);
         Notification.Builder builder = new Notification.Builder(context)
                 .setContentTitle(resources.getString(titleId))
                 .setContentText(String.format(resources.getString(textId),
@@ -187,6 +175,19 @@
         return builder.build();
     }
 
+    /**
+     * Creates the notification channel and registers it with NotificationManager. Also used to
+     * update an existing channel's name.
+     */
+    static void createNotificationChannels(Context context) {
+        context.getSystemService(NotificationManager.class)
+                .createNotificationChannel(new NotificationChannel(
+                NOTIFICATION_CHANNEL_ID_MOBILE_DATA_STATUS,
+                context.getResources().getString(
+                        R.string.mobile_data_status_notification_channel_name),
+                NotificationManager.IMPORTANCE_DEFAULT));
+    }
+
     private static void logd(String s) {
         Log.d(TAG, s);
     }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
index 3fd89d9..3f55ff5 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierDefaultBroadcastReceiver.java
@@ -32,6 +32,10 @@
             Log.d(TAG, "skip carrier actions during provisioning");
             return;
         }
+        if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+            CarrierActionUtils.createNotificationChannels(context);
+            return;
+        }
         List<Integer> actionList = CustomConfigLoader.loadCarrierActionList(context, intent);
         for (int actionIdx : actionList) {
             Log.d(TAG, "apply carrier action idx: " + actionIdx);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 24d8187..5a178a5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -998,9 +998,10 @@
             if (mRssi != info.getRssi()) {
                 mRssi = info.getRssi();
                 updated = true;
+            } else if (mNetworkInfo.getDetailedState() != networkInfo.getDetailedState()) {
+                updated = true;
             }
             mInfo = info;
-            // TODO(b/37289220): compare NetworkInfo states and set updated = true if necessary
             mNetworkInfo = networkInfo;
         } else if (mInfo != null) {
             updated = true;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 154fde2..56cb0a3 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -404,4 +404,55 @@
         assertThat(ap.getPasspointFqdn()).isEqualTo(fqdn);
         assertThat(ap.getConfigName()).isEqualTo(providerFriendlyName);
     }
+
+    @Test
+    public void testUpdateNetworkInfo_returnsTrue() {
+        int networkId = 123;
+        int rssi = -55;
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = networkId;
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setNetworkId(networkId);
+        wifiInfo.setRssi(rssi);
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
+
+        AccessPoint ap = new TestAccessPointBuilder(mContext)
+                .setNetworkInfo(networkInfo)
+                .setNetworkId(networkId)
+                .setRssi(rssi)
+                .setWifiInfo(wifiInfo)
+                .build();
+
+        NetworkInfo newInfo = new NetworkInfo(networkInfo);
+        newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
+        assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
+    }
+
+    @Test
+    public void testUpdateNetworkInfoWithSameInfo_returnsFalse() {
+        int networkId = 123;
+        int rssi = -55;
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = networkId;
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setNetworkId(networkId);
+        wifiInfo.setRssi(rssi);
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
+
+        AccessPoint ap = new TestAccessPointBuilder(mContext)
+                .setNetworkInfo(networkInfo)
+                .setNetworkId(networkId)
+                .setRssi(rssi)
+                .setWifiInfo(wifiInfo)
+                .build();
+
+        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+        assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
index a347203..2213ae6 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
 import android.os.Bundle;
 
 /**
@@ -36,11 +37,13 @@
 
     // set some sensible defaults
     private int mRssi = AccessPoint.UNREACHABLE_RSSI;
-    private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
+    private int mNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
     private String ssid = "TestSsid";
     private NetworkInfo mNetworkInfo = null;
     private String mFqdn = null;
     private String mProviderFriendlyName = null;
+    private WifiConfiguration mWifiConfig;
+    private WifiInfo mWifiInfo;
 
     Context mContext;
 
@@ -51,12 +54,13 @@
     public AccessPoint build() {
         Bundle bundle = new Bundle();
 
-        WifiConfiguration wifiConig = new WifiConfiguration();
-        wifiConig.networkId = networkId;
+        WifiConfiguration wifiConfig = new WifiConfiguration();
+        wifiConfig.networkId = mNetworkId;
 
         bundle.putString(AccessPoint.KEY_SSID, ssid);
-        bundle.putParcelable(AccessPoint.KEY_CONFIG, wifiConig);
+        bundle.putParcelable(AccessPoint.KEY_CONFIG, wifiConfig);
         bundle.putParcelable(AccessPoint.KEY_NETWORKINFO, mNetworkInfo);
+        bundle.putParcelable(AccessPoint.KEY_WIFIINFO, mWifiInfo);
         if (mFqdn != null) {
             bundle.putString(AccessPoint.KEY_FQDN, mFqdn);
         }
@@ -81,17 +85,12 @@
         return this;
     }
 
-    public TestAccessPointBuilder setRssi(int rssi) {
-        mRssi = rssi;
-        return this;
-    }
-
     /**
-    * Set the rssi based upon the desired signal level.
+     * Set the rssi based upon the desired signal level.
      *
-    * <p>Side effect: if this AccessPoint was previously unreachable,
-    * setting the level will also make it reachable.
-    */
+     * <p>Side effect: if this AccessPoint was previously unreachable,
+     * setting the level will also make it reachable.
+     */
     public TestAccessPointBuilder setLevel(int level) {
         // Reversal of WifiManager.calculateSignalLevels
         if (level == 0) {
@@ -106,6 +105,16 @@
         return this;
     }
 
+    public TestAccessPointBuilder setNetworkInfo(NetworkInfo info) {
+        mNetworkInfo = info;
+        return this;
+    }
+
+    public TestAccessPointBuilder setRssi(int rssi) {
+        mRssi = rssi;
+        return this;
+    }
+
     /**
     * Set whether the AccessPoint is reachable.
     * Side effect: if the signal level was not previously set,
@@ -125,9 +134,9 @@
 
     public TestAccessPointBuilder setSaved(boolean saved){
         if (saved) {
-             networkId = 1;
+             mNetworkId = 1;
         } else {
-             networkId = WifiConfiguration.INVALID_NETWORK_ID;
+             mNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
         }
         return this;
     }
@@ -146,4 +155,20 @@
         mProviderFriendlyName = friendlyName;
         return this;
     }
+
+    public TestAccessPointBuilder setWifiInfo(WifiInfo info) {
+        mWifiInfo = info;
+        return this;
+    }
+
+    /**
+     * Set the networkId in the WifiConfig.
+     *
+     * <p>Setting this to a value other than {@link WifiConfiguration#INVALID_NETWORK_ID} makes this
+     * AccessPoint a saved network.
+     */
+    public TestAccessPointBuilder setNetworkId(int networkId) {
+        mNetworkId = networkId;
+        return this;
+    }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
deleted file mode 100644
index 0688481..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/doze/DozeProvider.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.plugins.doze;
-
-import android.app.PendingIntent;
-import android.content.Context;
-
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-/**
- * Provides a {@link DozeUi}.
- */
-@ProvidesInterface(action = DozeProvider.ACTION, version = DozeProvider.VERSION)
-public interface DozeProvider extends Plugin {
-
-    String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
-    int VERSION = 1;
-
-    /**
-     * Caution: Even if this is called, the DozeUi provided may still be in use until it transitions
-     * to DozeState.FINISH
-     */
-    @Override
-    default void onDestroy() {
-    }
-
-    /**
-     * @return the plugin's implementation of DozeUi.
-     */
-    DozeUi provideDozeUi(Context context, DozeMachine machine, WakeLock wakeLock);
-
-    /**
-     * If true, the plugin allows the default pulse triggers to fire, otherwise they are disabled.
-     */
-    default boolean allowDefaultPulseTriggers() {
-        return false;
-    }
-
-    /**
-     * Ui for use in DozeMachine.
-     */
-    interface DozeUi {
-        /** Called whenever the DozeMachine state transitions */
-        void transitionTo(DozeState oldState, DozeState newState);
-    }
-
-    /** WakeLock wrapper for testability */
-    interface WakeLock {
-        /** @see android.os.PowerManager.WakeLock#acquire() */
-        void acquire();
-        /** @see android.os.PowerManager.WakeLock#release() */
-        void release();
-        /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
-        Runnable wrap(Runnable r);
-    }
-
-    /** Plugin version of the DozeMachine's state */
-    enum DozeState {
-        /** Default state. Transition to INITIALIZED to get Doze going. */
-        UNINITIALIZED,
-        /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
-        INITIALIZED,
-        /** Regular doze. Device is asleep and listening for pulse triggers. */
-        DOZE,
-        /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
-        DOZE_AOD,
-        /** Pulse has been requested. Device is awake and preparing UI */
-        DOZE_REQUEST_PULSE,
-        /** Pulse is showing. Device is awake and showing UI. */
-        DOZE_PULSING,
-        /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
-        DOZE_PULSE_DONE,
-        /** Doze is done. DozeService is finished. */
-        FINISH,
-        /** WakeUp. */
-        WAKE_UP,
-    }
-
-    /** Plugin interface for the doze machine. */
-    interface DozeMachine {
-        /** Request that the DozeMachine transitions to {@code state} */
-        void requestState(DozeState state);
-
-        /** Request that the PendingIntent is sent. */
-        void requestSendIntent(PendingIntent intent);
-    }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 7d78c08..9ef05c5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -16,6 +16,7 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.service.quicksettings.Tile;
 
 import com.android.systemui.plugins.annotations.DependsOn;
@@ -66,6 +67,10 @@
 
     State getState();
 
+    default LogMaker populate(LogMaker logMaker) {
+        return logMaker;
+    }
+
     @ProvidesInterface(version = Callback.VERSION)
     public interface Callback {
         public static final int VERSION = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
index 086e5e5..49e780c 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
+import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -159,11 +160,13 @@
     static private class PackageItemAdapter extends ArrayAdapter<ApplicationInfo> {
         final PackageManager mPm;
         final LayoutInflater mInflater;
+        final IconDrawableFactory mIconDrawableFactory;
 
         public PackageItemAdapter(Context context) {
             super(context, R.layout.foreground_service_item);
             mPm = context.getPackageManager();
             mInflater = LayoutInflater.from(context);
+            mIconDrawableFactory = IconDrawableFactory.newInstance(context, true);
         }
 
         public void setPackages(String[] packages) {
@@ -193,7 +196,7 @@
             }
 
             ImageView icon = view.findViewById(R.id.app_icon);
-            icon.setImageDrawable(getItem(position).loadIcon(mPm));
+            icon.setImageDrawable(mIconDrawableFactory.getBadgedIcon(getItem(position)));
 
             TextView label = view.findViewById(R.id.app_name);
             label.setText(getItem(position).loadLabel(mPm));
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index ba8e54a..eea09df 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -18,23 +18,18 @@
 
 import android.app.AlarmManager;
 import android.app.Application;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.os.Handler;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.systemui.SystemUIApplication;
-import com.android.systemui.plugins.doze.DozeProvider;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 
 public class DozeFactory {
 
-    private final DozeProvider mDozePlugin;
-
-    public DozeFactory(DozeProvider plugin) {
-        mDozePlugin = plugin;
+    public DozeFactory() {
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -65,89 +60,14 @@
     private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
             DozeHost host, AmbientDisplayConfiguration config, DozeParameters params,
             Handler handler, WakeLock wakeLock, DozeMachine machine) {
-        boolean allowPulseTriggers = mDozePlugin == null || mDozePlugin.allowDefaultPulseTriggers();
+        boolean allowPulseTriggers = true;
         return new DozeTriggers(context, machine, host, config, params,
                 sensorManager, handler, wakeLock, allowPulseTriggers);
     }
 
     private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
             DozeMachine machine, Handler handler, AlarmManager alarmManager) {
-        if (mDozePlugin != null) {
-            DozeProvider.DozeUi dozeUi = mDozePlugin.provideDozeUi(context,
-                    pluginMachine(context, machine, host),
-                    wakeLock);
-            return (oldState, newState) -> {
-                dozeUi.transitionTo(pluginState(oldState),
-                        pluginState(newState));
-            };
-        } else {
-            return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
-        }
-    }
-
-    private DozeProvider.DozeMachine pluginMachine(Context context, DozeMachine machine,
-            DozeHost host) {
-        return new DozeProvider.DozeMachine() {
-            @Override
-            public void requestState(DozeProvider.DozeState state) {
-                if (state == DozeProvider.DozeState.WAKE_UP) {
-                    machine.wakeUp();
-                    return;
-                }
-                machine.requestState(implState(state));
-            }
-
-            @Override
-            public void requestSendIntent(PendingIntent intent) {
-                host.startPendingIntentDismissingKeyguard(intent);
-            }
-        };
-    }
-
-    private DozeMachine.State implState(DozeProvider.DozeState s) {
-        switch (s) {
-            case UNINITIALIZED:
-                return DozeMachine.State.UNINITIALIZED;
-            case INITIALIZED:
-                return DozeMachine.State.INITIALIZED;
-            case DOZE:
-                return DozeMachine.State.DOZE;
-            case DOZE_AOD:
-                return DozeMachine.State.DOZE_AOD;
-            case DOZE_REQUEST_PULSE:
-                return DozeMachine.State.DOZE_REQUEST_PULSE;
-            case DOZE_PULSING:
-                return DozeMachine.State.DOZE_PULSING;
-            case DOZE_PULSE_DONE:
-                return DozeMachine.State.DOZE_PULSE_DONE;
-            case FINISH:
-                return DozeMachine.State.FINISH;
-            default:
-                throw new IllegalArgumentException("Unknown state: " + s);
-        }
-    }
-
-    private DozeProvider.DozeState pluginState(DozeMachine.State s) {
-        switch (s) {
-            case UNINITIALIZED:
-                return DozeProvider.DozeState.UNINITIALIZED;
-            case INITIALIZED:
-                return DozeProvider.DozeState.INITIALIZED;
-            case DOZE:
-                return DozeProvider.DozeState.DOZE;
-            case DOZE_AOD:
-                return DozeProvider.DozeState.DOZE_AOD;
-            case DOZE_REQUEST_PULSE:
-                return DozeProvider.DozeState.DOZE_REQUEST_PULSE;
-            case DOZE_PULSING:
-                return DozeProvider.DozeState.DOZE_PULSING;
-            case DOZE_PULSE_DONE:
-                return DozeProvider.DozeState.DOZE_PULSE_DONE;
-            case FINISH:
-                return DozeProvider.DozeState.FINISH;
-            default:
-                throw new IllegalArgumentException("Unknown state: " + s);
-        }
+        return new DozeUi(context, alarmManager, machine, wakeLock, host, handler);
     }
 
     public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 7139d59..af02e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -37,6 +37,7 @@
 
     private static final int PULSE_REASONS = 5;
 
+    public static final int PULSE_REASON_NONE = -1;
     public static final int PULSE_REASON_INTENT = 0;
     public static final int PULSE_REASON_NOTIFICATION = 1;
     public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 38b32e9..44bb33a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -106,6 +106,7 @@
 
     private final ArrayList<State> mQueuedRequests = new ArrayList<>();
     private State mState = State.UNINITIALIZED;
+    private int mPulseReason;
     private boolean mWakeLockHeldForCurrentState = false;
 
     public DozeMachine(Service service, AmbientDisplayConfiguration config,
@@ -133,6 +134,20 @@
      */
     @MainThread
     public void requestState(State requestedState) {
+        Preconditions.checkArgument(requestedState != State.DOZE_REQUEST_PULSE);
+        requestState(requestedState, DozeLog.PULSE_REASON_NONE);
+    }
+
+    @MainThread
+    public void requestPulse(int pulseReason) {
+        // Must not be called during a transition. There's no inherent problem with that,
+        // but there's currently no need to execute from a transition and it simplifies the
+        // code to not have to worry about keeping the pulseReason in mQueuedRequests.
+        Preconditions.checkState(!isExecutingTransition());
+        requestState(State.DOZE_REQUEST_PULSE, pulseReason);
+    }
+
+    private void requestState(State requestedState, int pulseReason) {
         Assert.isMainThread();
         if (DEBUG) {
             Log.i(TAG, "request: current=" + mState + " req=" + requestedState,
@@ -146,7 +161,7 @@
             for (int i = 0; i < mQueuedRequests.size(); i++) {
                 // Transitions in Parts can call back into requestState, which will
                 // cause mQueuedRequests to grow.
-                transitionTo(mQueuedRequests.get(i));
+                transitionTo(mQueuedRequests.get(i), pulseReason);
             }
             mQueuedRequests.clear();
             mWakeLock.release();
@@ -165,6 +180,20 @@
         return mState;
     }
 
+    /**
+     * @return the current pulse reason.
+     *
+     * This is only valid if the machine is currently in one of the pulse states.
+     */
+    @MainThread
+    public int getPulseReason() {
+        Assert.isMainThread();
+        Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE
+                || mState == State.DOZE_PULSING
+                || mState == State.DOZE_PULSE_DONE, "must be in pulsing state, but is " + mState);
+        return mPulseReason;
+    }
+
     /** Requests the PowerManager to wake up now. */
     public void wakeUp() {
         mDozeService.requestWakeUp();
@@ -174,7 +203,7 @@
         return !mQueuedRequests.isEmpty();
     }
 
-    private void transitionTo(State requestedState) {
+    private void transitionTo(State requestedState, int pulseReason) {
         State newState = transitionPolicy(requestedState);
 
         if (DEBUG) {
@@ -190,6 +219,7 @@
         State oldState = mState;
         mState = newState;
 
+        updatePulseReason(newState, oldState, pulseReason);
         performTransitionOnComponents(oldState, newState);
         updateScreenState(newState);
         updateWakeLockState(newState);
@@ -197,6 +227,14 @@
         resolveIntermediateState(newState);
     }
 
+    private void updatePulseReason(State newState, State oldState, int pulseReason) {
+        if (newState == State.DOZE_REQUEST_PULSE) {
+            mPulseReason = pulseReason;
+        } else if (oldState == State.DOZE_PULSE_DONE) {
+            mPulseReason = DozeLog.PULSE_REASON_NONE;
+        }
+    }
+
     private void performTransitionOnComponents(State oldState, State newState) {
         for (Part p : mParts) {
             p.transitionTo(oldState, newState);
@@ -280,7 +318,8 @@
             case INITIALIZED:
             case DOZE_PULSE_DONE:
                 transitionTo(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
-                        ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE);
+                        ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE,
+                        DozeLog.PULSE_REASON_NONE);
                 break;
             default:
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index e55a597..5241266 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -24,7 +24,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.doze.DozeProvider;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -50,9 +49,7 @@
             return;
         }
 
-        DozeProvider provider = Dependency.get(PluginManager.class)
-                .getOneShotPlugin(DozeProvider.class);
-        mDozeMachine = new DozeFactory(provider).assembleMachine(this);
+        mDozeMachine = new DozeFactory().assembleMachine(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 2096956..563b8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -227,7 +227,7 @@
                     mDozeHost.isPulsingBlocked());
             return;
         }
-        mMachine.requestState(DozeMachine.State.DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(reason);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 03076cc..64a152e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -83,7 +83,7 @@
                 unscheduleTimeTick();
                 break;
             case DOZE_REQUEST_PULSE:
-                pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */);
+                pulseWhileDozing(mMachine.getPulseReason());
                 break;
             case DOZE_PULSE_DONE:
                 mHost.abortPulsing();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index f5e096eb..c4d88ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.Message;
 import android.service.quicksettings.Tile;
@@ -30,6 +31,7 @@
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.Utils;
@@ -179,7 +181,7 @@
 
     public void openDetails(String subPanel) {
         QSTile tile = getTile(subPanel);
-        showDetailAdapter(true, tile.getDetailAdapter(), new int[] {getWidth() / 2, 0});
+        showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
     }
 
     private QSTile getTile(String subPanel) {
@@ -485,8 +487,9 @@
 
     private void logTiles() {
         for (int i = 0; i < mRecords.size(); i++) {
-            TileRecord tileRecord = mRecords.get(i);
-            mMetricsLogger.visible(tileRecord.tile.getMetricsCategory());
+            QSTile tile = mRecords.get(i).tile;
+            mMetricsLogger.write(tile.populate(new LogMaker(tile.getMetricsCategory())
+                    .setType(MetricsEvent.TYPE_OPEN)));
         }
     }
 
@@ -544,12 +547,13 @@
         private static final int SHOW_DETAIL = 1;
         private static final int SET_TILE_VISIBILITY = 2;
         private static final int ANNOUNCE_FOR_ACCESSIBILITY = 3;
+
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == SHOW_DETAIL) {
-                handleShowDetail((Record)msg.obj, msg.arg1 != 0);
+                handleShowDetail((Record) msg.obj, msg.arg1 != 0);
             } else if (msg.what == ANNOUNCE_FOR_ACCESSIBILITY) {
-                announceForAccessibility((CharSequence)msg.obj);
+                announceForAccessibility((CharSequence) msg.obj);
             }
         }
     }
@@ -569,8 +573,11 @@
 
     public interface QSTileLayout {
         void addTile(TileRecord tile);
+
         void removeTile(TileRecord tile);
+
         int getOffsetTop(TileRecord tile);
+
         boolean updateResources();
 
         void setListening(boolean listening);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index dc9176f..017365f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -157,7 +157,7 @@
     }
 
     @Override
-    protected LogMaker populate(LogMaker logMaker) {
+    public LogMaker populate(LogMaker logMaker) {
         return super.populate(logMaker).setComponentName(mComponent);
     }
 
@@ -275,7 +275,6 @@
         } catch (RemoteException e) {
             // Called through wrapper, won't happen here.
         }
-        MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 976efb2..32af230 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -175,7 +175,7 @@
         mHandler.sendEmptyMessage(H.LONG_CLICK);
     }
 
-    protected LogMaker populate(LogMaker logMaker) {
+    public LogMaker populate(LogMaker logMaker) {
         if (mState instanceof BooleanState) {
             logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index eea3de3..215604b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -20,10 +20,17 @@
 import android.os.PowerManager;
 import android.support.annotation.VisibleForTesting;
 
-import com.android.systemui.plugins.doze.DozeProvider;
-
 /** WakeLock wrapper for testability */
-public interface WakeLock extends DozeProvider.WakeLock {
+public interface WakeLock {
+
+    /** @see android.os.PowerManager.WakeLock#acquire() */
+    void acquire();
+
+    /** @see android.os.PowerManager.WakeLock#release() */
+    void release();
+
+    /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
+    Runnable wrap(Runnable r);
 
     static WakeLock createPartial(Context context, String tag) {
         return wrap(createPartialInner(context, tag));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index cdbde5e..d203602 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -106,7 +106,7 @@
     public void testPulseDone_goesToDoze() {
         when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
         mMachine.requestState(INITIALIZED);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
 
         mMachine.requestState(DOZE_PULSE_DONE);
@@ -119,7 +119,7 @@
     public void testPulseDone_goesToAoD() {
         when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
         mMachine.requestState(INITIALIZED);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
 
         mMachine.requestState(DOZE_PULSE_DONE);
@@ -163,7 +163,7 @@
     public void testWakeLock_heldInPulseStates() {
         mMachine.requestState(INITIALIZED);
 
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         assertTrue(mWakeLockFake.isHeld());
 
         mMachine.requestState(DOZE_PULSING);
@@ -186,7 +186,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
         mMachine.requestState(DOZE_PULSE_DONE);
 
@@ -198,9 +198,9 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSE_DONE);
     }
 
@@ -209,7 +209,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSE_DONE);
     }
 
@@ -235,7 +235,7 @@
     public void testScreen_onInPulse() {
         mMachine.requestState(INITIALIZED);
 
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
 
         assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
@@ -246,7 +246,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
 
         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
     }
@@ -256,7 +256,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE_AOD);
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
 
         assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
     }
@@ -270,12 +270,43 @@
             return null;
         }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE));
 
-        mMachine.requestState(DOZE_REQUEST_PULSE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
 
         assertEquals(DOZE_PULSING, mMachine.getState());
     }
 
     @Test
+    public void testPulseReason_getMatchesRequest() {
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(DOZE);
+        mMachine.requestPulse(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP);
+
+        assertEquals(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason());
+    }
+
+    @Test
+    public void testPulseReason_getFromTransition() {
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestState(DOZE);
+        doAnswer(inv -> {
+            DozeMachine.State newState = inv.getArgument(1);
+            if (newState == DOZE_REQUEST_PULSE
+                    || newState == DOZE_PULSING
+                    || newState == DOZE_PULSE_DONE) {
+                assertEquals(DozeLog.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason());
+            } else {
+                assertTrue("unexpected state " + newState,
+                        newState == DOZE || newState == DOZE_AOD);
+            }
+            return null;
+        }).when(mPartMock).transitionTo(any(), any());
+
+        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestState(DOZE_PULSING);
+        mMachine.requestState(DOZE_PULSE_DONE);
+    }
+
+    @Test
     public void testWakeUp_wakesUp() {
         mMachine.wakeUp();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 12e75a1..d57f813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -22,7 +22,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.withSettings;
 
 import android.app.Instrumentation;
 import android.content.Context;
@@ -39,8 +38,6 @@
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.mockito.Answers;
-import org.mockito.MockSettings;
 
 public class DozeTriggersTest {
     private Context mContext;
@@ -104,7 +101,7 @@
             mSensors.PROXIMITY.sendProximityResult(true); /* Far */
         });
 
-        verify(mMachine).requestState(DozeMachine.State.DOZE_REQUEST_PULSE);
+        verify(mMachine).requestPulse(anyInt());
     }
 
 }
\ No newline at end of file
diff --git a/preloaded-classes b/preloaded-classes
index 892c593..493e980 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1820,6 +1820,7 @@
 android.text.GetChars
 android.text.GraphicsOperations
 android.text.Html
+android.text.Html$HtmlParser
 android.text.Hyphenator
 android.text.InputFilter
 android.text.InputType
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 018fb68..9d03fde 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -221,7 +221,7 @@
 
                 final int numContexts = mContexts.size();
                 for (int i = 0; i < numContexts; i++) {
-                    fillStructureWithAllowedValues(mContexts.get(i).getStructure());
+                    fillStructureWithAllowedValues(mContexts.get(i).getStructure(), flags);
                 }
 
                 request = new FillRequest(requestId, mContexts, mClientState, flags);
@@ -235,10 +235,12 @@
      * Updates values of the nodes in the structure so that:
      * - proper node is focused
      * - autofillValue is sent back to service when it was previously autofilled
+     * - autofillValue is sent in the view used to force a request
      *
      * @param structure The structure to be filled
+     * @param flags The flags that started the session
      */
-    private void fillStructureWithAllowedValues(@NonNull AssistStructure structure) {
+    private void fillStructureWithAllowedValues(@NonNull AssistStructure structure, int flags) {
         final int numViewStates = mViewStates.size();
         for (int i = 0; i < numViewStates; i++) {
             final ViewState viewState = mViewStates.valueAt(i);
@@ -257,8 +259,10 @@
             }
             if (mCurrentViewId != null) {
                 overlay.focused = mCurrentViewId.equals(viewState.id);
+                if (overlay.focused && (flags & FLAG_MANUAL_REQUEST) != 0) {
+                    overlay.value = node.getAutofillValue();
+                }
             }
-
             node.setAutofillOverlay(overlay);
         }
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1b970e5..a68a7dd 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2387,7 +2387,7 @@
 
         long token = mAncestralToken;
         synchronized (mQueueLock) {
-            if (mEverStoredApps.contains(packageName)) {
+            if (mCurrentToken != 0 && mEverStoredApps.contains(packageName)) {
                 if (MORE_DEBUG) {
                     Slog.i(TAG, "App in ever-stored, so using current token");
                 }
@@ -3868,9 +3868,14 @@
                         writeApkToBackup(mPackage, output);
                     }
 
+                    final boolean isSharedStorage =
+                            mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+                    final long timeout = isSharedStorage ?
+                            TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_FULL_BACKUP_INTERVAL;
+
                     if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
-                    prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL,
-                            mTimeoutMonitor /* in parent class */, OP_TYPE_BACKUP_WAIT);
+                    prepareOperationTimeout(mToken, timeout, mTimeoutMonitor /* in parent class */,
+                            OP_TYPE_BACKUP_WAIT);
                     mAgent.doFullBackup(mPipe, mQuota, mToken, mBackupManagerBinder);
                 } catch (IOException e) {
                     Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
@@ -7578,9 +7583,12 @@
                         if (okay) {
                             boolean agentSuccess = true;
                             long toCopy = info.size;
+                            final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
+                            final long timeout = isSharedStorage ?
+                                    TIMEOUT_SHARED_BACKUP_INTERVAL : TIMEOUT_RESTORE_INTERVAL;
                             final int token = generateToken();
                             try {
-                                prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, null,
+                                prepareOperationTimeout(token, timeout, null,
                                         OP_TYPE_RESTORE_WAIT);
                                 if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
                                     if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
@@ -10456,8 +10464,7 @@
         final long oldId = Binder.clearCallingIdentity();
         try {
             String prevTransport = mTransportManager.selectTransport(transport);
-            Settings.Secure.putString(mContext.getContentResolver(),
-                    Settings.Secure.BACKUP_TRANSPORT, transport);
+            updateStateForTransport(transport);
             Slog.v(TAG, "selectBackupTransport() set " + mTransportManager.getCurrentTransportName()
                     + " returning " + prevTransport);
             return prevTransport;
@@ -10480,9 +10487,7 @@
             @Override
             public void onSuccess(String transportName) {
                 mTransportManager.selectTransport(transportName);
-                Settings.Secure.putString(mContext.getContentResolver(),
-                        Settings.Secure.BACKUP_TRANSPORT,
-                        mTransportManager.getCurrentTransportName());
+                updateStateForTransport(mTransportManager.getCurrentTransportName());
                 Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString());
                 try {
                     listener.onSuccess(transportName);
@@ -10505,6 +10510,28 @@
         Binder.restoreCallingIdentity(oldId);
     }
 
+    private void updateStateForTransport(String newTransportName) {
+        // Publish the name change
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.BACKUP_TRANSPORT, newTransportName);
+
+        // And update our current-dataset bookkeeping
+        IBackupTransport transport = mTransportManager.getTransportBinder(newTransportName);
+        if (transport != null) {
+            try {
+                mCurrentToken = transport.getCurrentRestoreSet();
+            } catch (Exception e) {
+                // Oops.  We can't know the current dataset token, so reset and figure it out
+                // when we do the next k/v backup operation on this transport.
+                mCurrentToken = 0;
+            }
+        } else {
+            // The named transport isn't bound at this particular moment, so we can't
+            // know yet what its current dataset token is.  Reset as above.
+            mCurrentToken = 0;
+        }
+    }
+
     // Supply the configuration Intent for the given transport.  If the name is not one
     // of the available transports, or if the transport does not supply any configuration
     // UI, the method returns null.
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 67f105e..da1f32c 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -182,13 +182,13 @@
 
     String[] getBoundTransportNames() {
         synchronized (mTransportLock) {
-            return mBoundTransports.keySet().toArray(new String[0]);
+            return mBoundTransports.keySet().toArray(new String[mBoundTransports.size()]);
         }
     }
 
     ComponentName[] getAllTransportCompenents() {
         synchronized (mTransportLock) {
-            return mValidTransports.keySet().toArray(new ComponentName[0]);
+            return mValidTransports.keySet().toArray(new ComponentName[mValidTransports.size()]);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 44caaf9..18c8b32 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2278,7 +2278,7 @@
     }
 
     /** Returns true if the configuration is compatible with this activity. */
-    private boolean isConfigurationCompatible(Configuration config) {
+    boolean isConfigurationCompatible(Configuration config) {
         final int orientation = mWindowContainerController != null
                 ? mWindowContainerController.getOrientation() : info.screenOrientation;
         if (isFixedOrientationPortrait(orientation)
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 39fef44..912b22c 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -655,11 +655,11 @@
         }
     }
 
-    final ActivityRecord topRunningActivityLocked() {
+    ActivityRecord topRunningActivityLocked() {
         return topRunningActivityLocked(false /* focusableOnly */);
     }
 
-    final ActivityRecord topRunningActivityLocked(boolean focusableOnly) {
+    private ActivityRecord topRunningActivityLocked(boolean focusableOnly) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             ActivityRecord r = mTaskHistory.get(taskNdx).topRunningActivityLocked();
             if (r != null && (!focusableOnly || r.isFocusable())) {
@@ -669,7 +669,21 @@
         return null;
     }
 
-    final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
+    ActivityRecord topRunningNonOverlayTaskActivity() {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (!r.finishing && !r.mTaskOverlay) {
+                    return r;
+                }
+            }
+        }
+        return null;
+    }
+
+    ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             final ArrayList<ActivityRecord> activities = task.mActivities;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 19b9b45..2273452 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -953,7 +953,7 @@
             // If we are not able to proceed, disassociate the activity from the task. Leaving an
             // activity in an incomplete state can lead to issues, such as performing operations
             // without a window container.
-            if (result != START_SUCCESS && mStartActivity.getTask() != null) {
+            if (result < START_SUCCESS && mStartActivity.getTask() != null) {
                 mStartActivity.getTask().removeActivity(mStartActivity);
             }
             mService.mWindowManager.continueSurfaceLayout();
@@ -1059,7 +1059,7 @@
                 // We didn't do anything...  but it was needed (a.k.a., client don't use that
                 // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
                 resumeTargetStackIfNeeded();
-                if (outActivity.length > 0) {
+                if (outActivity != null && outActivity.length > 0) {
                     outActivity[0] = reusedActivity;
                 }
                 return START_TASK_TO_FRONT;
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 672f563..34cdb54 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.app.RemoteAction;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
@@ -50,8 +51,21 @@
 
     void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
             boolean schedulePipModeChangedOnAnimationEnd) {
-        getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
-                animationDuration, schedulePipModeChangedOnAnimationEnd);
+        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
+            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+        } else {
+            getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
+                    animationDuration, schedulePipModeChangedOnAnimationEnd);
+        }
+    }
+
+    private boolean skipResizeAnimation(boolean toFullscreen) {
+        if (!toFullscreen) {
+            return false;
+        }
+        final Configuration parentConfig = getParent().getConfiguration();
+        final ActivityRecord top = topRunningNonOverlayTaskActivity();
+        return top != null && !top.isConfigurationCompatible(parentConfig);
     }
 
     void setPictureInPictureAspectRatio(float aspectRatio) {
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index d1275bb..7849896 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -47,7 +47,6 @@
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
-import com.android.server.vr.VrManagerService;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.Calendar;
@@ -62,7 +61,6 @@
         implements NightDisplayController.Callback {
 
     private static final String TAG = "NightDisplayService";
-    private static final boolean DEBUG = false;
 
     /**
      * The transition time, in milliseconds, for Night Display to turn on/off.
@@ -151,8 +149,9 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_SYSTEM_SERVICES_READY) {
-            IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE);
+        if (phase >= PHASE_SYSTEM_SERVICES_READY) {
+            final IVrManager vrManager = IVrManager.Stub.asInterface(
+                    getBinderService(Context.VR_SERVICE));
             if (vrManager != null) {
                 try {
                     vrManager.registerListener(mVrStateCallbacks);
@@ -160,7 +159,9 @@
                     Slog.e(TAG, "Failed to register VR mode state listener: " + e);
                 }
             }
-        } else if (phase == PHASE_BOOT_COMPLETED) {
+        }
+
+        if (phase >= PHASE_BOOT_COMPLETED) {
             mBootCompleted = true;
 
             // Register listeners now that boot is complete.
@@ -284,12 +285,18 @@
         if (mIsActivated == null || mIsActivated != activated) {
             Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
 
-            if (mAutoMode != null) {
-                mAutoMode.onActivated(activated);
+            if (mIsActivated != null) {
+                Secure.putLongForUser(getContext().getContentResolver(),
+                        Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+                        mCurrentUser);
             }
 
             mIsActivated = activated;
 
+            if (mAutoMode != null) {
+                mAutoMode.onActivated(activated);
+            }
+
             applyTint(false);
         }
     }
@@ -401,7 +408,7 @@
      * Set the color transformation {@code MATRIX_NIGHT} to the given color temperature.
      *
      * @param colorTemperature color temperature in Kelvin
-     * @param outTemp the 4x4 display transformation matrix for that color temperature
+     * @param outTemp          the 4x4 display transformation matrix for that color temperature
      */
     private void setMatrix(int colorTemperature, float[] outTemp) {
         if (outTemp.length != 16) {
@@ -423,8 +430,22 @@
         outTemp[10] = blue;
     }
 
+    private Calendar getLastActivatedTime() {
+        final ContentResolver cr = getContext().getContentResolver();
+        final long lastActivatedTimeMillis = Secure.getLongForUser(
+                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mCurrentUser);
+        if (lastActivatedTimeMillis < 0) {
+            return null;
+        }
+
+        final Calendar lastActivatedTime = Calendar.getInstance();
+        lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
+        return lastActivatedTime;
+    }
+
     private abstract class AutoMode implements NightDisplayController.Callback {
         public abstract void onStart();
+
         public abstract void onStop();
     }
 
@@ -438,7 +459,7 @@
 
         private Calendar mLastActivatedTime;
 
-        public CustomAutoMode() {
+        CustomAutoMode() {
             mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
             mTimeChangedReceiver = new BroadcastReceiver() {
                 @Override
@@ -452,10 +473,10 @@
             final Calendar now = Calendar.getInstance();
             final Calendar startTime = mStartTime.getDateTimeBefore(now);
             final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
-            final boolean activated = now.before(endTime);
 
-            boolean setActivated = mIsActivated == null || mLastActivatedTime == null;
-            if (!setActivated && mIsActivated != activated) {
+            boolean activate = now.before(endTime);
+            if (mLastActivatedTime != null) {
+                // Convert mLastActivatedTime to the current timezone if needed.
                 final TimeZone currentTimeZone = now.getTimeZone();
                 if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
                     final int year = mLastActivatedTime.get(Calendar.YEAR);
@@ -470,17 +491,16 @@
                     mLastActivatedTime.set(Calendar.MINUTE, minute);
                 }
 
-                if (mIsActivated) {
-                    setActivated = now.before(mStartTime.getDateTimeBefore(mLastActivatedTime))
-                            || now.after(mEndTime.getDateTimeAfter(mLastActivatedTime));
-                } else {
-                    setActivated = now.before(mEndTime.getDateTimeBefore(mLastActivatedTime))
-                            || now.after(mStartTime.getDateTimeAfter(mLastActivatedTime));
+                // Maintain the existing activated state if within the current period.
+                if (mLastActivatedTime.before(now)
+                        && mLastActivatedTime.after(startTime)
+                        && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+                    activate = mController.isActivated();
                 }
             }
 
-            if (setActivated) {
-                mController.setActivated(activated);
+            if (mIsActivated == null || mIsActivated != activate) {
+                mController.setActivated(activate);
             }
             updateNextAlarm(mIsActivated, now);
         }
@@ -502,6 +522,8 @@
             mStartTime = mController.getCustomStartTime();
             mEndTime = mController.getCustomEndTime();
 
+            mLastActivatedTime = getLastActivatedTime();
+
             // Force an update to initialize state.
             updateActivated();
         }
@@ -516,11 +538,8 @@
 
         @Override
         public void onActivated(boolean activated) {
-            final Calendar now = Calendar.getInstance();
-            if (mIsActivated != null) {
-                mLastActivatedTime = now;
-            }
-            updateNextAlarm(activated, now);
+            mLastActivatedTime = getLastActivatedTime();
+            updateNextAlarm(activated, Calendar.getInstance());
         }
 
         @Override
@@ -550,33 +569,33 @@
 
         private Calendar mLastActivatedTime;
 
-        public TwilightAutoMode() {
+        TwilightAutoMode() {
             mTwilightManager = getLocalService(TwilightManager.class);
         }
 
         private void updateActivated(TwilightState state) {
-            final boolean isNight = state != null && state.isNight();
-            boolean setActivated = mIsActivated == null || mIsActivated != isNight;
-            if (setActivated && state != null && mLastActivatedTime != null) {
+            boolean activate = state != null && state.isNight();
+            if (state != null && mLastActivatedTime != null) {
+                final Calendar now = Calendar.getInstance();
                 final Calendar sunrise = state.sunrise();
                 final Calendar sunset = state.sunset();
-                if (sunrise.before(sunset)) {
-                    setActivated = mLastActivatedTime.before(sunrise)
-                            || mLastActivatedTime.after(sunset);
-                } else {
-                    setActivated = mLastActivatedTime.before(sunset)
-                            || mLastActivatedTime.after(sunrise);
+
+                // Maintain the existing activated state if within the current period.
+                if (mLastActivatedTime.before(now)
+                        && (mLastActivatedTime.after(sunrise) ^ mLastActivatedTime.after(sunset))) {
+                    activate = mController.isActivated();
                 }
             }
 
-            if (setActivated) {
-                mController.setActivated(isNight);
+            if (mIsActivated == null || mIsActivated != activate) {
+                mController.setActivated(activate);
             }
         }
 
         @Override
         public void onStart() {
             mTwilightManager.registerListener(this, mHandler);
+            mLastActivatedTime = getLastActivatedTime();
 
             // Force an update to initialize state.
             updateActivated(mTwilightManager.getLastTwilightState());
@@ -591,7 +610,7 @@
         @Override
         public void onActivated(boolean activated) {
             if (mIsActivated != null) {
-                mLastActivatedTime = Calendar.getInstance();
+                mLastActivatedTime = getLastActivatedTime();
             }
         }
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 91c32e4..51bebb09 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -382,6 +382,8 @@
     // Wakelocks
     private final static String WAKELOCK_KEY = "GnssLocationProvider";
     private final PowerManager.WakeLock mWakeLock;
+    private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderXtraDownload";
+    private final PowerManager.WakeLock mDownloadXtraWakeLock;
 
     // Alarms
     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
@@ -686,6 +688,11 @@
         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
         mWakeLock.setReferenceCounted(true);
 
+        // Create a separate wake lock for xtra downloader as it may be released due to timeout.
+        mDownloadXtraWakeLock = mPowerManager.newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
+        mDownloadXtraWakeLock.setReferenceCounted(true);
+
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
@@ -989,7 +996,7 @@
         mDownloadXtraDataPending = STATE_DOWNLOADING;
 
         // hold wake lock while task runs
-        mWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
+        mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
             @Override
@@ -1011,13 +1018,17 @@
                             mXtraBackOff.nextBackoffMillis());
                 }
 
-                // release wake lock held by task
-                if (mWakeLock.isHeld()) {
-                    mWakeLock.release();
-                } else {
-                    Log.e(TAG, "WakeLock expired before release in handleDownloadXtraData()");
+                // Release wake lock held by task, synchronize on mLock in case multiple
+                // download tasks overrun.
+                synchronized (mLock) {
+                    if (mDownloadXtraWakeLock.isHeld()) {
+                        mDownloadXtraWakeLock.release();
+                        if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
+                    } else {
+                        Log.e(TAG, "WakeLock expired before release in "
+                                + "handleDownloadXtraData()");
+                    }
                 }
-                Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
             }
         });
     }
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 63647ff..8caaaa1 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -73,11 +73,13 @@
         // Next: sufficiently import person to person communication
         boolean leftPeople = isImportantPeople(left);
         boolean rightPeople = isImportantPeople(right);
+        final int contactAffinityComparison =
+                Float.compare(left.getContactAffinity(), right.getContactAffinity());
 
         if (leftPeople && rightPeople){
             // by contact proximity, close to far. if same proximity, check further fields.
-            if (Float.compare(left.getContactAffinity(), right.getContactAffinity()) != 0) {
-                return -1 * Float.compare(left.getContactAffinity(), right.getContactAffinity());
+            if (contactAffinityComparison != 0) {
+                return -1 * contactAffinityComparison;
             }
         } else if (leftPeople != rightPeople) {
             // People, messaging higher than non-messaging
@@ -91,6 +93,11 @@
             return -1 * Integer.compare(leftImportance, rightImportance);
         }
 
+        // by contact proximity, close to far. if same proximity, check further fields.
+        if (contactAffinityComparison != 0) {
+            return -1 * contactAffinityComparison;
+        }
+
         // Whether or not the notification can bypass DND.
         final int leftPackagePriority = left.getPackagePriority();
         final int rightPackagePriority = right.getPackagePriority();
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index 31ed350..f92bf3d 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.net.Uri;
 import android.service.notification.NotificationListenerService;
 import android.util.Log;
 import android.util.Slog;
@@ -46,12 +47,13 @@
         }
 
         if (record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT) {
-            final Notification notification = record.getNotification();
-            if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
-                    notification.vibrate != null ||
-                    (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
-                    notification.sound != null ||
-                    notification.fullScreenIntent != null) {
+            if (record.getSound() != null && record.getSound() != Uri.EMPTY) {
+                record.setRecentlyIntrusive(true);
+            }
+            if (record.getVibration() != null) {
+                record.setRecentlyIntrusive(true);
+            }
+            if (record.getNotification().fullScreenIntent != null) {
                 record.setRecentlyIntrusive(true);
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d8d099b..48d11c3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2869,7 +2869,8 @@
                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
                                 System.currentTimeMillis());
                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
-                        notificationRecord.getChannel());
+                        notificationRecord.getChannel(), mRankingHelper.supportsChannels(
+                                summarySbn.getPackageName(), summarySbn.getUid()));
                 summaries.put(pkg, summarySbn.getKey());
             }
         }
@@ -3189,12 +3190,6 @@
         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
                 notificationUid, channelId, false /* includeDeleted */);
         if (channel == null) {
-            // STOPSHIP TODO: remove before release - should always throw without a valid channel.
-            if (channelId == null) {
-                Log.e(TAG, "Cannot post notification without channel ID when targeting O "
-                        + " - notification=" + notification);
-                return;
-            }
             final String noChannelStr = "No Channel found for "
                     + "pkg=" + pkg
                     + ", channelId=" + channelId
@@ -3211,18 +3206,13 @@
                     "Failed to post notification on channel \"" + channelId + "\"\n" +
                     "See log for more details");
             return;
-        } else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) {
-            // STOPSHIP TODO: remove once default channel is removed for all apps that target O.
-            Log.e(TAG, "Developer Warning for package " + pkg
-                    + ", no channel specified for posted notification: " + notification);
-            doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
-                    "Posted notification should specify a channel");
         }
 
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                 user, null, System.currentTimeMillis());
-        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
+        final NotificationRecord r = new NotificationRecord(getContext(), n, channel,
+                mRankingHelper.supportsChannels(pkg, notificationUid));
 
         if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
             return;
@@ -3259,19 +3249,6 @@
         }
     }
 
-    // STOPSHIP - Remove once RankingHelper deletes default channel for all apps targeting O.
-    private boolean shouldWarnUseChannels(String pkg, int uid) {
-        try {
-            final int userId = UserHandle.getUserId(uid);
-            final ApplicationInfo applicationInfo =
-                    mPackageManagerClient.getApplicationInfoAsUser(pkg, 0, userId);
-            return applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1;
-        } catch (NameNotFoundException e) {
-            Slog.e(TAG, e.toString());
-            return false;
-        }
-    }
-
     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
         // The system can post notifications on behalf of any package it wants
         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b51a4d1..90257da 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -115,7 +115,7 @@
     private int mSuppressedVisualEffects = 0;
     private String mUserExplanation;
     private String mPeopleExplanation;
-    private boolean mPreChannelsNotification = true;
+    private boolean mSupportsChannels = false;
     private Uri mSound;
     private long[] mVibration;
     private AudioAttributes mAttributes;
@@ -128,7 +128,7 @@
 
     @VisibleForTesting
     public NotificationRecord(Context context, StatusBarNotification sbn,
-            NotificationChannel channel)
+            NotificationChannel channel, boolean supportsChannels)
     {
         this.sbn = sbn;
         mOriginalFlags = sbn.getNotification().flags;
@@ -138,7 +138,7 @@
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
         mChannel = channel;
-        mPreChannelsNotification = isPreChannelsNotification();
+        mSupportsChannels = supportsChannels;
         mSound = calculateSound();
         mVibration = calculateVibration();
         mAttributes = calculateAttributes();
@@ -146,27 +146,11 @@
         mLight = calculateLights();
     }
 
-    private boolean isPreChannelsNotification() {
-        try {
-            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
-                  final ApplicationInfo applicationInfo =
-                        mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
-                                0, UserHandle.getUserId(sbn.getUid()));
-                if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
-                    return true;
-                }
-            }
-        } catch (NameNotFoundException e) {
-            Slog.e(TAG, "Can't find package", e);
-        }
-        return false;
-    }
-
     private Uri calculateSound() {
         final Notification n = sbn.getNotification();
 
         Uri sound = mChannel.getSound();
-        if (mPreChannelsNotification && (getChannel().getUserLockedFields()
+        if (!mSupportsChannels && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
 
             final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -191,7 +175,7 @@
                 : defaultLightColor;
         Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
                 defaultLightOn, defaultLightOff) : null;
-        if (mPreChannelsNotification
+        if (!mSupportsChannels
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
             final Notification notification = sbn.getNotification();
@@ -222,7 +206,7 @@
         } else {
             vibration = null;
         }
-        if (mPreChannelsNotification
+        if (!mSupportsChannels
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
             final Notification notification = sbn.getNotification();
@@ -244,7 +228,7 @@
             attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
         }
 
-        if (mPreChannelsNotification
+        if (!mSupportsChannels
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
             if (n.audioAttributes != null) {
@@ -293,7 +277,7 @@
         stats.requestedImportance = requestedImportance;
         stats.isNoisy = mSound != null || mVibration != null;
 
-        if (mPreChannelsNotification
+        if (!mSupportsChannels
                 && (importance == IMPORTANCE_UNSPECIFIED
                 || (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
@@ -460,7 +444,7 @@
         pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
-        if (mPreChannelsNotification) {
+        if (!mSupportsChannels) {
             pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
             pw.println(prefix + "n.sound=" + notification.sound);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 4d19b52..14d796f 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -42,4 +42,6 @@
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannels(String pkg, int uid);
     ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
+
+    boolean supportsChannels(String pkg, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6d18c83..3481556 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -273,31 +273,21 @@
     }
 
     private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
+        if (supportsChannels(r)) {
+            return false;
+        }
+
         final int userId = UserHandle.getUserId(r.uid);
-        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
-        if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
-            // Pre-O apps should have it.
-            return true;
+        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                userId);
+        if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+            // O apps should not have the default channel.
+            return false;
         }
 
-        // STOPSHIP TODO: remove before release - O+ apps should never have a default channel.
-        // But for now, leave the default channel until an app has created its first channel.
-        boolean hasCreatedAChannel = false;
-        final int size = r.channels.size();
-        for (int i = 0; i < size; i++) {
-            final NotificationChannel notificationChannel = r.channels.valueAt(i);
-            if (notificationChannel != null &&
-                    !notificationChannel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-                hasCreatedAChannel = true;
-                break;
-            }
-        }
-        if (!hasCreatedAChannel) {
-            return true;
-        }
-
-        // Otherwise, should not have the default channel.
-        return false;
+        // Otherwise, this app should have the default channel.
+        return true;
     }
 
     private void deleteDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
@@ -516,6 +506,31 @@
     }
 
     @Override
+    public boolean supportsChannels(String pkg, int uid) {
+        Record r = getOrCreateRecord(pkg, uid);
+
+        if (r == null) {
+            return false;
+        }
+
+        if (r.channels.size() == 1
+                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean supportsChannels(Record r) {
+        if (r.channels.size() == 1
+                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+            return false;
+        }
+
+        return (r.channels.size() > 0);
+    }
+
+    @Override
     public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
             boolean fromTargetApp) {
         Preconditions.checkNotNull(pkg);
@@ -587,6 +602,10 @@
         r.channels.put(channel.getId(), channel);
         MetricsLogger.action(getChannelLog(channel, pkg).setType(
                 MetricsProto.MetricsEvent.TYPE_OPEN));
+
+        // Remove Default Channel.
+        r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
+
         updateConfig();
     }
 
@@ -683,13 +702,7 @@
         if (r == null) {
             return;
         }
-        int N = r.channels.size() - 1;
-        for (int i = N; i >= 0; i--) {
-            String key = r.channels.keyAt(i);
-            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
-                r.channels.remove(key);
-            }
-        }
+        r.channels.clear();
         updateConfig();
     }
 
@@ -1041,6 +1054,8 @@
                 final int uid = uidList[i];
                 synchronized (mRecords) {
                     mRecords.remove(recordKey(pkg, uid));
+                    // reset to default settings and re-add misc channel for pre-O apps
+                    getOrCreateRecord(pkg, uid);
                 }
                 mRestoredWithoutUids.remove(pkg);
                 updated = true;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 254bc2a..4c0d9da 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -361,10 +361,10 @@
         boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
         if (vmSafeMode) {
             // For the compilation, it doesn't really matter what we return here because installd
-            // will replace the filter with interpret-only anyway.
+            // will replace the filter with 'quicken' anyway.
             // However, we return a non profile guided filter so that we simplify the logic of
             // merging profiles.
-            // TODO(calin): safe mode path could be simplified if we pass interpret-only from
+            // TODO(calin): safe mode path could be simplified if we pass 'quicken' from
             //              here rather than letting installd decide on the filter.
             return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 61d83e5..2686fcb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5870,10 +5870,9 @@
         return mEphemeralAppsDisabled;
     }
 
-    private boolean isEphemeralAllowed(
+    private boolean isInstantAppAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
             boolean skipPackageCheck) {
-        final int callingUser = UserHandle.getCallingUserId();
         if (mInstantAppResolverConnection == null) {
             return false;
         }
@@ -5973,7 +5972,13 @@
                 for (int i = 0; i < N; i++) {
                     ri = query.get(i);
                     if (ri.activityInfo.applicationInfo.isInstantApp()) {
-                        return ri;
+                        final String packageName = ri.activityInfo.packageName;
+                        final PackageSetting ps = mSettings.mPackages.get(packageName);
+                        final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+                        final int status = (int)(packedStatus >> 32);
+                        if (status != INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
+                            return ri;
+                        }
                     }
                 }
                 ri = new ResolveInfo(mResolveInfo);
@@ -6417,7 +6422,7 @@
                 result = filterIfNotSystemUser(mActivities.queryIntent(
                         intent, resolvedType, flags, userId), userId);
                 addEphemeral = !ephemeralDisabled
-                        && isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
+                        && isInstantAppAllowed(intent, result, userId, false /*skipPackageCheck*/);
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                 xpResolveInfo = queryCrossProfileIntents(
@@ -6474,45 +6479,14 @@
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
                     addEphemeral = !ephemeralDisabled
-                            && isEphemeralAllowed(
+                            && isInstantAppAllowed(
                                     intent, null /*result*/, userId, true /*skipPackageCheck*/);
                     result = new ArrayList<ResolveInfo>();
                 }
             }
         }
         if (addEphemeral) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-            final InstantAppRequest requestObject = new InstantAppRequest(
-                    null /*responseObj*/, intent /*origIntent*/, resolvedType,
-                    null /*callingPackage*/, userId, null /*verificationBundle*/);
-            final AuxiliaryResolveInfo auxiliaryResponse =
-                    InstantAppResolver.doInstantAppResolutionPhaseOne(
-                            mContext, mInstantAppResolverConnection, requestObject);
-            if (auxiliaryResponse != null) {
-                if (DEBUG_EPHEMERAL) {
-                    Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
-                }
-                final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
-                final PackageSetting ps =
-                        mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
-                if (ps != null) {
-                    ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
-                            mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
-                    ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
-                    ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
-                    // make sure this resolver is the default
-                    ephemeralInstaller.isDefault = true;
-                    ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
-                            | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
-                    // add a non-generic filter
-                    ephemeralInstaller.filter = new IntentFilter(intent.getAction());
-                    ephemeralInstaller.filter.addDataPath(
-                            intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
-                    ephemeralInstaller.isInstantAppAvailable = true;
-                    result.add(ephemeralInstaller);
-                }
-            }
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            result = maybeAddInstantAppInstaller(result, intent, resolvedType, flags, userId);
         }
         if (sortResult) {
             Collections.sort(result, mResolvePrioritySorter);
@@ -6520,6 +6494,86 @@
         return applyPostResolutionFilter(result, instantAppPkgName);
     }
 
+    private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
+            String resolvedType, int flags, int userId) {
+        // first, check to see if we've got an instant app already installed
+        final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
+        boolean localInstantAppAvailable = false;
+        boolean blockResolution = false;
+        if (!alreadyResolvedLocally) {
+            final List<ResolveInfo> instantApps = mActivities.queryIntent(intent, resolvedType,
+                    flags
+                        | PackageManager.MATCH_INSTANT
+                        | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
+                    userId);
+            for (int i = instantApps.size() - 1; i >= 0; --i) {
+                final ResolveInfo info = instantApps.get(i);
+                final String packageName = info.activityInfo.packageName;
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps.getInstantApp(userId)) {
+                    final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+                    final int status = (int)(packedStatus >> 32);
+                    final int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
+                    if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+                        // there's a local instant application installed, but, the user has
+                        // chosen to never use it; skip resolution and don't acknowledge
+                        // an instant application is even available
+                        if (DEBUG_EPHEMERAL) {
+                            Slog.v(TAG, "Instant app marked to never run; pkg: " + packageName);
+                        }
+                        blockResolution = true;
+                        break;
+                    } else {
+                        // we have a locally installed instant application; skip resolution
+                        // but acknowledge there's an instant application available
+                        if (DEBUG_EPHEMERAL) {
+                            Slog.v(TAG, "Found installed instant app; pkg: " + packageName);
+                        }
+                        localInstantAppAvailable = true;
+                        break;
+                    }
+                }
+            }
+        }
+        // no app installed, let's see if one's available
+        AuxiliaryResolveInfo auxiliaryResponse = null;
+        if (!localInstantAppAvailable && !blockResolution) {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+            final InstantAppRequest requestObject = new InstantAppRequest(
+                    null /*responseObj*/, intent /*origIntent*/, resolvedType,
+                    null /*callingPackage*/, userId, null /*verificationBundle*/);
+            auxiliaryResponse =
+                    InstantAppResolver.doInstantAppResolutionPhaseOne(
+                            mContext, mInstantAppResolverConnection, requestObject);
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+        if (localInstantAppAvailable || auxiliaryResponse != null) {
+            if (DEBUG_EPHEMERAL) {
+                Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+            }
+            final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
+            final PackageSetting ps =
+                    mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
+            if (ps != null) {
+                ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
+                        mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
+                ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
+                ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
+                // make sure this resolver is the default
+                ephemeralInstaller.isDefault = true;
+                ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+                        | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+                // add a non-generic filter
+                ephemeralInstaller.filter = new IntentFilter(intent.getAction());
+                ephemeralInstaller.filter.addDataPath(
+                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+                ephemeralInstaller.instantAppAvailable = true;
+                result.add(ephemeralInstaller);
+            }
+        }
+        return result;
+    }
+
     private static class CrossProfileDomainInfo {
         /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
         ResolveInfo resolveInfo;
@@ -8667,7 +8721,7 @@
             // are verify-profile but for preopted apps there's no profile.
             // Do a hacky check to ensure that if we have no profiles (a reasonable indication
             // that before the OTA the app was preopted) the app gets compiled with a non-profile
-            // filter (by default interpret-only).
+            // filter (by default 'quicken').
             // Note that at this stage unused apps are already filtered.
             if (isSystemApp(pkg) &&
                     DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 25a596a..c1d68b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1598,10 +1598,10 @@
         pw.println("      -f: force compilation even if not needed");
         pw.println("      -m: select compilation mode");
         pw.println("          MODE is one of the dex2oat compiler filters:");
-        pw.println("            verify-none");
-        pw.println("            verify-at-runtime");
-        pw.println("            verify-profile");
-        pw.println("            interpret-only");
+        pw.println("            assume-verified");
+        pw.println("            extract");
+        pw.println("            verify");
+        pw.println("            quicken");
         pw.println("            space-profile");
         pw.println("            space");
         pw.println("            speed-profile");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7e03d80..4fb18d9 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -184,6 +184,7 @@
 import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.service.vr.IPersistentVrStateCallbacks;
 import android.speech.RecognizerIntent;
 import android.telecom.TelecomManager;
 import android.util.DisplayMetrics;
@@ -512,6 +513,8 @@
     volatile boolean mGoingToSleep;
     volatile boolean mRecentsVisible;
     volatile boolean mPictureInPictureVisible;
+    // Written by vr manager thread, only read in this class.
+    volatile private boolean mPersistentVrModeEnabled;
     volatile private boolean mDismissImeOnBackKeyPressed;
 
     // Used to hold the last user key used to wake the device.  This helps us prevent up events
@@ -1002,6 +1005,14 @@
     }
     MyOrientationListener mOrientationListener;
 
+    final IPersistentVrStateCallbacks mPersistentVrModeListener =
+            new IPersistentVrStateCallbacks.Stub() {
+        @Override
+        public void onPersistentVrStateChanged(boolean enabled) {
+            mPersistentVrModeEnabled = enabled;
+        }
+    };
+
     private final StatusBarController mStatusBarController = new StatusBarController();
 
     private final BarController mNavigationBarController = new BarController("NavigationBar",
@@ -6909,7 +6920,13 @@
                         || mAllowAllRotations == 1
                         || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                         || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
-                    preferredRotation = sensorRotation;
+                    // In VrMode, we report the sensor as always being in default orientation so:
+                    // 1) The orientation doesn't change as the user moves their head.
+                    // 2) 2D apps within VR show in the device's default orientation.
+                    // This only overwrites the sensor-provided orientation and does not affect any
+                    // explicit orientation preferences specified by any activities.
+                    preferredRotation =
+                            mPersistentVrModeEnabled ? Surface.ROTATION_0 : sensorRotation;
                 } else {
                     preferredRotation = lastRotation;
                 }
@@ -7083,6 +7100,9 @@
         mKeyguardDelegate.onSystemReady();
 
         mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
+        if (mVrManagerInternal != null) {
+            mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
+        }
 
         readCameraLensCoverState();
         updateUiMode();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8c3d80f..423bc0c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4632,12 +4632,6 @@
         }
 
         @Override
-        public void setButtonBrightnessOverrideFromWindowManager(int screenBrightness) {
-            // Do nothing.
-            // Button lights are not currently supported in the new implementation.
-        }
-
-        @Override
         public void setDozeOverrideFromDreamManager(int screenState, int screenBrightness) {
             switch (screenState) {
                 case Display.STATE_UNKNOWN:
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index a12965d..30a8ccc 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -31,7 +31,7 @@
     private final long mSunriseTimeMillis;
     private final long mSunsetTimeMillis;
 
-    TwilightState(long sunriseTimeMillis, long sunsetTimeMillis) {
+    public TwilightState(long sunriseTimeMillis, long sunsetTimeMillis) {
         mSunriseTimeMillis = sunriseTimeMillis;
         mSunsetTimeMillis = sunsetTimeMillis;
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index c625cbe..b5e194b 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -36,7 +36,6 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Trace;
 import android.util.Slog;
 import android.view.IApplicationToken;
@@ -319,7 +318,7 @@
                         + " token: " + mToken);
                 return;
             }
-            mContainer.setDisablePreviewSnapshots(disable);
+            mContainer.setDisablePreviewScreenshots(disable);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 36418be..640bac2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -23,6 +23,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -48,6 +49,7 @@
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
 import android.annotation.NonNull;
+import android.app.Activity;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -1528,12 +1530,24 @@
         return candidate;
     }
 
-    void setDisablePreviewSnapshots(boolean disable) {
+    /**
+     * See {@link Activity#setDisablePreviewScreenshots}.
+     */
+    void setDisablePreviewScreenshots(boolean disable) {
         mDisbalePreviewScreenshots = disable;
     }
 
-    boolean shouldDisablePreviewScreenshots() {
-        return mDisbalePreviewScreenshots;
+    /**
+     * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
+     * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
+     * we can't take a snapshot for other reasons, for example, if we have a secure window.
+     *
+     * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
+     *         screenshot.
+     */
+    boolean shouldUseAppThemeSnapshot() {
+        return mDisbalePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
+                true /* topToBottom */);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 4100446..d44cd13 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -188,6 +188,7 @@
     boolean animateDimLayers() {
         int fullScreen = -1;
         int fullScreenAndDimming = -1;
+        int topFullScreenUserLayer = 0;
         boolean result = false;
 
         for (int i = mState.size() - 1; i >= 0; i--) {
@@ -213,8 +214,18 @@
             // and we have to make sure we always animate the layer.
             if (user.dimFullscreen() && state.dimLayer == mSharedFullScreenDimLayer) {
                 fullScreen = i;
-                if (mState.valueAt(i).continueDimming) {
+                if (!state.continueDimming) {
+                    continue;
+                }
+
+                // When choosing which user to assign the shared fullscreen layer to
+                // we need to look at Z-order.
+                if (topFullScreenUserLayer == 0 ||
+                        (state.animator != null && state.animator.mAnimLayer > topFullScreenUserLayer)) {
                     fullScreenAndDimming = i;
+                    if (state.animator != null) {
+                        topFullScreenUserLayer = state.animator.mAnimLayer;
+                    }
                 }
             } else {
                 // We always want to animate the non fullscreen windows, they don't share their
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 05b95e2..be242b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1503,8 +1503,16 @@
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
-    @Override
-    int getOrientation() {
+    /**
+     * Returns the orientation that this display should be in factoring in its children containers.
+     *
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     * @return The orientation the display should be in.
+     */
+    int getOrientation(boolean includeAppContainers) {
         final WindowManagerPolicy policy = mService.mPolicy;
 
         if (mService.mDisplayFrozen) {
@@ -1533,8 +1541,14 @@
             }
         }
 
-        // Top system windows are not requesting an orientation. Start searching from apps.
-        return mTaskStackContainers.getOrientation();
+        // Top system windows are not requesting an orientation. Get orientation from app containers
+        // if allowed. Otherwise, return the last orientation.
+        return includeAppContainers ? mTaskStackContainers.getOrientation() : mLastOrientation;
+    }
+
+    @Override
+    int getOrientation() {
+        return getOrientation(true /* includeAppContainers */);
     }
 
     void updateDisplayInfo() {
@@ -1793,7 +1807,13 @@
             // events to be intercepted and used to change focus. This would likely cause a
             // disappearance of the input method.
             inputMethod.getTouchableRegion(mTmpRegion);
-            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
+            if (inputMethod.getDisplayId() == mDisplayId) {
+                mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
+            } else {
+                // IME is on a different display, so we need to update its tap detector.
+                // TODO(multidisplay): Remove when IME will always appear on same display.
+                inputMethod.getDisplayContent().setTouchExcludeRegion(null /* focusedTask */);
+            }
         }
         for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
             WindowState win = mTapExcludedWindows.get(i);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 60b136f..be3558b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -21,7 +21,10 @@
 import android.hardware.power.V1_0.PowerHint;
 import android.os.Binder;
 import android.os.Debug;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -34,6 +37,8 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.WindowManager;
+
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.EventLogTags;
 
@@ -87,13 +92,15 @@
 class RootWindowContainer extends WindowContainer<DisplayContent> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RootWindowContainer" : TAG_WM;
 
+    private static final int SET_SCREEN_BRIGHTNESS_OVERRIDE = 1;
+    private static final int SET_USER_ACTIVITY_TIMEOUT = 2;
+
     WindowManagerService mService;
 
     private boolean mWallpaperForceHidingChanged = false;
     private Object mLastWindowFreezeSource = null;
     private Session mHoldScreen = null;
     private float mScreenBrightness = -1;
-    private float mButtonBrightness = -1;
     private long mUserActivityTimeout = -1;
     private boolean mUpdateRotation = false;
     // Following variables are for debugging screen wakelock only.
@@ -128,6 +135,8 @@
     private final WindowLayersController mLayersController;
     final WallpaperController mWallpaperController;
 
+    private final Handler mHandler;
+
     private String mCloseSystemDialogsReason;
     private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> {
         if (w.mHasSurface) {
@@ -147,6 +156,7 @@
 
     RootWindowContainer(WindowManagerService service) {
         mService = service;
+        mHandler = new MyHandler(service.mH.getLooper());
         mLayersController = new WindowLayersController(mService);
         mWallpaperController = new WallpaperController(mService);
     }
@@ -552,7 +562,6 @@
 
         mHoldScreen = null;
         mScreenBrightness = -1;
-        mButtonBrightness = -1;
         mUserActivityTimeout = -1;
         mObscureApplicationContentOnSecondaryDisplays = false;
         mSustainedPerformanceModeCurrent = false;
@@ -702,20 +711,13 @@
 
         mService.setHoldScreenLocked(mHoldScreen);
         if (!mService.mDisplayFrozen) {
-            if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
-                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mScreenBrightness));
-            }
-            if (mButtonBrightness < 0 || mButtonBrightness > 1.0f) {
-                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mButtonBrightness));
-            }
-            mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
-                    mUserActivityTimeout);
+            final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
+                    ? -1 : toBrightnessOverride(mScreenBrightness);
+
+            // Post these on a handler such that we don't call into power manager service while
+            // holding the window manager lock to avoid lock contention with power manager lock.
+            mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
+            mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
         }
 
         if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
@@ -863,9 +865,6 @@
             if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
                 mScreenBrightness = w.mAttrs.screenBrightness;
             }
-            if (!syswin && w.mAttrs.buttonBrightness >= 0 && mButtonBrightness < 0) {
-                mButtonBrightness = w.mAttrs.buttonBrightness;
-            }
             if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
                 mUserActivityTimeout = w.mAttrs.userActivityTimeout;
             }
@@ -935,6 +934,29 @@
         return (int)(value * PowerManager.BRIGHTNESS_ON);
     }
 
+    private final class MyHandler extends Handler {
+
+        public MyHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SET_SCREEN_BRIGHTNESS_OVERRIDE:
+                    mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+                            msg.arg1);
+                    break;
+                case SET_USER_ACTIVITY_TIMEOUT:
+                    mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
+                            (Long) msg.obj);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
     void enableSurfaceTrace(ParcelFileDescriptor pfd) {
         final FileDescriptor fd = pfd.getFileDescriptor();
         if (mSurfaceTraceEnabled) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index fbb826d..b79173c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -31,11 +31,13 @@
 import android.graphics.Rect;
 import android.os.Environment;
 import android.util.ArraySet;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.google.android.collect.Sets;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
 
 import java.io.PrintWriter;
 
@@ -206,7 +208,7 @@
         final AppWindowToken topChild = task.getTopChild();
         if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
             return SNAPSHOT_MODE_NONE;
-        } else if (topChild != null && topChild.shouldDisablePreviewScreenshots()) {
+        } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
             return SNAPSHOT_MODE_APP_THEME;
         } else {
             return SNAPSHOT_MODE_REAL;
@@ -227,6 +229,8 @@
             return null;
         }
         final int color = task.getTaskDescription().getBackgroundColor();
+        final int statusBarColor = task.getTaskDescription().getStatusBarColor();
+        final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
         final GraphicBuffer buffer = GraphicBuffer.create(mainWindow.getFrameLw().width(),
                 mainWindow.getFrameLw().height(),
                 RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_RARELY | USAGE_SW_READ_NEVER);
@@ -235,6 +239,11 @@
         }
         final Canvas c = buffer.lockCanvas();
         c.drawColor(color);
+        final LayoutParams attrs = mainWindow.getAttrs();
+        final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
+                attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
+        decorPainter.setInsets(mainWindow.mContentInsets, mainWindow.mStableInsets);
+        decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
         buffer.unlockCanvasAndPost(c);
         return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
                 mainWindow.mStableInsets, false /* reduced */, 1.0f /* scale */);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c816ba3..2b9e800 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -42,8 +42,11 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityThread;
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
 import android.graphics.Paint;
@@ -118,13 +121,8 @@
     private final Handler mHandler;
     private boolean mSizeMismatch;
     private final Paint mBackgroundPaint = new Paint();
-    private final Paint mStatusBarPaint = new Paint();
-    private final Paint mNavigationBarPaint = new Paint();
     private final int mStatusBarColor;
-    private final int mNavigationBarColor;
-    private final int mSysUiVis;
-    private final int mWindowFlags;
-    private final int mWindowPrivateFlags;
+    @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
 
     static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
             TaskSnapshot snapshot) {
@@ -224,15 +222,9 @@
         mTitle = title;
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
         mTaskBounds = taskBounds;
-        mSysUiVis = sysUiVis;
-        mWindowFlags = windowFlags;
-        mWindowPrivateFlags = windowPrivateFlags;
-        mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
-                service.mContext.getColor(R.color.system_bar_background_semi_transparent),
-                statusBarColor);
-        mNavigationBarColor = navigationBarColor;
-        mStatusBarPaint.setColor(mStatusBarColor);
-        mNavigationBarPaint.setColor(navigationBarColor);
+        mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+                windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
+        mStatusBarColor = statusBarColor;
     }
 
     @Override
@@ -258,6 +250,7 @@
         mStableInsets.set(stableInsets);
         mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
                 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
+        mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
     }
 
     private void drawSnapshot() {
@@ -346,7 +339,7 @@
 
     @VisibleForTesting
     void drawBackgroundAndBars(Canvas c, Rect frame) {
-        final int statusBarHeight = getStatusBarColorViewHeight();
+        final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
         final boolean fillHorizontally = c.getWidth() > frame.right;
         final boolean fillVertically = c.getHeight() > frame.bottom;
         if (fillHorizontally) {
@@ -359,44 +352,7 @@
         if (fillVertically) {
             c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
         }
-        drawStatusBarBackground(c, frame, statusBarHeight);
-        drawNavigationBarBackground(c);
-    }
-
-    private int getStatusBarColorViewHeight() {
-        final boolean forceStatusBarBackground =
-                (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
-        if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
-            return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
-        } else {
-            return 0;
-        }
-    }
-
-    private boolean isNavigationBarColorViewVisible() {
-        return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
-    }
-
-    @VisibleForTesting
-    void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) {
-        if (statusBarHeight > 0 && c.getWidth() > frame.right) {
-            final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
-                    mContentInsets.right);
-            c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-        }
-    }
-
-    @VisibleForTesting
-    void drawNavigationBarBackground(Canvas c) {
-        final Rect navigationBarRect = new Rect();
-        getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
-                navigationBarRect);
-        final boolean visible = isNavigationBarColorViewVisible();
-        if (visible && !navigationBarRect.isEmpty()) {
-            c.drawRect(navigationBarRect, mNavigationBarPaint);
-        }
+        mSystemBarBackgroundPainter.drawDecors(c, frame);
     }
 
     private void reportDrawn() {
@@ -450,4 +406,84 @@
             }
         }
     }
+
+    /**
+     * Helper class to draw the background of the system bars in regions the task snapshot isn't
+     * filling the window.
+     */
+    static class SystemBarBackgroundPainter {
+
+        private final Rect mContentInsets = new Rect();
+        private final Rect mStableInsets = new Rect();
+        private final Paint mStatusBarPaint = new Paint();
+        private final Paint mNavigationBarPaint = new Paint();
+        private final int mStatusBarColor;
+        private final int mNavigationBarColor;
+        private final int mWindowFlags;
+        private final int mWindowPrivateFlags;
+        private final int mSysUiVis;
+
+        SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
+                int statusBarColor, int navigationBarColor) {
+            mWindowFlags = windowFlags;
+            mWindowPrivateFlags = windowPrivateFlags;
+            mSysUiVis = sysUiVis;
+            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+            mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
+                    context.getColor(R.color.system_bar_background_semi_transparent),
+                    statusBarColor);
+            mNavigationBarColor = navigationBarColor;
+            mStatusBarPaint.setColor(mStatusBarColor);
+            mNavigationBarPaint.setColor(navigationBarColor);
+        }
+
+        void setInsets(Rect contentInsets, Rect stableInsets) {
+            mContentInsets.set(contentInsets);
+            mStableInsets.set(stableInsets);
+        }
+
+        int getStatusBarColorViewHeight() {
+            final boolean forceStatusBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
+                return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
+            } else {
+                return 0;
+            }
+        }
+
+        private boolean isNavigationBarColorViewVisible() {
+            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
+        }
+
+        void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+            drawNavigationBarBackground(c);
+        }
+
+        @VisibleForTesting
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+                int statusBarHeight) {
+            if (statusBarHeight > 0
+                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+                final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
+                        mContentInsets.right);
+                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+            }
+        }
+
+        @VisibleForTesting
+        void drawNavigationBarBackground(Canvas c) {
+            final Rect navigationBarRect = new Rect();
+            getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
+                    navigationBarRect);
+            final boolean visible = isNavigationBarColorViewVisible();
+            if (visible && !navigationBarRect.isEmpty()) {
+                c.drawRect(navigationBarRect, mNavigationBarPaint);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a7f6600..a48397b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2373,7 +2373,7 @@
         try {
             synchronized(mWindowMap) {
                 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
-                        displayId);
+                        displayId, true /* includeAppContainers */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2383,13 @@
     }
 
     private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded, int displayId) {
+            IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
         if (!mDisplayReady) {
             return null;
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId)) {
+        if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2427,6 +2427,11 @@
         return config;
     }
 
+    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+        return updateOrientationFromAppTokensLocked(inTransaction, displayId,
+                false /* includeAppContainers */);
+    }
+
     /**
      * Determine the new desired orientation of the display, returning a non-null new Configuration
      * if it has changed from the current orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
@@ -2437,13 +2442,25 @@
      * The orientation is computed from non-application windows first. If none of the
      * non-application windows specify orientation, the orientation is computed from application
      * tokens.
+     *
+     * @param inTransaction True if we are currently in a surface transaction.
+     * @param displayId Id of the display to update orientation for.
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     *                             NOTE: Only call originating from activity manager are expected to
+     *                             set this to true as it needs to synchronize several app states
+     *                             like visibility with the update of display orientation.
+     * @return True if the display orientation was updated.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
      */
-    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
-        long ident = Binder.clearCallingIdentity();
+    private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
+            boolean includeAppContainers) {
+        final long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
-            final int req = dc.getOrientation();
+            final int req = dc.getOrientation(includeAppContainers);
             if (req != dc.getLastOrientation()) {
                 dc.setLastOrientation(req);
                 //send a message to Policy indicating orientation change to take
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 0cf4994..2e8b068 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -69,7 +69,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index d4904f5..5e8b3d4 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -259,7 +259,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
         mService.addNotification(r);
         return r;
     }
@@ -769,7 +769,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
         mService.addNotification(r);
 
         mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 24cb72e..33d2d07 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -53,21 +53,21 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
         left.setGlobalSortKey("first");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
         right.setGlobalSortKey("second");
 
         NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
 
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -93,13 +93,13 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
         right.setGlobalSortKey("not null");
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -124,14 +124,14 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
         left.setGlobalSortKey("not null");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel());
+                        "", 1499), getDefaultChannel(), true);
 
         final List<NotificationRecord> expected = new ArrayList<>();
         expected.add(left);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 3dbd803..7a2dbaf 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -71,7 +71,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index 84945ab..ccd2db0 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -108,7 +108,7 @@
                 .build();
         mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "minCall", callUid, callUid, n1,
-                new UserHandle(userId), "", 2000), getDefaultChannel());
+                new UserHandle(userId), "", 2000), getDefaultChannel(), false);
         mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
 
         Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -118,7 +118,7 @@
                 .build();
         mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "highcall", callUid, callUid, n2,
-                new UserHandle(userId), "", 1999), getDefaultChannel());
+                new UserHandle(userId), "", 1999), getDefaultChannel(), false);
         mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -128,14 +128,14 @@
                 .build();
         mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
-                "", 1499), getDefaultChannel());
+                "", 1499), getDefaultChannel(), false);
         mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setStyle(new Notification.MessagingStyle("sender!")).build();
         mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
-                "", 1599), getDefaultChannel());
+                "", 1599), getDefaultChannel(), false);
         mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
         mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -143,27 +143,27 @@
                 .setCategory(Notification.CATEGORY_MESSAGE).build();
         mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
                 smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
-                "", 1299), getDefaultChannel());
+                "", 1299), getDefaultChannel(), false);
         mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
-                "", 1259), getDefaultChannel());
+                "", 1259), getDefaultChannel(), false);
         mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
         mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
-                "", 1259), getDefaultChannel());
+                "", 1259), getDefaultChannel(), false);
         mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
         mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
-                "", 1258), getDefaultChannel());
+                "", 1258), getDefaultChannel(), false);
         mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -173,7 +173,7 @@
                 .build();
         mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
-                "", 9258), getDefaultChannel());
+                "", 9258), getDefaultChannel(), false);
         mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
         mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -181,7 +181,7 @@
                 .setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
         mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
-                "", 1599), getDefaultChannel());
+                "", 1599), getDefaultChannel(), false);
         mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -190,7 +190,7 @@
                 .build();
         mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
-                "", 9258), getDefaultChannel());
+                "", 9258), getDefaultChannel(), false);
         mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 177c02d..f3eb4f8 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -165,7 +165,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel);
+        return new NotificationRecord(mContext, sbn, channel, true);
     }
     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
         return generateNotificationRecord(channel, null);
@@ -184,7 +184,7 @@
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel);
+        return new NotificationRecord(mContext, sbn, channel, true);
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 1c8ca84..66f3799 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,7 +21,6 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -61,6 +60,10 @@
     private final Context mMockContext = Mockito.mock(Context.class);
     @Mock PackageManager mPm;
 
+    // constants for targetSdk version. N is pre channels, O is post.
+    private final boolean N = false;
+    private final boolean O = true;
+
     private final String pkg = "com.android.server.notification";
     private final int uid = 9583;
     private final String pkg2 = "pkg2";
@@ -76,7 +79,6 @@
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
-    final ApplicationInfo legacy = new ApplicationInfo();
     final ApplicationInfo upgrade = new ApplicationInfo();
 
     private static final long[] CUSTOM_VIBRATION = new long[] {
@@ -100,17 +102,13 @@
                 InstrumentationRegistry.getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
 
-        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        try {
-            when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
-            when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
-        } catch (PackageManager.NameNotFoundException e) {}
+        when(mMockContext.getApplicationInfo()).thenReturn(upgrade);
     }
 
-    private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
-            boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
-        when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
+    private StatusBarNotification getNotification(boolean supportsChannels, boolean noisy,
+            boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights,
+            boolean defaultLights) {
         final Builder builder = new Builder(mMockContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -149,13 +147,13 @@
         }
 
         builder.setDefaults(defaults);
-        if (!preO) {
+        if (supportsChannels) {
             builder.setChannelId(channelId);
         }
 
 
         Notification n = builder.build();
-        if (preO) {
+        if (!supportsChannels) {
             return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
                     mUser, null, uid);
         } else {
@@ -172,11 +170,11 @@
     public void testSound_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -185,11 +183,11 @@
     public void testSound_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, custom sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -199,11 +197,11 @@
         defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -211,11 +209,11 @@
     @Test
     public void testSound_noSound_preUpgrade() throws Exception {
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(N, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(null, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -224,11 +222,11 @@
     public void testSound_default_upgradeUsesChannel() throws Exception {
         channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         // post upgrade, default sound.
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -237,11 +235,11 @@
     public void testVibration_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(N, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertNotNull(record.getVibration());
     }
 
@@ -249,11 +247,11 @@
     public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(N, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(CUSTOM_VIBRATION, record.getVibration());
     }
 
@@ -262,11 +260,11 @@
         defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(N, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
     }
 
@@ -274,20 +272,20 @@
     public void testVibration_custom_upgradeUsesChannel() throws Exception {
         channel.enableVibration(true);
         // post upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+        StatusBarNotification sbn = getNotification(O, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
         assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
     }
 
     @Test
     public void testImportance_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
@@ -295,11 +293,11 @@
     public void testImportance_locked_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
     }
 
@@ -307,39 +305,39 @@
     public void testImportance_locked_unspecified_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record =  new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
     @Test
     public void testImportance_upgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
         assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
     }
 
     @Test
     public void testLights_preUpgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertNull(record.getLight());
     }
 
 
     @Test
     public void testLights_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertEquals(CUSTOM_LIGHT, record.getLight());
     }
 
@@ -347,11 +345,11 @@
     public void testLights_locked_preUpgrade() throws Exception {
         defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
-        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(N, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
         assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
     }
 
@@ -366,10 +364,10 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 defaultLightColor, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, true /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
         assertEquals(expected, record.getLight());
     }
 
@@ -382,19 +380,19 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 Color.BLUE, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
         assertEquals(expected, record.getLight());
     }
 
     @Test
     public void testLights_upgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+        StatusBarNotification sbn = getNotification(O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, O);
         assertNull(record.getLight());
     }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index ce899e3..e2428b9 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -124,7 +124,7 @@
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getDefaultChannel(), false);
 
         mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("B")
@@ -134,7 +134,7 @@
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getDefaultChannel(), false);
 
         mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("C")
@@ -142,7 +142,7 @@
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getDefaultChannel(), false);
 
         mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("D")
@@ -150,7 +150,7 @@
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getDefaultChannel(), false);
 
         mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("E")
@@ -159,7 +159,7 @@
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getDefaultChannel(), false);
 
         mAudioAttributes = new AudioAttributes.Builder()
                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -314,8 +314,6 @@
         assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
         compareChannels(channel2,
                 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
-        assertNotNull(mHelper.getNotificationChannel(
-                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false));
 
         List<NotificationChannelGroup> actualGroups =
                 mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
@@ -375,18 +373,13 @@
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
-        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
+        assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
         assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
     }
 
     @Test
     public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
-        NotificationChannel channel1 =
-                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_DEFAULT);
-
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
         loadStreamXml(baos);
@@ -401,16 +394,12 @@
 
     @Test
     public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
-        NotificationChannel channel1 =
-                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
         loadStreamXml(baos);
@@ -445,12 +434,9 @@
                 | NotificationChannel.USER_LOCKED_VISIBILITY,
                 updated1.getUserLockedFields());
 
-        // STOPSHIP - this should be reversed after the STOPSHIP is removed in the tested code.
         // No Default Channel created for updated packages
-        // assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
-        //         NotificationChannel.DEFAULT_CHANNEL_ID, false));
-        assertTrue(mHelper.getNotificationChannel(UPDATED_PKG, UID2,
-                NotificationChannel.DEFAULT_CHANNEL_ID, false) != null);
+        assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
@@ -466,12 +452,9 @@
         when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
         loadStreamXml(baos);
 
-        // STOPSHIP - this should be reversed after the STOPSHIP is removed in the tested code.
         // Default Channel should be gone.
-        // assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
-        //         NotificationChannel.DEFAULT_CHANNEL_ID, false));
-        assertTrue(mHelper.getNotificationChannel(UPDATED_PKG, UID2,
-                NotificationChannel.DEFAULT_CHANNEL_ID, false) != null);
+        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
@@ -713,20 +696,14 @@
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
                 mHelper.getNotificationChannels(PKG, UID, false).getList();
-        assertEquals(2, channels.size());   // Default channel + non-deleted channel
-        for (NotificationChannel nc : channels) {
-            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
-                compareChannels(channel2, nc);
-            }
-        }
+        assertEquals(1, channels.size());
+        compareChannels(channel2, channels.get(0));
 
         // Returns deleted channels too
         channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
-        assertEquals(3, channels.size());               // Includes default channel
+        assertEquals(2, channels.size());
         for (NotificationChannel nc : channels) {
-            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
-                compareChannels(channelMap.get(nc.getId()), nc);
-            }
+            compareChannels(channelMap.get(nc.getId()), nc);
         }
     }
 
@@ -824,8 +801,8 @@
 
         mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
 
-        // Only default channel remains
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        // No channels remain
+        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
     }
 
     @Test
@@ -874,13 +851,32 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        // since this is a pre upgrade app, clearing data should restore the default channel
+        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID,
+                mHelper.getNotificationChannels(PKG, UID, true).getList().get(0).getId());
 
         // Not deleted
         mHelper.createNotificationChannel(PKG, UID, channel1, true);
-
         mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
-        assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
+    }
+
+    @Test
+    public void testOnPackageChanged_packageRemoval_updatedPackage() throws Exception {
+        // Deleted
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
+        mHelper.onPackagesChanged(
+                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+        assertEquals(0, mHelper.getNotificationChannels(UPDATED_PKG, UID2, true).getList().size());
+
+        // Not deleted
+        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
+        mHelper.onPackagesChanged(
+                false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+        assertEquals(1, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
     }
 
     @Test
@@ -901,7 +897,23 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
+        // default channel restored
+        assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
+        assertNull(mHelper.getNotificationChannelGroups(PKG, UID, true).getList().get(0).getId());
+    }
+
+    @Test
+    public void testOnPackageChanged_packageRemoval_groups_upgraded() throws Exception {
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg, true);
+        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
+        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg2, true);
+
+        mHelper.onPackagesChanged(
+                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
+
+        assertEquals(0,
+                mHelper.getNotificationChannelGroups(UPDATED_PKG, UID2, true).getList().size());
     }
 
     @Test
@@ -975,9 +987,8 @@
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
-                assertEquals(2, group.getChannels().size()); // misc channel too
-                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
-                        || channel3.getId().equals(group.getChannels().get(1).getId()));
+                assertEquals(1, group.getChannels().size());
+                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()));
             } else if (group.getId().equals(ncg.getId())) {
                 assertEquals(2, group.getChannels().size());
                 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
@@ -1011,12 +1022,8 @@
         List<NotificationChannelGroup> actual =
                 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
 
-        assertEquals(2, actual.size());
-        for (NotificationChannelGroup group : actual) {
-            if (Objects.equals(group.getId(), ncg.getId())) {
-                assertEquals(1, group.getChannels().size());
-            }
-        }
+        assertEquals(1, actual.size());
+        assertEquals(1, actual.get(0).getChannels().size());
     }
 
     @Test
@@ -1067,7 +1074,7 @@
         for (int i = 0; i < numPackages; i++) {
             JSONObject object = actual.getJSONObject(i);
             assertTrue(expectedChannels.containsKey(object.get("packageName")));
-            assertEquals(expectedChannels.get(object.get("packageName")).intValue() + 1,
+            assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
                     object.getInt("channelCount"));
         }
     }
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index bc25860..b1cb4d7 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -312,7 +312,7 @@
                 TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
         return new NotificationRecord(getContext(), new StatusBarNotification(
                 pkg, pkg, id, tag, 0, 0, n, user, null,
-                System.currentTimeMillis()), notificationChannel);
+                System.currentTimeMillis()), notificationChannel, true);
     }
 
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cc682c4..fa72416 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -18,6 +18,7 @@
         package="com.android.frameworks.servicestests">
 
     <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
     <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
new file mode 100644
index 0000000..9a9c243
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.NightDisplayController.LocalTime;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.display.DisplayTransformManager;
+import com.android.server.display.NightDisplayService;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.Calendar;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.Mockito.doReturn;
+
+@RunWith(AndroidJUnit4.class)
+public class NightDisplayServiceTest {
+
+    private Context mContext;
+    private int mUserId;
+
+    private TwilightManager mTwilightManager;
+
+    private NightDisplayController mNightDisplayController;
+    private NightDisplayService mNightDisplayService;
+
+    @Before
+    public void setUp() {
+        mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+        mUserId = ActivityManager.getCurrentUser();
+
+        doReturn(mContext).when(mContext).getApplicationContext();
+
+        final MockContentResolver cr = new MockContentResolver(mContext);
+        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        doReturn(cr).when(mContext).getContentResolver();
+
+        final AlarmManager am = Mockito.mock(AlarmManager.class);
+        doReturn(am).when(mContext).getSystemService(Context.ALARM_SERVICE);
+
+        final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
+        LocalServices.addService(DisplayTransformManager.class, dtm);
+
+        mTwilightManager = Mockito.mock(TwilightManager.class);
+        LocalServices.addService(TwilightManager.class, mTwilightManager);
+
+        mNightDisplayController = new NightDisplayController(mContext, mUserId);
+        mNightDisplayService = new NightDisplayService(mContext);
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(DisplayTransformManager.class);
+        LocalServices.removeServiceForTest(TwilightManager.class);
+
+        mNightDisplayService = null;
+        mNightDisplayController = null;
+
+        mTwilightManager = null;
+
+        mUserId = UserHandle.USER_NULL;
+        mContext = null;
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOffDuringNight_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOffInFuture_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOnAfterNight_turnsOn() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOnDuringNight_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedAfterNight_ifOnInFuture_turnsOff() {
+        setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOffAfterNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOffDuringNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOffInPast_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOnAfterNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOnDuringNight_turnsOff() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedBeforeNight_ifOnInPast_turnsOn() {
+        setAutoModeCustom(60 /* startTimeOffset */, 120 /* endTimeOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOffAfterNight_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOffBeforeNight_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOffDuringNightInPast_turnsOff() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOnAfterNight_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOnBeforeNight_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void customSchedule_whenStartedDuringNight_ifOnDuringNightInPast_turnsOn() {
+        setAutoModeCustom(-60 /* startTimeOffset */, 60 /* endTimeOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOffInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedAfterNight_ifOnInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOffInPast_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOnAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedBeforeNight_ifOnInPast_turnsOn() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOffAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOffBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOffDuringNightInPast_turnsOff() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOnBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenStartedDuringNight_ifOnDuringNightInPast_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        startService();
+        assertActivated(true /* activated */);
+    }
+
+    /**
+     * Convenience for making a {@link LocalTime} instance with an offset relative to now.
+     *
+     * @param offsetMinutes the offset relative to now (in minutes)
+     * @return the LocalTime instance
+     */
+    private LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
+        final Calendar c = Calendar.getInstance();
+        c.add(Calendar.MINUTE, offsetMinutes);
+        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+    }
+
+    /**
+     * Configures Night display to use a custom schedule.
+     *
+     * @param startTimeOffset the offset relative to now to activate Night display (in minutes)
+     * @param endTimeOffset   the offset relative to now to deactivate Night display (in minutes)
+     */
+    private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
+        mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_CUSTOM);
+        mNightDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
+        mNightDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
+    }
+
+    /**
+     * Configures Night display to use the twilight schedule.
+     *
+     * @param sunsetOffset  the offset relative to now for sunset (in minutes)
+     * @param sunriseOffset the offset relative to now for sunrise (in minutes)
+     */
+    private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
+        mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_TWILIGHT);
+
+        final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
+        final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
+
+        final Calendar now = Calendar.getInstance();
+        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
+        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+        if (sunsetMillis < sunriseMillis) {
+            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+        } else {
+            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+        }
+
+        final TwilightState state = new TwilightState(sunriseMillis, sunsetMillis);
+        doReturn(state).when(mTwilightManager).getLastTwilightState();
+    }
+
+    /**
+     * Configures the Night display activated state.
+     *
+     * @param activated               {@code true} if Night display should be activated
+     * @param lastActivatedTimeOffset the offset relative to now to record that Night display was
+                                      activated (in minutes)
+     */
+    private void setActivated(boolean activated, int lastActivatedTimeOffset) {
+        mNightDisplayController.setActivated(activated);
+
+        final Calendar c = Calendar.getInstance();
+        c.add(Calendar.MINUTE, lastActivatedTimeOffset);
+        Secure.putLongForUser(mContext.getContentResolver(),
+                Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId);
+    }
+
+    /**
+     * Convenience method to start {@link #mNightDisplayService}.
+     */
+    private void startService() {
+        Secure.putIntForUser(mContext.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, mUserId);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mNightDisplayService.onStart();
+                mNightDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+                mNightDisplayService.onStartUser(mUserId);
+            }
+        });
+    }
+
+    /**
+     * Convenience method for asserting whether Night display should be activated.
+     *
+     * @param activated the expected activated state of Night display
+     */
+    private void assertActivated(boolean activated) {
+        assertWithMessage("Invalid Night display activated state")
+                .that(mNightDisplayController.isActivated())
+                .isEqualTo(activated);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 2b4d9fb..f253632 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.TaskSnapshotController.*;
 import static junit.framework.Assert.assertEquals;
@@ -76,12 +77,19 @@
     public void testGetSnapshotMode() throws Exception {
         final WindowState disabledWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
-        disabledWindow.mAppToken.setDisablePreviewSnapshots(true);
+        disabledWindow.mAppToken.setDisablePreviewScreenshots(true);
         assertEquals(SNAPSHOT_MODE_APP_THEME,
                 sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
+
         final WindowState normalWindow = createWindow(null,
                 FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow");
         assertEquals(SNAPSHOT_MODE_REAL,
                 sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
+
+        final WindowState secureWindow = createWindow(null,
+                FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow");
+        secureWindow.mAttrs.flags |= FLAG_SECURE;
+        assertEquals(SNAPSHOT_MODE_APP_THEME,
+                sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 717ddf2..e2868d7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -171,11 +171,25 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10);
+        mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+                mockCanvas, new Rect(0, 0, 50, 100), 10);
         verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
     }
 
     @Test
+    public void testDrawStatusBarBackground_nullFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+                mockCanvas, null, 10);
+        verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
     public void testDrawStatusBarBackground_nope() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
@@ -183,7 +197,8 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10);
+        mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
+                mockCanvas, new Rect(0, 0, 100, 100), 10);
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
@@ -196,7 +211,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
+        mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
     }
 
@@ -209,7 +224,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
+        mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
     }
 
@@ -222,7 +237,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mSurface.drawNavigationBarBackground(mockCanvas);
+        mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
     }
 }
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index ff632a5..b133a44 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -660,10 +660,10 @@
         @Deprecated
         public int tx_rate;
 
-        /** average transmit rate. Unit (100kbps). */
+        /** average transmit rate. Unit (kbps). */
         public int txRate;
 
-        /** average receiving rate Unit (100kbps). */
+        /** average receiving rate Unit (kbps). */
         public int rxRate;
 
        /**
@@ -673,7 +673,7 @@
         @Deprecated
         public long rtt_ns;
 
-        /** average round trip time in 0.1 nano second. */
+        /** average round trip time in picoseconds. */
         public long rtt;
 
         /**
@@ -683,7 +683,7 @@
         @Deprecated
         public long rtt_sd_ns;
 
-        /** standard deviation of RTT in 0.1 ns. */
+        /** standard deviation of RTT in picoseconds. */
         public long rttStandardDeviation;
 
         /**
@@ -693,7 +693,7 @@
         @Deprecated
         public long rtt_spread_ns;
 
-        /** spread (i.e. max - min) RTT in 0.1 ns. */
+        /** spread (i.e. max - min) RTT in picoseconds. */
         public long rttSpread;
 
         /**