Merge "Import translations. DO NOT MERGE" into oc-dev
diff --git a/Android.mk b/Android.mk
index e58f306..8f99bc0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -322,7 +322,6 @@
 	core/java/android/service/chooser/IChooserTargetResult.aidl \
 	core/java/android/service/resolver/IResolverRankerService.aidl \
 	core/java/android/service/resolver/IResolverRankerResult.aidl \
-	core/java/android/text/ITextClassificationService.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index a5b37f3..8fd8043 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -370,15 +370,6 @@
         "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
 
     /**
-     * Key to set default visibility for applications targeting API level
-     * {@link android.os.Build.VERSION_CODES#O} or above and don't have the same signature as
-     * authenticator See {@link #getAccountVisibility}. If the value was not set by authenticator
-     * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
-     */
-    public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
-        "android:accounts:key_legacy_visible";
-
-    /**
      * Key to set visibility for applications which satisfy one of the following conditions:
      * <ul>
      * <li>Target API level below {@link android.os.Build.VERSION_CODES#O} and have
@@ -394,6 +385,14 @@
      * See {@link #getAccountVisibility}. If the value was not set by authenticator
      * {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used.
      */
+    public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
+        "android:accounts:key_legacy_visible";
+
+    /**
+     * Key to set default visibility for applications which don't satisfy conditions in
+     * {@link PACKAGE_NAME_KEY_LEGACY_VISIBLE}. If the value was not set by authenticator
+     * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
+     */
     public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE =
             "android:accounts:key_legacy_not_visible";
 
@@ -608,14 +607,17 @@
     }
 
     /**
-     * Returns the accounts visible to the specified package, in an environment where some apps are
+     * Returns the accounts visible to the specified package in an environment where some apps are
      * not authorized to view all accounts. This method can only be called by system apps and
-     * authenticators managing the type
+     * authenticators managing the type.
+     * Beginning API level {@link android.os.Build.VERSION_CODES#O} it also return accounts
+     * which user can make visible to the application (see {@link VISIBILITY_USER_MANAGED_VISIBLE}).
      *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @param packageName The package name of the app for which the accounts are to be returned
      * @return An array of {@link Account}, one per matching account. Empty (never null) if no
-     *         accounts of the specified type have been added.
+     *         accounts of the specified type can be accessed by the package.
+     *
      */
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -644,7 +646,10 @@
      *
      * <p>
      * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
-     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * of accounts made visible to it by user
+     * (see {@link #newChooseAccountIntent(Account, List, String[], String,
+     * String, String[], Bundle)}) or AbstractAcccountAuthenticator
+     * using {@link setAccountVisibility}.
      * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
      *
      * <p>
@@ -787,7 +792,10 @@
      *
      * <p>
      * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
-     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * of accounts made visible to it by user
+     * (see {@link #newChooseAccountIntent(Account, List, String[], String,
+     * String, String[], Bundle)}) or AbstractAcccountAuthenticator
+     * using {@link setAccountVisibility}.
      * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
      *
      * <p>
@@ -869,7 +877,7 @@
     }
 
     /**
-     * Adds an account directly to the AccountManager. Additionally it specifies Account visiblity
+     * Adds an account directly to the AccountManager. Additionally it specifies Account visibility
      * for given list of packages.
      * <p>
      * Normally used by sign-up wizards associated with authenticators, not directly by
@@ -2663,8 +2671,8 @@
      *
      * <p>
      * This method gets a list of the accounts matching specific type and feature set which are
-     * visible to the caller or for which user can grant access (see {@link #getAccountsByType} for
-     * details); if there is exactly one already visible account, it is used; if there are some
+     * visible to the caller (see {@link #getAccountsByType} for details);
+     * if there is exactly one already visible account, it is used; if there are some
      * accounts for which user grant visibility, the user is prompted to pick one; if there are
      * none, the user is prompted to add one. Finally, an auth token is acquired for the chosen
      * account.
@@ -2735,6 +2743,9 @@
      * <p>
      * On success the activity returns a Bundle with the account name and type specified using
      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
+     * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
+     * (see {@link setAccountVisibility}) and will be returned to it in consequent
+     * {@link #getAccountsByType}) calls.
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
@@ -2787,6 +2798,9 @@
      * <p>
      * On success the activity returns a Bundle with the account name and type specified using
      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
+     * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
+     * (see {@link setAccountVisibility}) and will be returned to it in consequent
+     * {@link #getAccountsByType}) calls.
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index abe5dc3..37c287e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -25,6 +25,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 import android.annotation.CallSuper;
@@ -3147,19 +3148,6 @@
     }
 
     /**
-     * Called before {@link #onAttachedToWindow}.
-     *
-     * @hide
-     */
-    @CallSuper
-    public void onBeforeAttachedToWindow() {
-        if (mAutoFillResetNeeded) {
-            getAutofillManager().onAttachedToWindow(
-                    getWindow().getDecorView().getRootView().getWindowToken());
-        }
-    }
-
-    /**
      * Called when the main window associated with the activity has been
      * attached to the window manager.
      * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
@@ -7471,45 +7459,62 @@
     }
 
     /** @hide */
+    @NonNull public View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds) {
+        final View[] views = new View[viewIds.length];
+        final ArrayList<ViewRootImpl> roots =
+                WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
+
+        for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+            final View rootView = roots.get(rootNum).getView();
+
+            if (rootView != null) {
+                for (int viewNum = 0; viewNum < viewIds.length; viewNum++) {
+                    if (views[viewNum] == null) {
+                        views[viewNum] = rootView.findViewByAccessibilityIdTraversal(
+                                viewIds[viewNum]);
+                    }
+                }
+            }
+        }
+
+        return views;
+    }
+
+    /** @hide */
     @Override
-    public boolean getViewVisibility(int viewId) {
-        Window window = getWindow();
-        if (window == null) {
-            Log.i(TAG, "no window");
-            return false;
-        }
+    @NonNull public boolean[] getViewVisibility(@NonNull int[] viewIds) {
+        final boolean[] isVisible = new boolean[viewIds.length];
+        final View views[] = findViewsByAccessibilityIdTraversal(viewIds);
 
-        View decorView = window.peekDecorView();
-        if (decorView == null) {
-            Log.i(TAG, "no decorView");
-            return false;
-        }
-
-        View view = decorView.findViewByAccessibilityIdTraversal(viewId);
-        if (view == null) {
-            Log.i(TAG, "cannot find view");
-            return false;
-        }
-
-        // Check if the view is visible by checking all parents
-        while (view != null) {
-            if (view == decorView) {
-                break;
+        for (int i = 0; i < viewIds.length; i++) {
+            View view = views[i];
+            if (view == null) {
+                isVisible[i] = false;
+                continue;
             }
 
-            if (view.getVisibility() != View.VISIBLE) {
-                Log.i(TAG, view + " is not visible");
-                return false;
-            }
+            isVisible[i] = true;
 
-            if (view.getParent() instanceof View) {
-                view = (View) view.getParent();
-            } else {
-                break;
+            // Check if the view is visible by checking all parents
+            while (true) {
+                if (view instanceof DecorView && view.getViewRootImpl() == view.getParent()) {
+                    break;
+                }
+
+                if (view.getVisibility() != View.VISIBLE) {
+                    isVisible[i] = false;
+                    break;
+                }
+
+                if (view.getParent() instanceof View) {
+                    view = (View) view.getParent();
+                } else {
+                    break;
+                }
             }
         }
 
-        return true;
+        return isVisible;
     }
 
     /** @hide */
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 21a7ca7..7d4d70d 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -570,8 +570,10 @@
             // Find the location in the view's parent
             ViewGroup parent = (ViewGroup) view.getParent();
             Matrix matrix = new Matrix();
-            parent.transformMatrixToLocal(matrix);
-            matrix.postTranslate(parent.getScrollX(), parent.getScrollY());
+            if (parent != null) {
+                parent.transformMatrixToLocal(matrix);
+                matrix.postTranslate(parent.getScrollX(), parent.getScrollY());
+            }
             mSharedElementParentMatrices.add(matrix);
         }
     }
@@ -861,15 +863,17 @@
             Matrix tempMatrix = new Matrix();
             for (int i = 0; i < numSharedElements; i++) {
                 View view = mSharedElements.get(i);
-                tempMatrix.reset();
-                mSharedElementParentMatrices.get(i).invert(tempMatrix);
-                GhostView.addGhost(view, decor, tempMatrix);
-                ViewGroup parent = (ViewGroup) view.getParent();
-                if (moveWithParent && !isInTransitionGroup(parent, decor)) {
-                    GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
-                    parent.getViewTreeObserver().addOnPreDrawListener(listener);
-                    parent.addOnAttachStateChangeListener(listener);
-                    mGhostViewListeners.add(listener);
+                if (view.isAttachedToWindow()) {
+                    tempMatrix.reset();
+                    mSharedElementParentMatrices.get(i).invert(tempMatrix);
+                    GhostView.addGhost(view, decor, tempMatrix);
+                    ViewGroup parent = (ViewGroup) view.getParent();
+                    if (moveWithParent && !isInTransitionGroup(parent, decor)) {
+                        GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
+                        parent.getViewTreeObserver().addOnPreDrawListener(listener);
+                        parent.addOnAttachStateChangeListener(listener);
+                        mGhostViewListeners.add(listener);
+                    }
                 }
             }
         }
@@ -1065,7 +1069,7 @@
         @Override
         public boolean onPreDraw() {
             GhostView ghostView = GhostView.getGhost(mView);
-            if (ghostView == null) {
+            if (ghostView == null || !mView.isAttachedToWindow()) {
                 removeListener();
             } else {
                 GhostView.calculateMatrix(mView, mDecor, mMatrix);
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 28704e6..995d98a 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -71,11 +71,12 @@
     public static final int TYPE_INSTALL_WINDOWED = 2;
 
     /**
-     * Incoming system updates (except for security updates) will be blocked for 30 days, after
-     * which the policy will no longer be effective and the system will revert back to its normal
-     * behavior as if no policy were set.
-     * <b>Note:</b> security updates (e.g. monthly security patches) will <i>not</i> be affected by
-     * this policy.
+     * Incoming system updates (except for security updates) will be blocked for a maximum of 30
+     * days, after which the policy will no longer be effective and the system will revert back to
+     * its normal behavior as if no policy were set.
+     *
+     * <p><b>Note:</b> security updates (e.g. monthly security patches) may <i>not</i> be affected
+     * by this policy, depending on the policy set by the device manufacturer and carrier.
      *
      * <p>After this policy expires, resetting it to any policy other than
      * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bf7af20..10594af 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2891,6 +2891,7 @@
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
             TEXT_SERVICES_MANAGER_SERVICE,
+            TEXT_CLASSIFICATION_SERVICE,
             APPWIDGET_SERVICE,
             //@hide: VOICE_INTERACTION_MANAGER_SERVICE,
             //@hide: BACKUP_SERVICE,
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5264cd7..e127ca3 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -952,4 +952,12 @@
     public Handler getMainThreadHandler() {
         return mBase.getMainThreadHandler();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int getNextAccessibilityId() {
+        return mBase.getNextAccessibilityId();
+    }
 }
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 211d54d..63eedf5 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -107,7 +107,8 @@
     /**
      * Create a request suitable for zero shutter lag still capture. This means
      * means maximizing image quality without compromising preview frame rate.
-     * AE/AWB/AF should be on auto mode.
+     * AE/AWB/AF should be on auto mode. This is intended for application-operated ZSL. For
+     * device-operated ZSL, use {@link CaptureRequest#CONTROL_ENABLE_ZSL} if available.
      * This template is guaranteed to be supported on camera devices that support the
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING PRIVATE_REPROCESSING}
      * capability or the
@@ -115,6 +116,7 @@
      * capability.
      *
      * @see #createCaptureRequest
+     * @see CaptureRequest#CONTROL_ENABLE_ZSL
      */
     public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 279d73d..c41fc02 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1669,6 +1669,7 @@
      * <code>false</code> if present.</p>
      * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
      * capture templates is always <code>false</code> if present.</p>
+     * <p>For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index aedfc4b..6d80c20 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2174,6 +2174,7 @@
      * <code>false</code> if present.</p>
      * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
      * capture templates is always <code>false</code> if present.</p>
+     * <p>For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 37c153f..b5fd116 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -521,6 +521,7 @@
         public abstract Timer getForegroundActivityTimer();
         public abstract Timer getBluetoothScanTimer();
         public abstract Timer getBluetoothScanBackgroundTimer();
+        public abstract Counter getBluetoothScanResultCounter();
 
         // Note: the following times are disjoint.  They can be added together to find the
         // total time a uid has had any processes running at all.
@@ -3370,8 +3371,10 @@
                     final long actualTime = bleTimer.getTotalDurationMsLocked(rawRealtimeMs);
                     final long actualTimeBg = bleTimerBg != null ?
                             bleTimerBg.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+                    final int resultCount = u.getBluetoothScanResultCounter() != null ?
+                            u.getBluetoothScanResultCounter().getCountLocked(which) : 0;
                     dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA, totalTime, count,
-                            countBg, actualTime, actualTimeBg);
+                            countBg, actualTime, actualTimeBg, resultCount);
                 }
             }
 
@@ -4523,6 +4526,8 @@
                     final long actualTimeMs = bleTimer.getTotalDurationMsLocked(rawRealtimeMs);
                     final long actualTimeMsBg = bleTimerBg != null ?
                             bleTimerBg.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+                    final int resultCount = u.getBluetoothScanResultCounter() != null ?
+                            u.getBluetoothScanResultCounter().getCountLocked(which) : 0;
 
                     sb.setLength(0);
                     sb.append(prefix);
@@ -4547,6 +4552,8 @@
                         sb.append(countBg);
                         sb.append(" times)");
                     }
+                    sb.append("; Results count ");
+                    sb.append(resultCount);
                     pw.println(sb.toString());
                     uidActivity = true;
                 }
diff --git a/core/java/android/text/ITextClassificationService.aidl b/core/java/android/text/ITextClassificationService.aidl
deleted file mode 100644
index a73dbf0..0000000
--- a/core/java/android/text/ITextClassificationService.aidl
+++ /dev/null
@@ -1,33 +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 android.text;
-
-import android.os.ParcelFileDescriptor;
-
-/**
- * Interface to the text classification service, which grants access to the text classification
- * LSTM model file.
- * {@hide}
- */
-interface ITextClassificationService {
-
-    /**
-     * Request a file descriptor with read-only access to the LSTM model file.
-     * This file descriptor should be closed after the client is done with it.
-     */
-    ParcelFileDescriptor getModelFileFd();
-}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f539752..2ade9b5 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -678,6 +678,7 @@
                     mIsCreating = false;
                     if (mSurfaceControl != null && !mSurfaceCreated) {
                         mSurfaceControl.destroy();
+                        mSurface.release();
                         mSurfaceControl = null;
                     }
                 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0af49ed..6ee6d63 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7304,7 +7304,7 @@
      * fills in all data that can be inferred from the view itself.
      */
     public void onProvideStructure(ViewStructure structure) {
-        onProvideStructureForAssistOrAutofill(structure, false);
+        onProvideStructureForAssistOrAutofill(structure, false, 0);
     }
 
     /**
@@ -7318,6 +7318,9 @@
      *   <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
      * {@link ViewStructure#setAutofillOptions(CharSequence[])},
      * or {@link ViewStructure#setWebDomain(String)}.
+     *   <li> The {@code left} and {@code top} values set in
+     * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
+     * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
      * </ul>
      *
      * @param structure Fill in with structured view data. The default implementation
@@ -7326,12 +7329,12 @@
      *
      * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      */
-    public void onProvideAutofillStructure(ViewStructure structure, int flags) {
-        onProvideStructureForAssistOrAutofill(structure, true);
+    public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) {
+        onProvideStructureForAssistOrAutofill(structure, true, flags);
     }
 
     private void onProvideStructureForAssistOrAutofill(ViewStructure structure,
-            boolean forAutofill) {
+            boolean forAutofill, @AutofillFlags int flags) {
         final int id = mID;
         if (id != NO_ID && !isViewIdGenerated(id)) {
             String pkg, type, entry;
@@ -7359,7 +7362,31 @@
             }
         }
 
-        structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
+        int ignoredParentLeft = 0;
+        int ignoredParentTop = 0;
+        if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
+            View parentGroup = null;
+
+            ViewParent viewParent = getParent();
+            if (viewParent instanceof View) {
+                parentGroup = (View) viewParent;
+            }
+
+            while (parentGroup != null && !parentGroup.isImportantForAutofill()) {
+                ignoredParentLeft += parentGroup.mLeft;
+                ignoredParentTop += parentGroup.mTop;
+
+                viewParent = parentGroup.getParent();
+                if (viewParent instanceof View) {
+                    parentGroup = (View) viewParent;
+                } else {
+                    break;
+                }
+            }
+        }
+
+        structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY,
+                mRight - mLeft, mBottom - mTop);
         if (!forAutofill) {
             if (!hasIdentityMatrix()) {
                 structure.setTransformation(getMatrix());
@@ -7445,10 +7472,15 @@
      * <li>Call {@link AutofillManager#cancel()} ()} when the autofill context
      * of the view structure changed and you want the current autofill interaction if such
      * to be cancelled.
+     * <li> The {@code left} and {@code top} values set in
+     * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
+     * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
      * </ol>
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (currently {@code 0}).
+     * @param flags optional flags.
+     *
+     * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      */
     public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
     }
@@ -7706,7 +7738,8 @@
     }
 
     private boolean isAutofillable() {
-        return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill();
+        return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill()
+                && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID;
     }
 
     private void populateVirtualStructure(ViewStructure structure,
@@ -7771,7 +7804,7 @@
      * {@link #onProvideVirtualStructure}.
      */
     public void dispatchProvideStructure(ViewStructure structure) {
-        dispatchProvideStructureForAssistOrAutofill(structure, false);
+        dispatchProvideStructureForAssistOrAutofill(structure, false, 0);
     }
 
     /**
@@ -7804,16 +7837,15 @@
      */
     public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure,
             @AutofillFlags int flags) {
-        dispatchProvideStructureForAssistOrAutofill(structure, true);
+        dispatchProvideStructureForAssistOrAutofill(structure, true, flags);
     }
 
     private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure,
-            boolean forAutofill) {
+            boolean forAutofill, @AutofillFlags int flags) {
         if (forAutofill) {
             structure.setAutofillId(getAutofillId());
-            // NOTE: flags are not currently supported, hence 0
-            onProvideAutofillStructure(structure, 0);
-            onProvideAutofillVirtualStructure(structure, 0);
+            onProvideAutofillStructure(structure, flags);
+            onProvideAutofillVirtualStructure(structure, flags);
         } else if (!isAssistBlocked()) {
             onProvideStructure(structure);
             onProvideVirtualStructure(structure);
@@ -20430,9 +20462,10 @@
     @Nullable private Drawable getAutofilledDrawable() {
         // Lazily load the isAutofilled drawable.
         if (mAttachInfo.mAutofilledDrawable == null) {
-            TypedArray a = mContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR);
+            Context rootContext = getRootView().getContext();
+            TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR);
             int attributeResourceId = a.getResourceId(0, 0);
-            mAttachInfo.mAutofilledDrawable = mContext.getDrawable(attributeResourceId);
+            mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId);
             a.recycle();
         }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a432d30..6dd8ecf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -480,13 +480,6 @@
         public void onWindowFocusChanged(boolean hasFocus);
 
         /**
-         * @hide
-         */
-        default void onBeforeAttachedToWindow() {
-            // empty
-        }
-
-        /**
          * Called when the window has been attached to the window manager.
          * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
          * for more information.
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 7018529..02c8945 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -109,11 +109,6 @@
     }
 
     @Override
-    public void onBeforeAttachedToWindow() {
-        mWrapped.onBeforeAttachedToWindow();
-    }
-
-    @Override
     public void onAttachedToWindow() {
         mWrapped.onAttachedToWindow();
     }
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 143c49a..604e985 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -309,6 +309,13 @@
 
                 final int oldChildCount = oldInfo.getChildCount();
                 for (int i = 0; i < oldChildCount; i++) {
+                    if (nodes.get(sourceId) == null) {
+                        // We've removed (and thus recycled) this node because it was its own
+                        // ancestor (the app gave us bad data), we can't continue using it.
+                        // Clear the cache for this window and give up on adding the node.
+                        clearNodesForWindowLocked(windowId);
+                        return;
+                    }
                     final long oldChildId = oldInfo.getChildId(i);
                     // If the child is no longer present, remove the sub-tree.
                     if (newChildrenIds == null || newChildrenIds.indexOf(oldChildId) < 0) {
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index f8a13a3..79c81b2 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -630,7 +630,8 @@
     public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
 
     /**
-     * Represents the event of scrolling a view.
+     * Represents the event of scrolling a view. This event type is generally not sent directly.
+     * @see View#onScrollChanged(int, int, int, int)
      */
     public static final int TYPE_VIEW_SCROLLED = 0x00001000;
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index d0133ed..c7151db 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -28,7 +28,6 @@
 import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.service.autofill.AutofillService;
@@ -38,7 +37,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
-import android.view.WindowManagerGlobal;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -47,6 +45,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -188,11 +187,11 @@
         boolean autofillCallbackRequestHideFillUi();
 
         /**
-         * Checks if the view is currently attached and visible.
+         * Checks if views are currently attached and visible.
          *
-         * @return {@code true} iff the view is attached or visible
+         * @return And array with {@code true} iff the view is attached or visible
          */
-        boolean getViewVisibility(int viewId);
+        @NonNull boolean[] getViewVisibility(@NonNull int[] viewId);
 
         /**
          * Checks is the client is currently visible as understood by autofill.
@@ -200,6 +199,15 @@
          * @return {@code true} if the client is currently visible
          */
         boolean isVisibleForAutofill();
+
+        /**
+         * Find views by traversing the hierarchies of the client.
+         *
+         * @param viewIds The accessibility ids of the views to find
+         *
+         * @return And array containing the views, or {@code null} if not found
+         */
+        @NonNull View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds);
     }
 
     /**
@@ -259,30 +267,6 @@
     }
 
     /**
-     * Set window future popup windows should be attached to.
-     *
-     * @param windowToken The window the popup windows should be attached to
-     *
-     * {@hide}
-     */
-    public void onAttachedToWindow(@NonNull IBinder windowToken) {
-        if (!hasAutofillFeature()) {
-            return;
-        }
-        synchronized (mLock) {
-            if (mSessionId == NO_SESSION) {
-                return;
-            }
-
-            try {
-                mService.setWindow(mSessionId, windowToken);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not attach window to session " + mSessionId);
-            }
-        }
-    }
-
-    /**
      * Called once the client becomes visible.
      *
      * @see AutofillClient#isVisibleForAutofill()
@@ -292,7 +276,7 @@
     public void onVisibleForAutofill() {
         synchronized (mLock) {
             if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) {
-                mTrackedViews.onVisibleForAutofill();
+                mTrackedViews.onVisibleForAutofillLocked();
             }
         }
     }
@@ -406,7 +390,7 @@
 
                 if (mSessionId == NO_SESSION) {
                     // Starts new session.
-                    startSessionLocked(id, view.getWindowToken(), null, value, flags);
+                    startSessionLocked(id, null, value, flags);
                 } else {
                     // Update focus on existing session.
                     updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
@@ -484,7 +468,7 @@
 
                 if (mSessionId == NO_SESSION) {
                     // Starts new session.
-                    startSessionLocked(id, view.getWindowToken(), bounds, null, flags);
+                    startSessionLocked(id, bounds, null, flags);
                 } else {
                     // Update focus on existing session.
                     updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
@@ -725,15 +709,15 @@
         return new AutofillId(parent.getAccessibilityViewId(), childId);
     }
 
-    private void startSessionLocked(@NonNull AutofillId id, @NonNull IBinder windowToken,
-            @NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
+    private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
+            @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
                     + ", flags=" + flags);
         }
 
         try {
-            mSessionId = mService.startSession(mContext.getActivityToken(), windowToken,
+            mSessionId = mService.startSession(mContext.getActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, mContext.getOpPackageName());
             final AutofillClient client = getClientLocked();
@@ -855,9 +839,9 @@
         }
     }
 
-    private void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id, int width,
-            int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
-        final View anchor = findAchorView(windowToken, id);
+    private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+            Rect anchorBounds, IAutofillWindowPresenter presenter) {
+        final View anchor = findView(id);
         if (anchor == null) {
             return;
         }
@@ -930,27 +914,27 @@
         }
     }
 
-    private void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
-            List<AutofillValue> values) {
+    private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
         synchronized (mLock) {
             if (sessionId != mSessionId) {
                 return;
             }
 
-            final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
-            if (root == null) {
+            final AutofillClient client = getClientLocked();
+            if (client == null) {
                 return;
             }
 
             final int itemCount = ids.size();
             int numApplied = 0;
             ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
+            final View[] views = client.findViewsByAccessibilityIdTraversal(getViewIds(ids));
 
             for (int i = 0; i < itemCount; i++) {
                 final AutofillId id = ids.get(i);
                 final AutofillValue value = values.get(i);
                 final int viewId = id.getViewId();
-                final View view = root.findViewByAccessibilityIdTraversal(viewId);
+                final View view = views[i];
                 if (view == null) {
                     Log.w(TAG, "autofill(): no View with id " + viewId);
                     continue;
@@ -1022,8 +1006,11 @@
         }
     }
 
-    private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
-        final View anchor = findAchorView(windowToken, id);
+    private void requestHideFillUi(int sessionId, AutofillId id) {
+        final View anchor = findView(id);
+        if (anchor == null) {
+            return;
+        }
 
         AutofillCallback callback = null;
         synchronized (mLock) {
@@ -1049,8 +1036,11 @@
         }
     }
 
-    private void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
-        final View anchor = findAchorView(windowToken, id);
+    private void notifyNoFillUi(int sessionId, AutofillId id) {
+        final View anchor = findView(id);
+        if (anchor == null) {
+            return;
+        }
 
         AutofillCallback callback = null;
         synchronized (mLock) {
@@ -1070,18 +1060,38 @@
         }
     }
 
-    private View findAchorView(IBinder windowToken, AutofillId id) {
-        final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
-        if (root == null) {
-            Log.w(TAG, "no window with token " + windowToken);
+    /**
+     * Get an array of viewIds from a List of {@link AutofillId}.
+     *
+     * @param autofillIds The autofill ids to convert
+     *
+     * @return The array of viewIds.
+     */
+    @NonNull private int[] getViewIds(@NonNull List<AutofillId> autofillIds) {
+        final int numIds = autofillIds.size();
+        final int[] viewIds = new int[numIds];
+        for (int i = 0; i < numIds; i++) {
+            viewIds[i] = autofillIds.get(i).getViewId();
+        }
+
+        return viewIds;
+    }
+
+    /**
+     * Find a single view by its id.
+     *
+     * @param autofillId The autofill id of the view
+     *
+     * @return The view or {@code null} if view was not found
+     */
+    private View findView(@NonNull AutofillId autofillId) {
+        final AutofillClient client = getClientLocked();
+
+        if (client == null) {
             return null;
         }
-        final View view = root.findViewByAccessibilityIdTraversal(id.getViewId());
-        if (view == null) {
-            Log.w(TAG, "no view with id " + id);
-            return null;
-        }
-        return view;
+
+        return client.findViewsByAccessibilityIdTraversal(new int[]{autofillId.getViewId()})[0];
     }
 
     /** @hide */
@@ -1160,22 +1170,26 @@
          *
          * @param trackedIds The views to be tracked
          */
-        TrackedViews(@NonNull List<AutofillId> trackedIds) {
+        TrackedViews(List<AutofillId> trackedIds) {
             mVisibleTrackedIds = null;
             mInvisibleTrackedIds = null;
 
             AutofillClient client = getClientLocked();
-            if (trackedIds != null) {
-                int numIds = trackedIds.size();
+            if (trackedIds != null && client != null) {
+                final boolean[] isVisible;
+
+                if (client.isVisibleForAutofill()) {
+                    isVisible = client.getViewVisibility(getViewIds(trackedIds));
+                } else {
+                    // All false
+                    isVisible = new boolean[trackedIds.size()];
+                }
+
+                final int numIds = trackedIds.size();
                 for (int i = 0; i < numIds; i++) {
-                    AutofillId id = trackedIds.get(i);
+                    final AutofillId id = trackedIds.get(i);
 
-                    boolean isVisible = true;
-                    if (client != null && client.isVisibleForAutofill()) {
-                        isVisible = client.getViewVisibility(id.getViewId());
-                    }
-
-                    if (isVisible) {
+                    if (isVisible[i]) {
                         mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id);
                     } else {
                         mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
@@ -1233,16 +1247,23 @@
          *
          * @see AutofillClient#isVisibleForAutofill()
          */
-        void onVisibleForAutofill() {
-            // The visibility of the views might have changed while the client was not started,
+        void onVisibleForAutofillLocked() {
+            // The visibility of the views might have changed while the client was not be visible,
             // hence update the visibility state for all views.
             AutofillClient client = getClientLocked();
             ArraySet<AutofillId> updatedVisibleTrackedIds = null;
             ArraySet<AutofillId> updatedInvisibleTrackedIds = null;
             if (client != null) {
                 if (mInvisibleTrackedIds != null) {
-                    for (AutofillId id : mInvisibleTrackedIds) {
-                        if (client.getViewVisibility(id.getViewId())) {
+                    final ArrayList<AutofillId> orderedInvisibleIds =
+                            new ArrayList<>(mInvisibleTrackedIds);
+                    final boolean[] isVisible = client.getViewVisibility(
+                            getViewIds(orderedInvisibleIds));
+
+                    final int numInvisibleTrackedIds = orderedInvisibleIds.size();
+                    for (int i = 0; i < numInvisibleTrackedIds; i++) {
+                        final AutofillId id = orderedInvisibleIds.get(i);
+                        if (isVisible[i]) {
                             updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
 
                             if (sDebug) {
@@ -1255,8 +1276,16 @@
                 }
 
                 if (mVisibleTrackedIds != null) {
-                    for (AutofillId id : mVisibleTrackedIds) {
-                        if (client.getViewVisibility(id.getViewId())) {
+                    final ArrayList<AutofillId> orderedVisibleIds =
+                            new ArrayList<>(mVisibleTrackedIds);
+                    final boolean[] isVisible = client.getViewVisibility(
+                            getViewIds(orderedVisibleIds));
+
+                    final int numVisibleTrackedIds = orderedVisibleIds.size();
+                    for (int i = 0; i < numVisibleTrackedIds; i++) {
+                        final AutofillId id = orderedVisibleIds.get(i);
+
+                        if (isVisible[i]) {
                             updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
                         } else {
                             updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
@@ -1355,12 +1384,11 @@
         }
 
         @Override
-        public void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
-                List<AutofillValue> values) {
+        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.autofill(sessionId, windowToken, ids, values));
+                        () -> afm.autofill(sessionId, ids, values));
             }
         }
 
@@ -1374,31 +1402,30 @@
         }
 
         @Override
-        public void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id,
-                int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
+        public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+                Rect anchorBounds, IAutofillWindowPresenter presenter) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.requestShowFillUi(sessionId, windowToken, id, width, height,
-                                anchorBounds, presenter));
+                        () -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+                                presenter));
             }
         }
 
         @Override
-        public void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
+        public void requestHideFillUi(int sessionId, AutofillId id) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.requestHideFillUi(sessionId, windowToken, id));
+                        () -> afm.requestHideFillUi(sessionId, id));
             }
         }
 
         @Override
-        public void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
+        public void notifyNoFillUi(int sessionId, AutofillId id) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.mContext.getMainThreadHandler().post(
-                        () -> afm.notifyNoFillUi(sessionId, windowToken, id));
+                afm.mContext.getMainThreadHandler().post(() -> afm.notifyNoFillUi(sessionId, id));
             }
         }
 
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index f28d8ba..4193a3c 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,12 +32,11 @@
 interface IAutoFillManager {
     // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
     int addClient(in IAutoFillManagerClient client, int userId);
-    int startSession(IBinder activityToken, IBinder windowToken, in IBinder appCallback,
-            in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
-            boolean hasCallback, int flags, String packageName);
+    int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
+            in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
+            String packageName);
     FillEventHistory getFillEventHistory();
     boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
-    void setWindow(int sessionId, in IBinder windowToken);
     void updateSession(int sessionId, in AutofillId id, in Rect bounds,
             in AutofillValue value, int action, int flags, int userId);
     void finishSession(int sessionId, int userId);
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index aef98b7..825d311 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -40,8 +40,7 @@
     /**
       * Autofills the activity with the contents of a dataset.
       */
-    void autofill(int sessionId, in IBinder windowToken, in List<AutofillId> ids,
-            in List<AutofillValue> values);
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
 
     /**
       * Authenticates a fill response or a data set.
@@ -58,18 +57,18 @@
     /**
      * Requests showing the fill UI.
      */
-    void requestShowFillUi(int sessionId, in IBinder windowToken, in AutofillId id, int width,
-            int height, in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+    void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+    in Rect anchorBounds, in IAutofillWindowPresenter presenter);
 
     /**
      * Requests hiding the fill UI.
      */
-    void requestHideFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
+    void requestHideFillUi(int sessionId, in AutofillId id);
 
     /**
      * Notifies no fill UI will be shown.
      */
-    void notifyNoFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
+    void notifyNoFillUi(int sessionId, in AutofillId id);
 
     /**
      * Starts the provided intent sender
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 7bdd6da..d456989 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -737,6 +737,7 @@
         mInputText.setFilters(new InputFilter[] {
             new InputTextFilter()
         });
+        mInputText.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
 
         mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
         mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE);
@@ -770,6 +771,12 @@
         if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         }
+
+        // Should be focusable by default, as the text view whose visibility changes is focusable
+        if (getFocusable() == View.FOCUSABLE_AUTO) {
+            setFocusable(View.FOCUSABLE);
+            setFocusableInTouchMode(true);
+        }
     }
 
     @Override
@@ -856,7 +863,7 @@
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
                 removeAllCallbacks();
-                mInputText.setVisibility(View.INVISIBLE);
+                hideSoftInput();
                 mLastDownOrMoveEventY = mLastDownEventY = event.getY();
                 mLastDownEventTime = event.getEventTime();
                 mIgnoreMoveEvents = false;
@@ -883,11 +890,9 @@
                     mFlingScroller.forceFinished(true);
                     mAdjustScroller.forceFinished(true);
                 } else if (mLastDownEventY < mTopSelectionDividerTop) {
-                    hideSoftInput();
                     postChangeCurrentByOneFromLongPress(
                             false, ViewConfiguration.getLongPressTimeout());
                 } else if (mLastDownEventY > mBottomSelectionDividerBottom) {
-                    hideSoftInput();
                     postChangeCurrentByOneFromLongPress(
                             true, ViewConfiguration.getLongPressTimeout());
                 } else {
@@ -1120,6 +1125,7 @@
     @Override
     public void scrollBy(int x, int y) {
         int[] selectorIndices = mSelectorIndices;
+        int startScrollOffset = mCurrentScrollOffset;
         if (!mWrapSelectorWheel && y > 0
                 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
             mCurrentScrollOffset = mInitialScrollOffset;
@@ -1147,6 +1153,9 @@
                 mCurrentScrollOffset = mInitialScrollOffset;
             }
         }
+        if (startScrollOffset != mCurrentScrollOffset) {
+            onScrollChanged(0, mCurrentScrollOffset, 0, startScrollOffset);
+        }
     }
 
     @Override
@@ -1735,7 +1744,10 @@
         }
         int previous = mValue;
         mValue = current;
-        updateInputTextView();
+        // If we're flinging, we'll update the text view at the end when it becomes visible
+        if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) {
+            updateInputTextView();
+        }
         if (notifyChange) {
             notifyChange(previous, current);
         }
@@ -1752,7 +1764,7 @@
      */
      private void changeValueByOne(boolean increment) {
         if (mHasSelectorWheel) {
-            mInputText.setVisibility(View.INVISIBLE);
+            hideSoftInput();
             if (!moveToFinalScrollerPosition(mFlingScroller)) {
                 moveToFinalScrollerPosition(mAdjustScroller);
             }
@@ -1799,9 +1811,8 @@
      */
     private void onScrollerFinished(Scroller scroller) {
         if (scroller == mFlingScroller) {
-            if (!ensureScrollWheelAdjusted()) {
-                updateInputTextView();
-            }
+            ensureScrollWheelAdjusted();
+            updateInputTextView();
             onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
         } else {
             if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
@@ -1937,9 +1948,25 @@
          */
         String text = (mDisplayedValues == null) ? formatNumber(mValue)
                 : mDisplayedValues[mValue - mMinValue];
-        if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) {
-            mInputText.setText(text);
-            return true;
+        if (!TextUtils.isEmpty(text)) {
+            CharSequence beforeText = mInputText.getText();
+            if (!text.equals(beforeText.toString())) {
+                mInputText.setText(text);
+                if (mAccessibilityNodeProvider != null) {
+                    AccessibilityEvent event = AccessibilityEvent.obtain(
+                            AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+                    mInputText.onInitializeAccessibilityEvent(event);
+                    mInputText.onPopulateAccessibilityEvent(event);
+                    event.setFromIndex(0);
+                    event.setRemovedCount(beforeText.length());
+                    event.setAddedCount(text.length());
+                    event.setBeforeText(beforeText);
+                    event.setSource(NumberPicker.this,
+                            AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT);
+                    requestSendAccessibilityEvent(NumberPicker.this, event);
+                }
+                return true;
+            }
         }
 
         return false;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 99a25fd..373f4bb 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -132,6 +132,7 @@
     void noteBleScanStarted(in WorkSource ws);
     void noteBleScanStopped(in WorkSource ws);
     void noteResetBleScan();
+    void noteBleScanResult(in WorkSource ws);
 
     HealthStatsParceler takeUidSnapshot(int uid);
     HealthStatsParceler[] takeUidSnapshots(in int[] uid);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a582c2c..748272600 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -114,7 +114,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 155 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 156 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -4704,6 +4704,14 @@
         }
     }
 
+    public void noteBluetoothScanResultFromSourceLocked(WorkSource ws) {
+        final int N = ws.size();
+        for (int i = 0; i < N; i++) {
+            int uid = mapUid(ws.get(i));
+            getUidStatsLocked(uid).noteBluetoothScanResultLocked();
+        }
+    }
+
     private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis,
             final long uptimeMillis, int uid) {
         uid = mapUid(uid);
@@ -5421,6 +5429,7 @@
         StopwatchTimer mCameraTurnedOnTimer;
         StopwatchTimer mForegroundActivityTimer;
         DualTimer mBluetoothScanTimer;
+        Counter mBluetoothScanResultCounter;
 
         int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
         StopwatchTimer[] mProcessStateTimer;
@@ -5864,6 +5873,17 @@
             }
         }
 
+        public Counter createBluetoothScanResultCounterLocked() {
+            if (mBluetoothScanResultCounter == null) {
+                mBluetoothScanResultCounter = new Counter(mBsi.mOnBatteryTimeBase);
+            }
+            return mBluetoothScanResultCounter;
+        }
+
+        public void noteBluetoothScanResultLocked() {
+            createBluetoothScanResultCounterLocked().stepAtomic();
+        }
+
         @Override
         public void noteActivityResumedLocked(long elapsedRealtimeMs) {
             // We always start, since we want multiple foreground PIDs to nest
@@ -6017,6 +6037,11 @@
             return mBluetoothScanTimer.getSubTimer();
         }
 
+        @Override
+        public Counter getBluetoothScanResultCounter() {
+            return mBluetoothScanResultCounter;
+        }
+
         void makeProcessState(int i, Parcel in) {
             if (i < 0 || i >= NUM_PROCESS_STATE) return;
 
@@ -6266,6 +6291,9 @@
             active |= !resetTimerIfNotNull(mCameraTurnedOnTimer, false);
             active |= !resetTimerIfNotNull(mForegroundActivityTimer, false);
             active |= !resetTimerIfNotNull(mBluetoothScanTimer, false);
+            if (mBluetoothScanResultCounter != null) {
+                mBluetoothScanResultCounter.reset(false);
+            }
 
             if (mProcessStateTimer != null) {
                 for (int i = 0; i < NUM_PROCESS_STATE; i++) {
@@ -6450,6 +6478,10 @@
                     mBluetoothScanTimer.detach();
                     mBluetoothScanTimer = null;
                 }
+                if (mBluetoothScanResultCounter != null) {
+                    mBluetoothScanResultCounter.detach();
+                    mBluetoothScanResultCounter = null;
+                }
                 if (mUserActivityCounters != null) {
                     for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
                         mUserActivityCounters[i].detach();
@@ -6620,6 +6652,12 @@
             } else {
                 out.writeInt(0);
             }
+            if (mBluetoothScanResultCounter != null) {
+                out.writeInt(1);
+                mBluetoothScanResultCounter.writeToParcel(out);
+            } else {
+                out.writeInt(0);
+            }
             for (int i = 0; i < NUM_PROCESS_STATE; i++) {
                 if (mProcessStateTimer[i] != null) {
                     out.writeInt(1);
@@ -6850,6 +6888,11 @@
             } else {
                 mBluetoothScanTimer = null;
             }
+            if (in.readInt() != 0) {
+                mBluetoothScanResultCounter = new Counter(mBsi.mOnBatteryTimeBase, in);
+            } else {
+                mBluetoothScanResultCounter = null;
+            }
             mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
             for (int i = 0; i < NUM_PROCESS_STATE; i++) {
                 if (in.readInt() != 0) {
@@ -10998,6 +11041,9 @@
             if (in.readInt() != 0) {
                 u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in);
             }
+            if (in.readInt() != 0) {
+                u.createBluetoothScanResultCounterLocked().readSummaryFromParcelLocked(in);
+            }
             u.mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
             for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
                 if (in.readInt() != 0) {
@@ -11391,6 +11437,12 @@
             } else {
                 out.writeInt(0);
             }
+            if (u.mBluetoothScanResultCounter != null) {
+                out.writeInt(1);
+                u.mBluetoothScanResultCounter.writeSummaryFromParcelLocked(out);
+            } else {
+                out.writeInt(0);
+            }
             for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
                 if (u.mProcessStateTimer[i] != null) {
                     out.writeInt(1);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 80b6b08..1b83708 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1498,7 +1498,6 @@
 
         final Window.Callback cb = mWindow.getCallback();
         if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
-            cb.onBeforeAttachedToWindow();
             cb.onAttachedToWindow();
         }
 
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index fc90fb3..9ad57b1 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -41,9 +41,6 @@
 
 namespace android {
 
-// Must be same with Java constant in Typeface.Builder. See Typeface.java
-constexpr jint RESOLVE_BY_FONT_TABLE = -1;
-
 struct NativeFamilyBuilder {
     NativeFamilyBuilder(uint32_t langId, int variant)
         : langId(langId), variant(variant), allowUnsupportedFont(false) {}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 86c97a1..eb2ca5d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -30,14 +30,14 @@
 
 static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createFromTypeface(family, (SkTypeface::Style)style);
+    Typeface* face = Typeface::createRelative(family, (SkTypeface::Style)style);
     // TODO: the following logic shouldn't be necessary, the above should always succeed.
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+        face = Typeface::createRelative(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
     }
     for (int i = 0; NULL == face && i < 4; i++) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)i);
+        face = Typeface::createRelative(family, (SkTypeface::Style)i);
     }
     return reinterpret_cast<jlong>(face);
 }
@@ -45,8 +45,7 @@
 static jlong Typeface_createFromTypefaceWithExactStyle(JNIEnv* env, jobject, jlong nativeInstance,
         jint weight, jboolean italic) {
     Typeface* baseTypeface = reinterpret_cast<Typeface*>(nativeInstance);
-    return reinterpret_cast<jlong>(
-            Typeface::createFromTypefaceWithStyle(baseTypeface, weight, italic));
+    return reinterpret_cast<jlong>(Typeface::createAbsolute(baseTypeface, weight, italic));
 }
 
 static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
@@ -68,7 +67,7 @@
 
 static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createWeightAlias(family, weight);
+    Typeface* face = Typeface::createWithDifferentBaseWeight(family, weight);
     return reinterpret_cast<jlong>(face);
 }
 
@@ -82,9 +81,9 @@
     return face->fSkiaStyle;
 }
 
-static jint Typeface_getBaseWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
+static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
     Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
-    return face->fBaseWeight;
+    return face->fStyle.getWeight() * 100;
 }
 
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
@@ -134,7 +133,7 @@
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
-    { "nativeGetBaseWeight",      "(J)I",  (void*)Typeface_getBaseWeight },
+    { "nativeGetWeight",      "(J)I",  (void*)Typeface_getWeight },
     { "nativeCreateFromArray",    "([JII)J",
                                            (void*)Typeface_createFromArray },
     { "nativeSetDefault",         "(J)V",   (void*)Typeface_setDefault },
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
new file mode 100644
index 0000000..1dced75
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.internal.os;
+
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import android.os.WorkSource;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Test various BatteryStatsImpl noteStart methods.
+ */
+public class BatteryStatsNoteTest extends TestCase{
+    private static final int UID = 10500;
+    private static final WorkSource WS = new WorkSource(UID);
+
+    /** Test that BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */
+    @SmallTest
+    public void testNoteBluetoothScanResultLocked() throws Exception {
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
+        bi.updateTimeBasesLocked(true, true, 0, 0);
+
+        bi.noteBluetoothScanResultFromSourceLocked(WS);
+        bi.noteBluetoothScanResultFromSourceLocked(WS);
+        assertEquals(2,
+                bi.getUidStats().get(UID).getBluetoothScanResultCounter()
+                        .getCountLocked(STATS_SINCE_CHARGED));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 57d6934..3a16fcf 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -15,6 +15,7 @@
         BatteryStatsUidTest.class,
         BatteryStatsSensorTest.class,
         BatteryStatsBackgroundStatsTest.class,
+        BatteryStatsNoteTest.class,
     })
 public class BatteryStatsTests {
 }
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 79898bc..5a56f53 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -123,7 +123,7 @@
     public static final int BOLD_ITALIC = 3;
 
     private int mStyle = 0;
-    private int mBaseWeight = 0;
+    private int mWeight = 0;
 
     // Value for weight and italic. Indicates the value is resolved by font metadata.
     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -544,7 +544,7 @@
                 return base;
             }
 
-            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight;
+            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mWeight : mWeight;
             final boolean italic =
                     (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1;
             final int key = weight << 1 | (italic ? 1 : 0);
@@ -882,7 +882,7 @@
 
         native_instance = ni;
         mStyle = nativeGetStyle(ni);
-        mBaseWeight = nativeGetBaseWeight(ni);
+        mWeight = nativeGetWeight(ni);
     }
 
     private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
@@ -1068,7 +1068,7 @@
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
-    private static native int  nativeGetBaseWeight(long native_instance);
+    private static native int  nativeGetWeight(long native_instance);
     private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
     private static native void nativeSetDefault(long native_instance);
     private static native int[] nativeGetSupportedAxes(long native_instance);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 41e5af1..c3ef450 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -483,10 +483,10 @@
         final int sourceDensity = mVectorState.mDensity;
         final int targetDensity = mTargetDensity;
         if (targetDensity != sourceDensity) {
-            mDpiScaledWidth = Drawable.scaleFromDensity(
-                    (int) mVectorState.mBaseWidth, sourceDensity, targetDensity, true);
-            mDpiScaledHeight = Drawable.scaleFromDensity(
-                    (int) mVectorState.mBaseHeight,sourceDensity, targetDensity, true);
+            mDpiScaledWidth = Drawable.scaleFromDensity(mVectorState.mBaseWidth, sourceDensity,
+                    targetDensity, true);
+            mDpiScaledHeight = Drawable.scaleFromDensity(mVectorState.mBaseHeight,sourceDensity,
+                    targetDensity, true);
             final int left = Drawable.scaleFromDensity(
                     opticalInsets.left, sourceDensity, targetDensity, false);
             final int right = Drawable.scaleFromDensity(
@@ -497,8 +497,8 @@
                     opticalInsets.bottom, sourceDensity, targetDensity, false);
             mDpiScaledInsets = Insets.of(left, top, right, bottom);
         } else {
-            mDpiScaledWidth = (int) mVectorState.mBaseWidth;
-            mDpiScaledHeight = (int) mVectorState.mBaseHeight;
+            mDpiScaledWidth = mVectorState.mBaseWidth;
+            mDpiScaledHeight = mVectorState.mBaseHeight;
             mDpiScaledInsets = opticalInsets;
         }
 
@@ -675,9 +675,9 @@
                     "<vector> tag requires viewportHeight > 0");
         }
 
-        state.mBaseWidth = a.getDimension(
+        state.mBaseWidth = a.getDimensionPixelSize(
                 R.styleable.VectorDrawable_width, state.mBaseWidth);
-        state.mBaseHeight = a.getDimension(
+        state.mBaseHeight = a.getDimensionPixelSize(
                 R.styleable.VectorDrawable_height, state.mBaseHeight);
 
         if (state.mBaseWidth <= 0) {
@@ -819,8 +819,8 @@
         Mode mTintMode = DEFAULT_TINT_MODE;
         boolean mAutoMirrored;
 
-        float mBaseWidth = 0;
-        float mBaseHeight = 0;
+        int mBaseWidth = 0;
+        int mBaseHeight = 0;
         float mViewportWidth = 0;
         float mViewportHeight = 0;
         Insets mOpticalInsets = Insets.NONE;
@@ -1004,8 +1004,9 @@
         }
 
         private void applyDensityScaling(int sourceDensity, int targetDensity) {
-            mBaseWidth = Drawable.scaleFromDensity(mBaseWidth, sourceDensity, targetDensity);
-            mBaseHeight = Drawable.scaleFromDensity(mBaseHeight, sourceDensity, targetDensity);
+            mBaseWidth = Drawable.scaleFromDensity(mBaseWidth, sourceDensity, targetDensity, true);
+            mBaseHeight = Drawable.scaleFromDensity(mBaseHeight, sourceDensity, targetDensity,
+                    true);
 
             final int insetLeft = Drawable.scaleFromDensity(
                     mOpticalInsets.left, sourceDensity, targetDensity, false);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5ef49dc..030e845 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -319,6 +319,7 @@
     tests/unit/TestUtilsTests.cpp \
     tests/unit/TextDropShadowCacheTests.cpp \
     tests/unit/TextureCacheTests.cpp \
+    tests/unit/TypefaceTests.cpp \
     tests/unit/VectorDrawableTests.cpp \
 
 include $(LOCAL_PATH)/hwui_static_deps.mk
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 4fb4b53..f66bb04 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -36,28 +36,33 @@
 #include <minikin/FontFamily.h>
 #include <minikin/Layout.h>
 #include <utils/Log.h>
+#include <utils/MathUtils.h>
 
 namespace android {
 
-// This indicates that the passed information should be resolved by OS/2 table.
-// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
-constexpr int RESOLVE_BY_FONT_TABLE = -1;
+static SkTypeface::Style computeSkiaStyle(int weight, bool italic) {
+    // This bold detection comes from SkTypeface.h
+    if (weight >= SkFontStyle::kSemiBold_Weight) {
+        return italic ? SkTypeface::kBoldItalic : SkTypeface::kBold;
+    } else {
+        return italic ? SkTypeface::kItalic : SkTypeface::kNormal;
+    }
+}
 
-// Resolve the 1..10 weight based on base weight and bold flag
-static void resolveStyle(Typeface* typeface) {
+static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
     // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
-    int weight = (typeface->fBaseWeight + 50) / 100;
-    if (typeface->fSkiaStyle & SkTypeface::kBold) {
-        weight += 3;
+    const int minikinWeight = uirenderer::MathUtils::clamp((weight + 50) / 100, 1, 10);
+    return minikin::FontStyle(minikinWeight, italic);
+}
+
+// Resolve the relative weight from the baseWeight and target style.
+static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style relativeStyle) {
+    int weight = baseWeight;
+    if ((relativeStyle & SkTypeface::kBold) != 0) {
+        weight += 300;
     }
-    if (weight > 10) {
-        weight = 10;
-    }
-    if (weight < 1) {
-        weight = 1;
-    }
-    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
-    typeface->fStyle = minikin::FontStyle(weight, italic);
+    bool italic = (relativeStyle & SkTypeface::kItalic) != 0;
+    return computeMinikinStyle(weight, italic);
 }
 
 Typeface* gDefaultTypeface = NULL;
@@ -67,26 +72,26 @@
     return src == nullptr ? gDefaultTypeface : src;
 }
 
-Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
+Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = style;
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = style;
+        result->fStyle = computeRelativeStyle(result->fBaseWeight, style);
     }
     return result;
 }
 
-Typeface* Typeface::createFromTypefaceWithStyle(Typeface* base, int weight, bool italic) {
+Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
     Typeface* resolvedFace = Typeface::resolveDefault(base);
     Typeface* result = new Typeface();
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fBaseWeight = weight;
-        result->fStyle = minikin::FontStyle(weight / 100, italic);
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fBaseWeight = resolvedFace->fBaseWeight;
+        result->fSkiaStyle = computeSkiaStyle(weight, italic);
+        result->fStyle = computeMinikinStyle(weight, italic);
     }
     return result;
 }
@@ -103,21 +108,23 @@
             // So we will reuse the same collection with incrementing reference count.
             result->fFontCollection = resolvedFace->fFontCollection;
         }
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        // Do not update styles.
+        // TODO: We may want to update base weight if the 'wght' is specified.
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = resolvedFace->fStyle;
     }
     return result;
 }
 
-Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
+Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
         result->fBaseWeight = weight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = computeRelativeStyle(weight, result->fSkiaStyle);
     }
     return result;
 }
@@ -160,14 +167,8 @@
     }
 
     result->fBaseWeight = weight;
-    // This bold detection comes from SkTypefae.h
-    const bool isBold = weight >= SkFontStyle::kSemiBold_Weight;
-    const bool isItalic = italic == 1;
-    // TODO: remove fSkiaStyle
-    result->fSkiaStyle = isBold ?
-            (isItalic ? SkTypeface::kBoldItalic : SkTypeface::kBold) :
-            (isItalic ? SkTypeface::kItalic : SkTypeface::kNormal);
-    resolveStyle(result);
+    result->fSkiaStyle = computeSkiaStyle(weight, italic);
+    result->fStyle = computeMinikinStyle(weight, italic);
     return result;
 }
 
@@ -197,7 +198,7 @@
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
     hwTypeface->fSkiaStyle = SkTypeface::kNormal;
-    hwTypeface->fBaseWeight = SkFontStyle::kSemiBold_Weight;
+    hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
     hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
 
     Typeface::setDefault(hwTypeface);
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index e35a7b4..db0b2cd 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -27,28 +27,53 @@
 
 namespace android {
 
-struct ANDROID_API Typeface {
-    std::shared_ptr<minikin::FontCollection> fFontCollection;
+// This indicates that the weight or italic information should be resolved by OS/2 table.
+// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
+constexpr int RESOLVE_BY_FONT_TABLE = -1;
 
-    // style used for constructing and querying Typeface objects
-    SkTypeface::Style fSkiaStyle;
-    // base weight in CSS-style units, 100..900
-    int fBaseWeight;
+struct ANDROID_API Typeface {
+ public:
+    std::shared_ptr<minikin::FontCollection> fFontCollection;
 
     // resolved style actually used for rendering
     minikin::FontStyle fStyle;
 
+    // style used for constructing and querying Typeface objects
+    SkTypeface::Style fSkiaStyle;
+
     static Typeface* resolveDefault(Typeface* src);
 
-    static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
-
-    static Typeface* createFromTypefaceWithStyle(Typeface* base, int weight, bool italic);
+    // The following three functions create new Typeface from an existing Typeface with a different
+    // style. There is a base weight concept which is used for calculating relative style from an
+    // existing Typeface.
+    // The createRelative method creates a new Typeface with a style relative to the base Typeface.
+    // For example, if the base Typeface has a base weight of 400 and the desired style is bold, the
+    // resulting Typeface renders the text with a weight of 700. This function doesn't change the
+    // base weight, so even if you create a new Typeface from the bold Typeface specifying bold on
+    // it again, the text is still rendered with a weight of 700.
+    // You can create another base weight Typeface from an existing Typeface with
+    // createWithDifferentBaseWeight. The Typeface created with this function renders the text with
+    // a specified base weight.
+    // The createAbsolute method creates a new Typeface ignoring the base weight.
+    // Here is an example:
+    //   Typeface* base = resolveDefault(nullptr);  // Usually this has a weight of 400.
+    //   Typeface* bold = createRelative(base, Bold);  // Rendered with a weight of 700.
+    //   Typeface* bold2 = createRelative(bold, Bold); // Rendered with a weight of 700.
+    //
+    //   Typeface* boldBase = createWithDifferentBaseWeight(base, 700);  // With a weight of 700.
+    //   Typeface* boldBold = createRelative(boldBase, Bold);  // Rendered with a weight of 1000.
+    //
+    //   Typeface* lightBase = createWithDifferentBaseWeight(base, 300);  // With a weight of 300.
+    //   Typeface* lightBold = createRelative(lightBase, Bold);  // Rendered with a weight of 600.
+    //
+    //   Typeface* black = createAbsolute(base, 900, false);  // Rendered with a weight of 900.
+    static Typeface* createWithDifferentBaseWeight(Typeface* src, int baseweight);
+    static Typeface* createRelative(Typeface* src, SkTypeface::Style desiredStyle);
+    static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
 
     static Typeface* createFromTypefaceWithVariation(Typeface* src,
             const std::vector<minikin::FontVariation>& variations);
 
-    static Typeface* createWeightAlias(Typeface* src, int baseweight);
-
     static Typeface* createFromFamilies(
             std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
             int weight, int italic);
@@ -57,6 +82,10 @@
 
     // Sets roboto font as the default typeface for testing purpose.
     static void setRobotoTypefaceForTest();
+ private:
+    // base weight in CSS-style units, 1..1000
+    int fBaseWeight;
+
 };
 
 }
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
new file mode 100644
index 0000000..c90b6f0
--- /dev/null
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <utils/Log.h>
+
+#include "SkFontMgr.h"
+#include "SkStream.h"
+
+#include "hwui/MinikinSkia.h"
+#include "hwui/Typeface.h"
+
+using namespace android;
+
+namespace {
+
+constexpr char kRobotoRegular[] = "/system/fonts/Roboto-Regular.ttf";
+constexpr char kRobotoBold[] = "/system/fonts/Roboto-Bold.ttf";
+constexpr char kRobotoItalic[] = "/system/fonts/Roboto-Italic.ttf";
+constexpr char kRobotoBoldItalic[] = "/system/fonts/Roboto-BoldItalic.ttf";
+
+void unmap(const void* ptr, void* context) {
+    void* p = const_cast<void*>(ptr);
+    size_t len = reinterpret_cast<size_t>(context);
+    munmap(p, len);
+}
+
+std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) {
+    int fd = open(fileName, O_RDONLY);
+    LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", fileName);
+    struct stat st = {};
+    LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", fileName);
+    void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    sk_sp<SkData> skData =
+            SkData::MakeWithProc(data, st.st_size, unmap, reinterpret_cast<void*>(st.st_size));
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(skData));
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> typeface(fm->createFromStream(fontData.release()));
+    LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
+    std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
+            std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
+    return std::make_shared<minikin::FontFamily>(
+            std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+}
+
+std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
+    return std::vector<std::shared_ptr<minikin::FontFamily>>({ buildFamily(fileName) });
+}
+
+TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
+
+    Typeface* old = Typeface::resolveDefault(nullptr);  // Keep the original to restore it later.
+    ASSERT_NE(nullptr, old);
+
+    Typeface::setDefault(regular.get());
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(nullptr));
+
+    Typeface::setDefault(old);  // Restore to the original.
+}
+
+TEST(TypefaceTest, createWithDifferentBaseWeight) {
+    std::unique_ptr<Typeface> bold(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, bold->fSkiaStyle);
+
+    std::unique_ptr<Typeface> light(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+    EXPECT_EQ(3, light->fStyle.getWeight());
+    EXPECT_FALSE(light->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, light->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromRegular) {
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(nullptr, SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(nullptr, SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createRelative(nullptr, SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_BoldBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(7, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(10, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(7, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(10, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_LightBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(3, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(6, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.ITLIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(3, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(6, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromBoldStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kBold));
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromItalicStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createAbsolute(nullptr, 400, false));
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createAbsolute) {
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> regular(Typeface::createAbsolute(nullptr, 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> bold(Typeface::createAbsolute(nullptr, 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> italic(Typeface::createAbsolute(nullptr, 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> boldItalic(Typeface::createAbsolute(nullptr, 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> over1000(Typeface::createAbsolute(nullptr, 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
+    std::unique_ptr<Typeface> over1000(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Family) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoRegular), buildFamily(kRobotoBold), buildFamily(kRobotoItalic),
+            buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+}  // namespace
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index d82e549..e7da20b 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1453,7 +1453,8 @@
         /**
          * The release date of this TV program.
          *
-         * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+         * <p>The value should be in one of the following formats:
+         * "yyyy", "yyyy-MM-dd", and "yyyy-MM-ddTHH:mm:ssZ" (UTC in ISO 8601).
          *
          * <p>Type: TEXT
          */
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index 5446ace..9fb956e 100644
--- a/packages/SettingsLib/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_two_target.xml
@@ -37,7 +37,7 @@
             android:id="@+id/icon_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="60dp"
+            android:minWidth="56dp"
             android:orientation="horizontal"
             android:paddingEnd="12dp"
             android:paddingTop="4dp"
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index e52c5db..7541b0e 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -31,5 +31,6 @@
         <item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
         <item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
         <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+        <item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
     </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
index 40e3b12..ffd58dc 100644
--- a/packages/SystemUI/res/values/config_tv.xml
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -17,17 +17,9 @@
 <resources>
     <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
          when the PIP menu is shown with settings. -->
-    <string translatable="false" name="pip_settings_bounds">"662 54 1142 324"</string>
+    <string translatable="false" name="pip_settings_bounds">"662 756 1142 1026"</string>
 
     <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
          when the PIP menu is shown in center. -->
     <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
-
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
-         when the PIP is shown in Recents without focus. -->
-    <string translatable="false" name="pip_recents_bounds">"800 54 1120 234"</string>
-
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
-         when the PIP is shown in Recents with focus. -->
-    <string translatable="false" name="pip_recents_focused_bounds">"775 54 1145 262"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index e578068..a9bdb71 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -17,6 +17,14 @@
  */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Picture-in-Picture (PIP) notification -->
+    <!-- Title for the notification channel for TV PIP controls. [CHAR LIMIT=NONE] -->
+    <string name="notification_channel_tv_pip">Picture-in-Picture</string>
+    <!-- Title of the picture-in-picture (PIP) notification title
+         when the media doesn't have title [CHAR LIMIT=NONE] -->
+    <string name="pip_notification_unknown_title">(No title program)</string>
+
     <!-- Picture-in-Picture (PIP) menu -->
     <eat-comment />
     <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 9735bfc..6667b71 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -61,7 +61,8 @@
  */
 public class PipManager implements BasePipManager {
     private static final String TAG = "PipManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/";
 
     private static PipManager sPipManager;
@@ -122,6 +123,7 @@
     private ComponentName mPipComponentName;
     private MediaController mPipMediaController;
     private String[] mLastPackagesResourceGranted;
+    private PipNotification mPipNotification;
 
     private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
@@ -246,6 +248,8 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
+
+        mPipNotification = new PipNotification(context);
     }
 
     private void loadConfigurationsAndApply() {
@@ -267,6 +271,7 @@
      */
     public void onConfigurationChanged() {
         loadConfigurationsAndApply();
+        mPipNotification.onConfigurationChanged(mContext);
     }
 
     /**
@@ -345,7 +350,7 @@
      * @param state In Pip state also used to determine the new size for the Pip.
      */
     void resizePinnedStack(int state) {
-        if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+        if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state, new Exception());
         boolean wasStateNoPip = (mState == STATE_NO_PIP);
         mResumeResizePinnedStackRunnable = state;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -511,8 +516,8 @@
 
     /**
      * Returns the PIPed activity's playback state.
-     * This returns one of {@link PLAYBACK_STATE_PLAYING}, {@link PLAYBACK_STATE_PAUSED},
-     * or {@link PLAYBACK_STATE_UNAVAILABLE}.
+     * This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
+     * or {@link #PLAYBACK_STATE_UNAVAILABLE}.
      */
     int getPlaybackState() {
         if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
new file mode 100644
index 0000000..727eb5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -0,0 +1,225 @@
+/*
+ * 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.systemui.pip.tv;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.util.NotificationChannels;
+import com.android.systemui.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+
+/**
+ * A notification that informs users that PIP is running and also provides PIP controls.
+ * <p>Once it's created, it will manage the PIP notification UI by itself except for handling
+ * configuration changes.
+ */
+public class PipNotification {
+    private static final String TAG = "PipNotification";
+    private static final boolean DEBUG = PipManager.DEBUG;
+
+    private static final String ACTION_MENU = "PipNotification.menu";
+    private static final String ACTION_CLOSE = "PipNotification.close";
+
+    private final PipManager mPipManager = PipManager.getInstance();
+
+    private final NotificationManager mNotificationManager;
+    private final Notification.Builder mNotificationBuilder;
+
+    private MediaController mMediaController;
+    private String mDefaultTitle;
+    private Icon mDefaultIcon;
+
+    private boolean mNotified;
+    private String mTitle;
+    private Bitmap mArt;
+
+    private PipManager.Listener mPipListener = new PipManager.Listener() {
+        @Override
+        public void onPipEntered() {
+            updateMediaControllerMetadata();
+            notifyPipNotification();
+        }
+
+        @Override
+        public void onPipActivityClosed() {
+            dismissPipNotification();
+        }
+
+        @Override
+        public void onShowPipMenu() {
+            // no-op.
+        }
+
+        @Override
+        public void onMoveToFullscreen() {
+            dismissPipNotification();
+        }
+
+        @Override
+        public void onPipResizeAboutToStart() {
+            // no-op.
+        }
+    };
+
+    private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            if (updateMediaControllerMetadata() && mNotified) {
+                // update notification
+                notifyPipNotification();
+            }
+        }
+    };
+
+    private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+        @Override
+        public void onMediaControllerChanged() {
+            MediaController newController = mPipManager.getMediaController();
+            if (mMediaController == newController) {
+                return;
+            }
+            if (mMediaController != null) {
+                mMediaController.unregisterCallback(mMediaControllerCallback);
+            }
+            mMediaController = newController;
+            if (mMediaController != null) {
+                mMediaController.registerCallback(mMediaControllerCallback);
+            }
+            if (updateMediaControllerMetadata() && mNotified) {
+                // update notification
+                notifyPipNotification();
+            }
+        }
+    };
+
+    private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.d(TAG, "Received " + intent.getAction() + " from the notification UI");
+            }
+            switch (intent.getAction()) {
+                case ACTION_MENU:
+                    mPipManager.showPictureInPictureMenu();
+                    break;
+                case ACTION_CLOSE:
+                    mPipManager.closePip();
+                    break;
+            }
+        }
+    };
+
+    public PipNotification(Context context) {
+        mNotificationManager = (NotificationManager) context.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+
+        mNotificationBuilder = new Notification.Builder(context, NotificationChannels.TVPIP)
+                .setLocalOnly(true)
+                .setOngoing(false)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .extend(new Notification.TvExtender()
+                        .setContentIntent(createPendingIntent(context, ACTION_MENU))
+                        .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
+
+        mPipManager.addListener(mPipListener);
+        mPipManager.addMediaListener(mPipMediaListener);
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_MENU);
+        intentFilter.addAction(ACTION_CLOSE);
+        context.registerReceiver(mEventReceiver, intentFilter);
+
+        onConfigurationChanged(context);
+    }
+
+    /**
+     * Called by {@link PipManager} when the configuration is changed.
+     */
+    void onConfigurationChanged(Context context) {
+        Resources res = context.getResources();
+        mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
+        mDefaultIcon = Icon.createWithResource(context,
+                res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
+                        ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr);
+        if (mNotified) {
+            // update notification
+            notifyPipNotification();
+        }
+    }
+
+    private void notifyPipNotification() {
+        mNotified = true;
+        mNotificationBuilder
+                .setShowWhen(true)
+                .setWhen(System.currentTimeMillis())
+                // TODO: Sending bitmap doesn't work in launcher side. Once launcher supports it,
+                // we can set icon.
+                //.setSmallIcon(mArt != null ? Icon.createWithBitmap(mArt) : mDefaultIcon)
+                .setSmallIcon(mDefaultIcon.getResId())
+                .setContentTitle(!TextUtils.isEmpty(mTitle) ? mTitle : mDefaultTitle);
+        mNotificationManager.notify(SystemMessage.NOTE_TV_PIP, mNotificationBuilder.build());
+    }
+
+    private void dismissPipNotification() {
+        mNotified = false;
+        mNotificationManager.cancel(SystemMessage.NOTE_TV_PIP);
+    }
+
+    private boolean updateMediaControllerMetadata() {
+        String title = null;
+        Bitmap art = null;
+        if (mPipManager.getMediaController() != null) {
+            MediaMetadata metadata = mPipManager.getMediaController().getMetadata();
+            if (metadata != null) {
+                title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE);
+                if (TextUtils.isEmpty(title)) {
+                    title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+                }
+                art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+                if (art == null) {
+                    art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+                }
+            }
+        }
+        if (!TextUtils.equals(title, mTitle) || art != mArt) {
+            mTitle = title;
+            mArt = art;
+            return true;
+        }
+        return false;
+    }
+
+    private static PendingIntent createPendingIntent(Context context, String action) {
+        return PendingIntent.getBroadcast(context, 0,
+                new Intent(action), PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 5512993..6f28838 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -68,6 +68,7 @@
     private final Callback mCallback = new Callback();
     private final ActivityStarter mActivityStarter;
     private Dialog mDialog;
+    private boolean mRegistered;
 
     public CastTile(QSHost host) {
         super(host);
@@ -146,7 +147,7 @@
                 mDialog = dialog;
             }
             mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
-            mDialog.show();
+            mUiHandler.post(() -> mDialog.show());
             registerReceiver();
             mHost.collapsePanels();
         });
@@ -155,7 +156,13 @@
     private void registerReceiver() {
         mContext.registerReceiverAsUser(mReceiver, UserHandle.CURRENT,
                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, null);
-        mDialog.setOnDismissListener(dialog -> mContext.unregisterReceiver(mReceiver));
+        mRegistered = true;
+        mDialog.setOnDismissListener(dialog -> {
+            if (mRegistered) {
+                mContext.unregisterReceiver(mReceiver);
+                mRegistered = false;
+            }
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 1375310..23a67e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -95,14 +95,25 @@
 
         /**
          * Called when the guts view have been told to close, typically after an outside
-         * interaction. Returning {@code true} here will prevent the guts view to close.
+         * interaction.
+         *
+         * @param save whether the state should be saved.
+         * @param force whether the guts view should be forced closed regardless of state.
+         * @return if closing the view has been handled.
          */
-        public boolean handleCloseControls(boolean save);
+        public boolean handleCloseControls(boolean save, boolean force);
 
         /**
          * @return whether the notification associated with these guts is set to be removed.
          */
         public boolean willBeRemoved();
+
+        /**
+         * @return whether these guts are a leavebehind (e.g. {@link NotificationSnooze}).
+         */
+        public default boolean isLeavebehind() {
+            return false;
+        }
     }
 
     public interface OnGutsClosedListener {
@@ -125,7 +136,7 @@
             @Override
             public void run() {
                 if (mNeedsFalsingProtection && mExposed) {
-                    closeControls(-1 /* x */, -1 /* y */, false /* save */);
+                    closeControls(-1 /* x */, -1 /* y */, false /* save */, false /* force */);
                 }
             }
         };
@@ -144,6 +155,10 @@
         addView(mGutsContent.getContentView());
     }
 
+    public GutsContent getGutsContent() {
+        return mGutsContent;
+    }
+
     public void resetFalsingCheck() {
         mHandler.removeCallbacks(mFalsingCheck);
         if (mNeedsFalsingProtection && mExposed) {
@@ -197,19 +212,30 @@
         }
     }
 
-    public void closeControls(int x, int y, boolean save) {
+    public void closeControls(boolean leavebehinds, boolean controls, int x, int y, boolean force) {
+        if (mGutsContent != null) {
+            if (mGutsContent.isLeavebehind() && leavebehinds) {
+                closeControls(x, y, true /* save */, force);
+            } else if (!mGutsContent.isLeavebehind() && controls) {
+                closeControls(x, y, true /* save */, force);
+            }
+        }
+    }
+
+    public void closeControls(int x, int y, boolean save, boolean force) {
         if (getWindowToken() == null) {
             if (mClosedListener != null) {
                 mClosedListener.onGutsClosed(this);
             }
             return;
         }
-        if (mGutsContent == null || !mGutsContent.handleCloseControls(save)) {
+
+        if (mGutsContent == null || !mGutsContent.handleCloseControls(save, force)) {
             animateClose(x, y);
-        }
-        setExposed(false, mNeedsFalsingProtection);
-        if (mClosedListener != null) {
-            mClosedListener.onGutsClosed(this);
+            setExposed(false, mNeedsFalsingProtection);
+            if (mClosedListener != null) {
+                mClosedListener.onGutsClosed(this);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 2cf06c2..0c2c5bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -393,7 +393,7 @@
     }
 
     @Override
-    public boolean handleCloseControls(boolean save) {
+    public boolean handleCloseControls(boolean save, boolean force) {
         if (save && hasImportanceChanged()) {
             if (mCheckSaveListener != null) {
                 mCheckSaveListener.checkSave(() -> { saveImportance(); });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index 8b3d6d9..8830c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -103,6 +103,18 @@
         createOptionViews();
     }
 
+    public boolean isExpanded() {
+        return mExpanded;
+    }
+
+    public void setSnoozeListener(NotificationSwipeActionHelper listener) {
+        mSnoozeListener = listener;
+    }
+
+    public void setStatusBarNotification(StatusBarNotification sbn) {
+        mSbn = sbn;
+    }
+
     private ArrayList<SnoozeOption> getDefaultSnoozeOptions() {
         ArrayList<SnoozeOption> options = new ArrayList<>();
         options.add(createOption(R.string.snooze_option_15_min, 15));
@@ -203,7 +215,7 @@
             final int x = targetLoc[0] - parentLoc[0] + centerX;
             final int y = targetLoc[1] - parentLoc[1] + centerY;
             showSnoozeOptions(false);
-            mGutsContainer.closeControls(x, y, false /* save */);
+            mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
         }
     }
 
@@ -224,29 +236,31 @@
         return this;
     }
 
-    public void setStatusBarNotification(StatusBarNotification sbn) {
-        mSbn = sbn;
-    }
-
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
     }
 
-    public void setSnoozeListener(NotificationSwipeActionHelper listener) {
-        mSnoozeListener = listener;
-    }
-
     @Override
-    public boolean handleCloseControls(boolean save) {
-        // When snooze is closed (i.e. there was interaction outside of the notification)
-        // then we commit the snooze action.
-        if (mSnoozeListener != null && mSelectedOption != null) {
+    public boolean handleCloseControls(boolean save, boolean force) {
+        if (mExpanded && !force) {
+            // Collapse expanded state on outside touch
+            showSnoozeOptions(false);
+            return true;
+        } else if (mSnoozeListener != null && mSelectedOption != null) {
+            // Snooze option selected so commit it
             mSnoozing = true;
             mSnoozeListener.snooze(mSbn, mSelectedOption);
             return true;
+        } else {
+            // The view should actually be closed
+            setSelected(mSnoozeOptions.get(0));
+            return false; // Return false here so that guts handles closing the view
         }
-        // The view should be closed
-        return false;
+    }
+
+    @Override
+    public boolean isLeavebehind() {
+        return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 1a9a40b..674a61c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -168,7 +168,8 @@
                         distance = mTranslationOnDown + distance;
                         distance = Math.max(0, distance);
                     }
-                    setTranslation(distance, false /* isReset */, false /* animateReset */);
+                    setTranslation(distance, false /* isReset */, false /* animateReset */,
+                            false /* force */);
                 }
                 break;
 
@@ -373,11 +374,12 @@
         targetView.finishAnimation(velocity, mAnimationEndRunnable);
     }
 
-    private void setTranslation(float translation, boolean isReset, boolean animateReset) {
+    private void setTranslation(float translation, boolean isReset, boolean animateReset,
+            boolean force) {
         translation = rightSwipePossible() ? translation : Math.max(0, translation);
         translation = leftSwipePossible() ? translation : Math.min(0, translation);
         float absTranslation = Math.abs(translation);
-        if (translation != mTranslation || isReset) {
+        if (translation != mTranslation || isReset || force) {
             KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
             KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
             float alpha = absTranslation / getMinTranslationAmount();
@@ -392,15 +394,15 @@
             boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
                 updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
-                        false, false, false, false);
+                        false, false, force, false);
             } else {
                 updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
-                        animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                        animateIcons, slowAnimation, force, forceNoCircleAnimation);
             }
             updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
-                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
             updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
-                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
 
             mTranslation = translation;
         }
@@ -508,8 +510,12 @@
     }
 
     public void reset(boolean animate) {
+        reset(animate, false /* force */);
+    }
+
+    public void reset(boolean animate, boolean force) {
         cancelAnimation();
-        setTranslation(0.0f, true, animate);
+        setTranslation(0.0f, true, animate, force);
         mMotionCancelled = true;
         if (mSwipingInProgress) {
             mCallback.onSwipingAborted();
@@ -517,6 +523,10 @@
         }
     }
 
+    public void resetImmediately() {
+        reset(false /* animate */, true /* force */);
+    }
+
     public boolean isSwipingInProgress() {
         return mSwipingInProgress;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8a97be5..f7480bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -46,7 +46,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
@@ -524,7 +523,8 @@
             mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
         }
         closeQs();
-        mStatusBar.dismissPopups();
+        mStatusBar.closeAndSaveGuts(true /* leavebehind */, true /* force */,
+                true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
         mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
                 true /* cancelAnimators */);
         mNotificationStackScroller.resetScrollPosition();
@@ -1015,6 +1015,7 @@
         float height = mQsExpansionHeight - overscrollAmount;
         setQsExpansion(height);
         requestPanelHeightUpdate();
+        mNotificationStackScroller.checkSnoozeLeavebehind();
     }
 
     private void setQsExpanded(boolean expanded) {
@@ -1381,6 +1382,7 @@
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
+                mNotificationStackScroller.resetCheckSnoozeLeavebehind();
                 mQsExpansionAnimator = null;
                 if (onFinishRunnable != null) {
                     onFinishRunnable.run();
@@ -2463,6 +2465,14 @@
         }
     };
 
+    @Override
+    public void setTouchDisabled(boolean disabled) {
+        super.setTouchDisabled(disabled);
+        if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
+            mAffordanceHelper.resetImmediately();
+        }
+    }
+
     public void setDark(boolean dark) {
         mDark = dark;
         mKeyguardStatusView.setDark(dark);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e86fd48..d342635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -221,8 +221,11 @@
 
     public void setTouchDisabled(boolean disabled) {
         mTouchDisabled = disabled;
-        if (mTouchDisabled && mTracking) {
-            onTrackingStopped(true /* expanded */);
+        if (mTouchDisabled) {
+            cancelHeightAnimator();
+            if (mTracking) {
+                onTrackingStopped(true /* expanded */);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 4610bc8..b33d509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2996,8 +2996,9 @@
         mStatusBarWindowManager.setPanelVisible(false);
         mStatusBarWindowManager.setForceStatusBarVisible(false);
 
-        // Close any "App info" popups that might have snuck on-screen
-        dismissPopups();
+        // Close any guts that might be visible
+        closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */,
+                -1 /* x */, -1 /* y */, true /* resetMenu */);
 
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
@@ -4056,13 +4057,6 @@
             setBarState(StatusBarState.KEYGUARD);
         }
         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
-        if (!mDeviceInteractive) {
-
-            // If the screen is off already, we need to disable touch events because these might
-            // collapse the panel after we expanded it, and thus we would end up with a blank
-            // Keyguard.
-            mNotificationPanel.setTouchDisabled(true);
-        }
         if (mState == StatusBarState.KEYGUARD) {
             instantExpandNotificationsPanel();
         } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
@@ -4617,6 +4611,7 @@
     public void onDragDownReset() {
         mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
         mStackScroller.resetScrollPosition();
+        mStackScroller.resetCheckSnoozeLeavebehind();
     }
 
     @Override
@@ -4627,6 +4622,7 @@
     @Override
     public void onTouchSlopExceeded() {
         mStackScroller.removeLongPressCallback();
+        mStackScroller.checkSnoozeLeavebehind();
     }
 
     @Override
@@ -4861,6 +4857,12 @@
         mStackScroller.setAnimationsEnabled(false);
         mVisualStabilityManager.setScreenOn(false);
         updateVisibleToUser();
+
+        // We need to disable touch events because these might
+        // collapse the panel after we expanded it, and thus we would end up with a blank
+        // Keyguard.
+        mNotificationPanel.setTouchDisabled(true);
+        mStatusBarWindow.cancelCurrentTouch();
         if (mLaunchCameraOnFinishedGoingToSleep) {
             mLaunchCameraOnFinishedGoingToSleep = false;
 
@@ -5800,8 +5802,10 @@
             if (!g.willBeRemoved() && !row.isRemoved()) {
                 mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
             }
-            mNotificationGutsExposed = null;
-            mGutsMenuItem = null;
+            if (mNotificationGutsExposed == g) {
+                mNotificationGutsExposed = null;
+                mGutsMenuItem = null;
+            }
         });
 
         View gutsView = item.getGutsView();
@@ -5897,7 +5901,8 @@
         final int centerY = done.getHeight() / 2;
         final int x = doneLocation[0] - rowLocation[0] + centerX;
         final int y = doneLocation[1] - rowLocation[1] + centerY;
-        dismissPopups(x, y);
+        closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
+                true /* removeControls */, x, y, true /* resetMenu */);
     }
 
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
@@ -5917,6 +5922,12 @@
                 if (row.isDark()) {
                     return false;
                 }
+                if (row.areGutsExposed()) {
+                    closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
+                            true /* removeControls */, -1 /* x */, -1 /* y */,
+                            true /* resetMenu */);
+                    return false;
+                }
                 bindGuts(row, item);
                 NotificationGuts guts = row.getGuts();
 
@@ -5926,12 +5937,6 @@
                     return false;
                 }
 
-                // Already showing?
-                if (guts.getVisibility() == View.VISIBLE) {
-                    dismissPopups(x, y);
-                    return false;
-                }
-
                 mMetricsLogger.action(MetricsEvent.ACTION_NOTE_CONTROLS);
 
                 // ensure that it's laid but not visible until actually laid out
@@ -5945,8 +5950,9 @@
                                     + "window");
                             return;
                         }
-                        dismissPopups(-1 /* x */, -1 /* y */, false /* resetMenu */,
-                                false /* animate */);
+                        closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
+                                true /* removeControls */, -1 /* x */, -1 /* y */,
+                                false /* resetMenu */);
                         guts.setVisibility(View.VISIBLE);
                         final double horz = Math.max(guts.getWidth() - x, x);
                         final double vert = Math.max(guts.getHeight() - y, y);
@@ -5986,20 +5992,23 @@
         return mNotificationGutsExposed;
     }
 
-    public void dismissPopups() {
-        dismissPopups(-1 /* x */, -1 /* y */, true /* resetMenu */, false /* animate */);
-    }
-
-    private void dismissPopups(int x, int y) {
-        dismissPopups(x, y, true /* resetMenu */, false /* animate */);
-    }
-
-    public void dismissPopups(int x, int y, boolean resetMenu, boolean animate) {
+    /**
+     * Closes guts or notification menus that might be visible and saves any changes.
+     *
+     * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
+     * @param force true if guts should be closed regardless of state (used for snooze only).
+     * @param removeControls true if controls (e.g. info) should be closed.
+     * @param x if closed based on touch location, this is the x touch location.
+     * @param y if closed based on touch location, this is the y touch location.
+     * @param resetMenu if any notification menus that might be revealed should be closed.
+     */
+    public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls,
+            int x, int y, boolean resetMenu) {
         if (mNotificationGutsExposed != null) {
-            mNotificationGutsExposed.closeControls(x, y, true /* save */);
+            mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
         }
         if (resetMenu) {
-            mStackScroller.resetExposedMenuView(animate, true /* force */);
+            mStackScroller.resetExposedMenuView(false /* animate */, true /* force */);
         }
     }
 
@@ -6528,7 +6537,8 @@
         if (mVisible != visible) {
             mVisible = visible;
             if (!visible) {
-                dismissPopups();
+                closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
+                        true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
             }
         }
         updateVisibleToUser();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 1a09d75..26e007c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -84,6 +85,8 @@
     private ActionMode mFloatingActionMode;
     private FloatingToolbar mFloatingToolbar;
     private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
+    private boolean mTouchCancelled;
+    private boolean mTouchActive;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -239,10 +242,20 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
-                && mNotificationPanel.isFullyCollapsed()) {
+        boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
+        if (isDown && mNotificationPanel.isFullyCollapsed()) {
             mNotificationPanel.startExpandLatencyTracking();
         }
+        if (isDown) {
+            mTouchActive = true;
+            mTouchCancelled = false;
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
+                || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+            mTouchActive = false;
+        }
+        if (mTouchCancelled) {
+            return false;
+        }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
             // Disallow new pointers while the brightness mirror is visible. This is so that you
@@ -252,7 +265,7 @@
                 return false;
             }
         }
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+        if (isDown) {
             mStackScrollLayout.closeControlsIfOutsideTouch(ev);
         }
         if (mService.isDozing()) {
@@ -349,6 +362,18 @@
         }
     }
 
+    public void cancelCurrentTouch() {
+        if (mTouchActive) {
+            final long now = SystemClock.uptimeMillis();
+            MotionEvent event = MotionEvent.obtain(now, now,
+                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            dispatchTouchEvent(event);
+            event.recycle();
+            mTouchCancelled = true;
+        }
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 15fcb38..5f83e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -75,6 +75,7 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationGuts;
 import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.NotificationSnooze;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -234,6 +235,7 @@
     private NotificationMenuRowPlugin mCurrMenuRow;
     private View mTranslatingParentView;
     private View mMenuExposedView;
+    boolean mCheckForLeavebehind;
 
     /**
      * Should in this touch motion only be scrolling allowed? It's true when the scroller was
@@ -1310,6 +1312,22 @@
                 && !mDisallowDismissInThisMotion) {
             horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
         }
+
+        // Check if we need to clear any snooze leavebehinds
+        NotificationGuts guts = mStatusBar.getExposedGuts();
+        if (guts != null && !isTouchInView(ev, guts)
+                && guts.getGutsContent() instanceof NotificationSnooze) {
+            NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
+            if ((ns.isExpanded() && isCancelOrUp)
+                    || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
+                // If the leavebehind is expanded we clear it on the next up event, otherwise we
+                // clear it on the next non-horizontal swipe or expand event.
+                checkSnoozeLeavebehind();
+            }
+        }
+        if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+            mCheckForLeavebehind = true;
+        }
         return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
     }
 
@@ -1429,6 +1447,8 @@
                         // existing overScroll, we have to scroll the view
                         customOverScrollBy((int) scrollAmount, mOwnScrollY,
                                 range, getHeight() / 2);
+                        // If we're scrolling, leavebehinds should be dismissed
+                        checkSnoozeLeavebehind();
                     }
                 }
                 break;
@@ -2458,6 +2478,18 @@
                 && !mDisallowDismissInThisMotion) {
             swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
         }
+        // Check if we need to clear any snooze leavebehinds
+        boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
+        NotificationGuts guts = mStatusBar.getExposedGuts();
+        if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt
+                && !scrollWantsIt) {
+            mCheckForLeavebehind = false;
+            mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
+                    false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+        }
+        if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+            mCheckForLeavebehind = true;
+        }
         return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
     }
 
@@ -3287,13 +3319,27 @@
         return Math.max(mMaxLayoutHeight - mContentHeight, 0);
     }
 
+    public void checkSnoozeLeavebehind() {
+        if (mCheckForLeavebehind) {
+            mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
+                    false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+            mCheckForLeavebehind = false;
+        }
+    }
+
+    public void resetCheckSnoozeLeavebehind() {
+        mCheckForLeavebehind = true;
+    }
+
     public void onExpansionStarted() {
         mIsExpansionChanging = true;
         mAmbientState.setExpansionChanging(true);
+        checkSnoozeLeavebehind();
     }
 
     public void onExpansionStopped() {
         mIsExpansionChanging = false;
+        resetCheckSnoozeLeavebehind();
         mAmbientState.setExpansionChanging(false);
         if (!mIsExpanded) {
             setOwnScrollY(0);
@@ -4292,6 +4338,8 @@
                 // of the panel early.
                 handleChildDismissed(view);
             }
+            mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
+                    false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
             handleMenuCoveredOrDismissed();
         }
 
@@ -4374,29 +4422,19 @@
         public void closeControlsIfOutsideTouch(MotionEvent ev) {
             NotificationGuts guts = mStatusBar.getExposedGuts();
             View view = null;
-            int height = 0;
-            if (guts != null) {
-                // Checking guts
+            if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+                // Only close visible guts if they're not a leavebehind.
                 view = guts;
-                height = guts.getActualHeight();
             } else if (mCurrMenuRow != null && mCurrMenuRow.isMenuVisible()
                     && mTranslatingParentView != null) {
                 // Checking menu
                 view = mTranslatingParentView;
-                height = ((ExpandableView) mTranslatingParentView).getActualHeight();
             }
-            if (view != null) {
-                final int rx = (int) ev.getRawX();
-                final int ry = (int) ev.getRawY();
-
-                view.getLocationOnScreen(mTempInt2);
-                final int x = mTempInt2[0];
-                final int y = mTempInt2[1];
-                Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
-                if (!rect.contains(rx, ry)) {
-                    // Touch was outside visible guts / meny notification, close what's visible
-                    mStatusBar.dismissPopups(-1, -1, true /* resetMenu */, true /* animate */);
-                }
+            if (view != null && !isTouchInView(ev, view)) {
+                // Touch was outside visible guts / menu notification, close what's visible
+                mStatusBar.closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
+                        true /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+                resetExposedMenuView(true /* animate */, true /* force */);
             }
         }
 
@@ -4420,6 +4458,23 @@
         }
     }
 
+    private boolean isTouchInView(MotionEvent ev, View view) {
+        if (view == null) {
+            return false;
+        }
+        final int height = (view instanceof ExpandableView)
+                ? ((ExpandableView) view).getActualHeight()
+                : view.getHeight();
+        final int rx = (int) ev.getRawX();
+        final int ry = (int) ev.getRawY();
+        view.getLocationOnScreen(mTempInt2);
+        final int x = mTempInt2[0];
+        final int y = mTempInt2[1];
+        Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+        boolean ret = rect.contains(rx, ry);
+        return ret;
+    }
+
     private void updateContinuousShadowDrawing() {
         boolean continuousShadowUpdate = mAnimationRunning
                 || !mAmbientState.getDraggedViews().isEmpty();
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index cd85a76..ae8afe4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -30,6 +30,7 @@
     public static String SCREENSHOTS = "SCN";
     public static String GENERAL     = "GEN";
     public static String STORAGE     = "DSK";
+    public static String TVPIP       = "TPP";
 
     @VisibleForTesting
     static void createAll(Context context) {
@@ -55,6 +56,15 @@
                                 ? NotificationManager.IMPORTANCE_DEFAULT
                                 : NotificationManager.IMPORTANCE_LOW)
                 ));
+        if (isTv(context)) {
+            // TV specific notification channel for TV PIP controls.
+            // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest
+            // priority, so it can be shown in all times.
+            nm.createNotificationChannel(new NotificationChannel(
+                    TVPIP,
+                    context.getString(R.string.notification_channel_tv_pip),
+                    NotificationManager.IMPORTANCE_MAX));
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 2b14b31..0531ec5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -497,7 +497,7 @@
                 mNotificationChannel.getImportance(), mSbn, null, null, null,
                 null, null);
 
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
     }
@@ -511,7 +511,7 @@
                 mNotificationChannel.getImportance(), mSbn, null, null, null,
                 null, null);
 
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
     }
@@ -571,7 +571,7 @@
                 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
                 mNotificationChannel.getImportance(), mSbn, null, null, null,
                 null, Collections.singleton(TEST_PACKAGE_NAME));
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 anyString(), anyInt(), any());
     }
@@ -586,7 +586,7 @@
 
         Switch enabledSwitch = mNotificationInfo.findViewById(R.id.channel_enabled_switch);
         enabledSwitch.setChecked(false);
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
 
         ArgumentCaptor<NotificationChannel> updated =
                 ArgumentCaptor.forClass(NotificationChannel.class);
@@ -606,7 +606,7 @@
 
         Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
         enabledSwitch.setChecked(false);
-        mNotificationInfo.handleCloseControls(false);
+        mNotificationInfo.handleCloseControls(false, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
     }
@@ -623,7 +623,7 @@
 
         Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
         enabledSwitch.setChecked(false);
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
     }
@@ -641,7 +641,7 @@
 
         Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
         enabledSwitch.setChecked(false);
-        mNotificationInfo.handleCloseControls(true);
+        mNotificationInfo.handleCloseControls(true, false);
         verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                 eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
     }
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 53b3fe9..2f6b7e6 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -212,6 +212,10 @@
     // Package: com.android.systemui
     NOTE_LOGOUT_USER = 1011;
 
+    // Notify the user that a TV PIP is running.
+    // Package: com.android.systemui
+    NOTE_TV_PIP = 1100;
+
     // Communicate to the user about remote bugreports.
     // Package: android
     NOTE_REMOTE_BUGREPORT = 678432343;
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 05ad161..238bf0f 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -2895,6 +2895,7 @@
             mAllocationArray[0] = createTyped(rs, t, usage);
             if ((usage & USAGE_IO_INPUT) != 0) {
                 if (numAlloc > MAX_NUMBER_IO_INPUT_ALLOC) {
+                    mAllocationArray[0].destroy();
                     throw new RSIllegalArgumentException("Exceeds the max number of Allocations allowed: " +
                                                          MAX_NUMBER_IO_INPUT_ALLOC);
                 }
diff --git a/rs/java/android/renderscript/ScriptIntrinsicLUT.java b/rs/java/android/renderscript/ScriptIntrinsicLUT.java
index 69ff64a..e90462d 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicLUT.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicLUT.java
@@ -56,6 +56,10 @@
 
     }
 
+    public void destroy() {
+        mTables.destroy();
+        super.destroy();
+    }
 
     private void validate(int index, int value) {
         if (index < 0 || index > 255) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 9081746..e3398c9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -118,7 +118,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                mUi.hideAll();
+                mUi.hideAll(null);
             }
         }
     };
@@ -470,9 +470,9 @@
         }
 
         @Override
-        public int startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
-                AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
-                boolean hasCallback, int flags, String packageName) {
+        public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
+                Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
+                String packageName) {
 
             activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
             appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -489,8 +489,8 @@
 
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-                return service.startSessionLocked(activityToken, getCallingUid(), windowToken,
-                        appCallback, autofillId, bounds, value, hasCallback, flags, packageName);
+                return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
+                        autofillId, bounds, value, hasCallback, flags, packageName);
             }
         }
 
@@ -528,19 +528,6 @@
         }
 
         @Override
-        public void setWindow(int sessionId, IBinder windowToken) throws RemoteException {
-            windowToken = Preconditions.checkNotNull(windowToken, "windowToken");
-
-            synchronized (mLock) {
-                final AutofillManagerServiceImpl service = mServicesCache.get(
-                        UserHandle.getCallingUserId());
-                if (service != null) {
-                    service.setWindow(sessionId, getCallingUid(), windowToken);
-                }
-            }
-        }
-
-        @Override
         public void updateSession(int sessionId, AutofillId id, Rect bounds,
                 AutofillValue value, int action, int flags, int userId) {
             synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 3ab8b8d..e315f9d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -263,7 +263,7 @@
         }
     }
 
-    int startSessionLocked(@NonNull IBinder activityToken, int uid, @Nullable IBinder windowToken,
+    int startSessionLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
             int flags, @NonNull String packageName) {
@@ -274,8 +274,8 @@
         // Occasionally clean up abandoned sessions
         pruneAbandonedSessionsLocked();
 
-        final Session newSession = createSessionByTokenLocked(activityToken, uid, windowToken,
-                appCallbackToken, hasCallback, flags, packageName);
+        final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
+                hasCallback, flags, packageName);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -359,8 +359,8 @@
     }
 
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
-            @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback,
-            int flags, @NonNull String packageName) {
+            @NonNull IBinder appCallbackToken, boolean hasCallback, int flags,
+            @NonNull String packageName) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -375,7 +375,7 @@
         } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
-                sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback,
+                sessionId, uid, activityToken, appCallbackToken, hasCallback,
                 mInfo.getServiceInfo().getComponentName(), packageName);
         mSessions.put(newSession.id, newSession);
 
@@ -402,24 +402,6 @@
         }
     }
 
-    /**
-     * Set the window the UI should get attached to
-     *
-     * @param sessionId The id of the session to restore
-     * @param uid UID of the process that tries to restore the session
-     * @param windowToken The window the activity is now in
-     */
-    boolean setWindow(int sessionId, int uid, @NonNull IBinder windowToken) {
-        final Session session = mSessions.get(sessionId);
-
-        if (session == null || uid != session.uid) {
-            return false;
-        } else {
-            session.switchWindow(windowToken);
-            return true;
-        }
-    }
-
     void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
             AutofillValue value, int action, int flags) {
         final Session session = mSessions.get(sessionId);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a98821d..3f78fb8 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -119,9 +119,6 @@
     @GuardedBy("mLock")
     @NonNull private IBinder mActivityToken;
 
-    @GuardedBy("mLock")
-    @NonNull private IBinder mWindowToken;
-
     /** Package name of the app that is auto-filled */
     @NonNull private final String mPackageName;
 
@@ -341,7 +338,7 @@
     Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
-            @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
+            @NonNull IBinder client, boolean hasCallback,
             @NonNull ComponentName componentName, @NonNull String packageName) {
         id = sessionId;
         this.uid = uid;
@@ -351,7 +348,6 @@
         mHandlerCaller = handlerCaller;
         mRemoteFillService = new RemoteFillService(context, componentName, userId, this);
         mActivityToken = activityToken;
-        mWindowToken = windowToken;
         mHasCallback = hasCallback;
         mPackageName = packageName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
@@ -369,23 +365,6 @@
     }
 
     /**
-     * Sets new window  for this session.
-     *
-     * @param newWindow The window the Ui should be attached to. Can be {@code null} if no
-     *                  further UI is needed.
-     */
-    void switchWindow(@NonNull IBinder newWindow) {
-        synchronized (mLock) {
-            if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#switchWindow() rejected - session: "
-                        + id + " destroyed");
-                return;
-            }
-            mWindowToken = newWindow;
-        }
-    }
-
-    /**
      * Sets new activity and client for this session.
      *
      * @param newActivity The token of the new activity
@@ -419,7 +398,7 @@
         }
         if (response == null) {
             if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
-                getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
+                getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
             }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient();
@@ -469,7 +448,7 @@
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
         mMetricsLogger.write(log);
 
-        getUiForShowing().showError(message);
+        getUiForShowing().showError(message, this);
         removeSelf();
     }
 
@@ -516,7 +495,7 @@
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
         mMetricsLogger.write(log);
 
-        getUiForShowing().showError(message);
+        getUiForShowing().showError(message, this);
         removeSelf();
     }
 
@@ -627,8 +606,8 @@
             if (id.equals(mCurrentViewId)) {
                 try {
                     final ViewState view = mViewStates.get(id);
-                    mClient.requestShowFillUi(this.id, mWindowToken, id, width, height,
-                            view.getVirtualBounds(), presenter);
+                    mClient.requestShowFillUi(this.id, id, width, height, view.getVirtualBounds(),
+                            presenter);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error requesting to show fill UI", e);
                 }
@@ -648,7 +627,7 @@
             // NOTE: We allow this call in a destroyed state as the UI is
             // asked to go away after we get destroyed, so let it do that.
             try {
-                mClient.requestHideFillUi(this.id, mWindowToken, id);
+                mClient.requestHideFillUi(this.id, id);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error requesting to hide fill UI", e);
             }
@@ -706,7 +685,7 @@
                         // refactor auth to support partitions; if it doesn't, we need to
                         // investigate it further (it can be reproduced by running
                         // LoginActivityTest.testFillResponseAuthServiceHasNoData())
-                        mUi.hideAll();
+                        mUi.hideAll(this);
                     }
                     processResponseLocked(response);
                 } else {
@@ -851,7 +830,8 @@
             }
             if (atLeastOneChanged) {
                 mService.setSaveShown();
-                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName);
+                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
+                        this);
 
                 mIsSaving = true;
                 return false;
@@ -1062,9 +1042,9 @@
 
                     //..and the UI
                     if (value.isText()) {
-                        getUiForShowing().filterFillUi(value.getTextValue().toString());
+                        getUiForShowing().filterFillUi(value.getTextValue().toString(), this);
                     } else {
-                        getUiForShowing().filterFillUi(null);
+                        getUiForShowing().filterFillUi(null, this);
                     }
                 }
                 break;
@@ -1076,7 +1056,7 @@
 
                 // Remove the UI if the ViewState has changed.
                 if (mCurrentViewId != viewState.id) {
-                    mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+                    mUi.hideFillUi(this);
                     mCurrentViewId = viewState.id;
                 }
 
@@ -1086,7 +1066,7 @@
             case ACTION_VIEW_EXITED:
                 if (mCurrentViewId == viewState.id) {
                     if (sVerbose) Slog.d(TAG, "Exiting view " + id);
-                    mUi.hideFillUi(viewState.id);
+                    mUi.hideFillUi(this);
                     mCurrentViewId = null;
                 }
                 break;
@@ -1123,7 +1103,7 @@
             filterText = value.getTextValue().toString();
         }
 
-        getUiForShowing().showFillUi(filledId, response, filterText, mPackageName);
+        getUiForShowing().showFillUi(filledId, response, filterText, mPackageName, this);
     }
 
     boolean isDestroyed() {
@@ -1142,10 +1122,9 @@
         synchronized (mLock) {
             if (!mHasCallback) return;
             try {
-                mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
+                mClient.notifyNoFillUi(id, mCurrentViewId);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
-                        + " id=" + mCurrentViewId, e);
+                Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
             }
         }
     }
@@ -1413,8 +1392,7 @@
             }
             try {
                 if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
-                mClient.autofill(id, mWindowToken, dataset.getFieldIds(),
-                        dataset.getFieldValues());
+                mClient.autofill(id, dataset.getFieldIds(), dataset.getFieldValues());
                 setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error autofilling activity: " + e);
@@ -1434,8 +1412,8 @@
             return;
         }
         mRemoteFillService.destroy();
-        mUi.hideAll();
-        mUi.setCallback(null);
+        mUi.hideAll(this);
+        mUi.clearCallback(this);
         mDestroyed = true;
         mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_FINISHED, mPackageName);
     }
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 7428460..9eaabfe2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -74,31 +74,43 @@
         mContext = context;
     }
 
-    public void setCallback(@Nullable AutoFillUiCallback callback) {
+    public void setCallback(@NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
             if (mCallback != callback) {
-                hideAllUiThread();
+                if (mCallback != null) {
+                    hideAllUiThread(mCallback);
+                }
+
                 mCallback = callback;
             }
         });
     }
 
+    public void clearCallback(@NonNull AutoFillUiCallback callback) {
+        mHandler.post(() -> {
+            if (mCallback == callback) {
+                hideAllUiThread(callback);
+                mCallback = null;
+            }
+        });
+    }
+
     /**
      * Displays an error message to the user.
      */
-    public void showError(int resId) {
-        showError(mContext.getString(resId));
+    public void showError(int resId, @NonNull AutoFillUiCallback callback) {
+        showError(mContext.getString(resId), callback);
     }
 
     /**
      * Displays an error message to the user.
      */
-    public void showError(@Nullable CharSequence message) {
+    public void showError(@Nullable CharSequence message, @NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (mCallback != callback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             if (!TextUtils.isEmpty(message)) {
                 Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
             }
@@ -108,8 +120,8 @@
     /**
      * Hides the fill UI.
      */
-    public void hideFillUi(AutofillId id) {
-        mHandler.post(this::hideFillUiUiThread);
+    public void hideFillUi(@NonNull AutoFillUiCallback callback) {
+        mHandler.post(() -> hideFillUiUiThread(callback));
     }
 
     /**
@@ -117,12 +129,12 @@
      *
      * @param filterText The filter prefix.
      */
-    public void filterFillUi(@Nullable String filterText) {
+    public void filterFillUi(@Nullable String filterText, @NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideSaveUiUiThread();
+            hideSaveUiUiThread(callback);
             if (mFillUi != null) {
                 mFillUi.setFilterText(filterText);
             }
@@ -136,9 +148,11 @@
      * @param response the current fill response
      * @param filterText text of the view to be filled
      * @param packageName package name of the activity that is filled
+     * @param callback Identifier for the caller
      */
     public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
-            @Nullable String filterText, @NonNull String packageName) {
+            @Nullable String filterText, @NonNull String packageName,
+            @NonNull AutoFillUiCallback callback) {
         if (sDebug) {
             Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + filterText);
         }
@@ -150,16 +164,16 @@
                         response.getDatasets() == null ? 0 : response.getDatasets().size());
 
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             mFillUi = new FillUi(mContext, response, focusedId,
                     filterText, new FillUi.Callback() {
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.authenticate(response.getRequestId(),
                                 response.getAuthentication(), response.getClientState());
@@ -169,7 +183,7 @@
                 @Override
                 public void onDatasetPicked(Dataset dataset) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.fill(response.getRequestId(), dataset);
                     }
@@ -178,7 +192,7 @@
                 @Override
                 public void onCanceled() {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                 }
 
                 @Override
@@ -218,7 +232,7 @@
      * Shows the UI asking the user to save for autofill.
      */
     public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
-            @NonNull String packageName) {
+            @NonNull String packageName, @NonNull AutoFillUiCallback callback) {
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
         numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
@@ -228,16 +242,16 @@
                         MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
 
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             mSaveUi = new SaveUi(mContext, providerLabel, info,
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
                     log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
-                    hideSaveUiUiThread();
+                    hideSaveUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.save();
                     }
@@ -246,7 +260,7 @@
                 @Override
                 public void onCancel(IntentSender listener) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
-                    hideSaveUiUiThread();
+                    hideSaveUiUiThread(callback);
                     if (listener != null) {
                         try {
                             listener.sendIntent(mContext, 0, null, null, null);
@@ -278,8 +292,8 @@
     /**
      * Hides all UI affordances.
      */
-    public void hideAll() {
-        mHandler.post(this::hideAllUiThread);
+    public void hideAll(@Nullable AutoFillUiCallback callback) {
+        mHandler.post(() -> hideAllUiThread(callback));
     }
 
     public void dump(PrintWriter pw) {
@@ -301,28 +315,24 @@
     }
 
     @android.annotation.UiThread
-    private void hideFillUiUiThread() {
-        if (mFillUi != null) {
+    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback) {
+        if (mFillUi != null && (callback == null || callback == mCallback)) {
             mFillUi.destroy();
             mFillUi = null;
         }
     }
 
     @android.annotation.UiThread
-    private void hideSaveUiUiThread() {
-        if (mSaveUi != null) {
+    private void hideSaveUiUiThread(@Nullable AutoFillUiCallback callback) {
+        if (mSaveUi != null && (callback == null || callback == mCallback)) {
             mSaveUi.destroy();
             mSaveUi = null;
         }
     }
 
     @android.annotation.UiThread
-    private void hideAllUiThread() {
-        hideFillUiUiThread();
-        hideSaveUiUiThread();
-    }
-
-    private boolean hasCallback() {
-        return mCallback != null;
+    private void hideAllUiThread(@Nullable AutoFillUiCallback callback) {
+        hideFillUiUiThread(callback);
+        hideSaveUiUiThread(callback);
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 268adc5..b5f8a09 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6945,7 +6945,7 @@
         }
 
         // Check whether the next backup agent is in this process...
-        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
+        if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
             if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                     "New app is backup target, launching agent for " + app);
             notifyPackageUse(mBackupTarget.appInfo.packageName,
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ba2c0cd..01fbdd4 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -249,6 +249,8 @@
     // Last configuration reported to the activity in the client process.
     private MergedConfiguration mLastReportedConfiguration;
     private int mLastReportedDisplayId;
+    private boolean mLastReportedMultiWindowMode;
+    private boolean mLastReportedPictureInPictureMode;
     CompatibilityInfo compat;// last used compatibility mode
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
@@ -289,10 +291,6 @@
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
-    private boolean mInMultiWindowMode; // whether or not this activity is currently in multi-window
-                                        // mode (default false)
-    private boolean mInPictureInPictureMode; // whether or not this activity is currently in
-                                             // picture-in-picture mode (default false)
     boolean supportsPictureInPictureWhilePausing;  // This flag is set by the system to indicate
         // that the activity can enter picture in picture while pausing (ie. only when another
         // task is brought to front or started)
@@ -535,6 +533,8 @@
         }
         if (info != null) {
             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+            pw.println(prefix + "mLastReportedMultiWindowMode=" + mLastReportedMultiWindowMode
+                    + " mLastReportedPictureInPictureMode=" + mLastReportedPictureInPictureMode);
             if (info.supportsPictureInPicture()) {
                 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());
                 pw.println(prefix + "supportsPictureInPictureWhilePausing: "
@@ -637,15 +637,15 @@
 
         // An activity is considered to be in multi-window mode if its task isn't fullscreen.
         final boolean inMultiWindowMode = !task.mFullscreen;
-        if (inMultiWindowMode != mInMultiWindowMode) {
-            mInMultiWindowMode = inMultiWindowMode;
+        if (inMultiWindowMode != mLastReportedMultiWindowMode) {
+            mLastReportedMultiWindowMode = inMultiWindowMode;
             scheduleMultiWindowModeChanged(getConfiguration());
         }
     }
 
     private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
         try {
-            app.thread.scheduleMultiWindowModeChanged(appToken, mInMultiWindowMode,
+            app.thread.scheduleMultiWindowModeChanged(appToken, mLastReportedMultiWindowMode,
                     overrideConfig);
         } catch (Exception e) {
             // If process died, I don't care.
@@ -659,11 +659,11 @@
 
         final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) &&
                 (targetStackBounds != null);
-        if (inPictureInPictureMode != mInPictureInPictureMode) {
+        if (inPictureInPictureMode != mLastReportedPictureInPictureMode) {
             // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
             // update that here in order
-            mInPictureInPictureMode = inPictureInPictureMode;
-            mInMultiWindowMode = inPictureInPictureMode;
+            mLastReportedPictureInPictureMode = inPictureInPictureMode;
+            mLastReportedMultiWindowMode = inPictureInPictureMode;
             final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
                     targetStackBounds, null);
             schedulePictureInPictureModeChanged(newConfig);
@@ -673,7 +673,8 @@
 
     private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
         try {
-            app.thread.schedulePictureInPictureModeChanged(appToken, mInPictureInPictureMode,
+            app.thread.schedulePictureInPictureModeChanged(appToken,
+                    mLastReportedPictureInPictureMode,
                     overrideConfig);
         } catch (Exception e) {
             // If process died, no one cares.
@@ -940,6 +941,12 @@
 
         task.addActivityToTop(this);
 
+        // When an activity is started directly into a split-screen fullscreen stack, we need to
+        // update the initial multi-window modes so that the callbacks are scheduled correctly when
+        // the user leaves that mode.
+        mLastReportedMultiWindowMode = !task.mFullscreen;
+        mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID);
+
         onOverrideConfigurationSent();
     }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 983c975..7a46248 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -966,6 +966,14 @@
     }
 
     @Override
+    public void noteBleScanResult(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteBluetoothScanResultFromSourceLocked(ws);
+        }
+    }
+
+    @Override
     public void noteWifiControllerActivity(WifiActivityEnergyInfo info) {
         enforceCallingPermission();
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 9b984c1..6f5b028 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,21 +16,20 @@
 
 package com.android.server.fingerprint;
 
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 
-import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.SynchronousUserSwitchObserver;
-import android.content.ComponentName;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -82,10 +81,10 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.LinkedList;
 
 /**
  * A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -400,6 +399,10 @@
         ClientMonitor client = mCurrentClient;
         if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
             removeClient(client);
+            // When the last fingerprint of a group is removed, update the authenticator id
+            if (!hasEnrolledFingerprints(groupId)) {
+                updateActiveGroup(groupId, null);
+            }
         }
         if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
             cleanupUnknownFingerprints();
@@ -446,6 +449,9 @@
         ClientMonitor client = mCurrentClient;
         if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
             removeClient(client);
+            // When enrollment finishes, update this group's authenticator id, as the HAL has
+            // already generated a new authenticator id when the new fingerprint is enrolled.
+            updateActiveGroup(groupId, null);
         }
     }
 
@@ -1382,7 +1388,8 @@
                     daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
                     mCurrentUserId = userId;
                 }
-                mAuthenticatorIds.put(userId, daemon.getAuthenticatorId());
+                mAuthenticatorIds.put(userId,
+                        hasEnrolledFingerprints(userId) ? daemon.getAuthenticatorId() : 0L);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveGroup():", e);
             }
@@ -1436,7 +1443,6 @@
      */
     public long getAuthenticatorId(String opPackageName) {
         final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
-        Long authenticatorId = mAuthenticatorIds.get(userId);
-        return authenticatorId != null ? authenticatorId : 0;
+        return mAuthenticatorIds.getOrDefault(userId, 0L);
     }
 }
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 09e9433..aa780cc 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -80,19 +80,23 @@
     }
 
     public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(int hashPrefix[],
-            String token) {
+            String token) throws ConnectionException {
         throwIfCalledOnMainThread();
         IInstantAppResolver target = null;
         try {
-            target = getRemoteInstanceLazy(token);
-            return mGetEphemeralResolveInfoCaller
-                    .getEphemeralResolveInfoList(target, hashPrefix, token);
-        } catch (RemoteException e) {
-        } catch (InterruptedException | TimeoutException e) {
-            if (target == null) {
-                Slog.w(TAG, "[" + token + "] Timeout! Phase1 binding to instant app resolver");
-            } else {
-                Slog.w(TAG, "[" + token + "] Timeout! Phase1 resolving instant app");
+            try {
+                target = getRemoteInstanceLazy(token);
+            } catch (TimeoutException e) {
+                throw new ConnectionException(ConnectionException.FAILURE_BIND);
+            } catch (InterruptedException e) {
+                throw new ConnectionException(ConnectionException.FAILURE_INTERRUPTED);
+            }
+            try {
+                return mGetEphemeralResolveInfoCaller
+                        .getEphemeralResolveInfoList(target, hashPrefix, token);
+            } catch (TimeoutException e) {
+                throw new ConnectionException(ConnectionException.FAILURE_BIND);
+            } catch (RemoteException ignore) {
             }
         } finally {
             synchronized (mLock) {
@@ -104,7 +108,7 @@
 
     public final void getInstantAppIntentFilterList(int hashPrefix[], String token,
             String hostName, PhaseTwoCallback callback, Handler callbackHandler,
-            final long startTime) {
+            final long startTime) throws ConnectionException {
         final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() {
             @Override
             public void sendResult(Bundle data) throws RemoteException {
@@ -122,14 +126,16 @@
         try {
             getRemoteInstanceLazy(token)
                     .getInstantAppIntentFilterList(hashPrefix, token, hostName, remoteCallback);
-        } catch (RemoteException e) {
-        } catch (InterruptedException | TimeoutException e) {
-            Slog.w(TAG, "[" + token + "] Timeout! Phase2 binding to instant app resolver");
+        } catch (TimeoutException e) {
+            throw new ConnectionException(ConnectionException.FAILURE_BIND);
+        } catch (InterruptedException e) {
+            throw new ConnectionException(ConnectionException.FAILURE_INTERRUPTED);
+        } catch (RemoteException ignore) {
         }
     }
 
     private IInstantAppResolver getRemoteInstanceLazy(String token)
-            throws TimeoutException, InterruptedException {
+            throws ConnectionException, TimeoutException, InterruptedException {
         synchronized (mLock) {
             if (mRemoteInstance != null) {
                 return mRemoteInstance;
@@ -139,7 +145,7 @@
         }
     }
 
-    private void waitForBind(String token) throws TimeoutException, InterruptedException {
+    private void waitForBindLocked(String token) throws TimeoutException, InterruptedException {
         final long startMillis = SystemClock.uptimeMillis();
         while (mIsBinding) {
             if (mRemoteInstance != null) {
@@ -154,12 +160,13 @@
         }
     }
 
-    private void bindLocked(String token) throws TimeoutException, InterruptedException {
+    private void bindLocked(String token)
+            throws ConnectionException, TimeoutException, InterruptedException {
         if (DEBUG_EPHEMERAL && mIsBinding && mRemoteInstance == null) {
             Slog.i(TAG, "[" + token + "] Previous bind timed out; waiting for connection");
         }
         try {
-            waitForBind(token);
+            waitForBindLocked(token);
         } catch (TimeoutException e) {
             if (DEBUG_EPHEMERAL) {
                 Slog.i(TAG, "[" + token + "] Previous connection never established; rebinding");
@@ -179,9 +186,10 @@
             wasBound = mContext
                     .bindServiceAsUser(mIntent, mServiceConnection, flags, UserHandle.SYSTEM);
             if (wasBound) {
-                waitForBind(token);
+                waitForBindLocked(token);
             } else {
                 Slog.w(TAG, "[" + token + "] Failed to bind to: " + mIntent);
+                throw new ConnectionException(ConnectionException.FAILURE_BIND);
             }
         } finally {
             mIsBinding = wasBound && mRemoteInstance == null;
@@ -222,6 +230,17 @@
                 List<InstantAppResolveInfo> instantAppResolveInfoList, long startTime);
     }
 
+    public static class ConnectionException extends Exception {
+        public static final int FAILURE_BIND = 1;
+        public static final int FAILURE_CALL = 2;
+        public static final int FAILURE_INTERRUPTED = 3;
+
+        public final int failure;
+        public ConnectionException(int _failure) {
+            failure = _failure;
+        }
+    }
+
     private final class MyServiceConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index f3c9cbb..85be4a2 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -22,6 +22,7 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_RESOLUTION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_RESOLUTION_STATUS;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -50,20 +51,37 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.pm.EphemeralResolverConnection.ConnectionException;
 import com.android.server.pm.EphemeralResolverConnection.PhaseTwoCallback;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.TimeoutException;
 
 /** @hide */
 public abstract class InstantAppResolver {
     private static final boolean DEBUG_EPHEMERAL = Build.IS_DEBUGGABLE;
     private static final String TAG = "PackageManager";
 
-    private static int RESOLUTION_SUCCESS = 0;
-    private static int RESOLUTION_FAILURE = 1;
+    private static final int RESOLUTION_SUCCESS = 0;
+    private static final int RESOLUTION_FAILURE = 1;
+    /** Binding to the external service timed out */
+    private static final int RESOLUTION_BIND_TIMEOUT = 2;
+    /** The call to retrieve an instant application response timed out */
+    private static final int RESOLUTION_CALL_TIMEOUT = 3;
+
+    @IntDef(flag = true, prefix = { "RESOLUTION_" }, value = {
+            RESOLUTION_SUCCESS,
+            RESOLUTION_FAILURE,
+            RESOLUTION_BIND_TIMEOUT,
+            RESOLUTION_CALL_TIMEOUT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResolutionStatus {}
 
     private static MetricsLogger sMetricsLogger;
     private static MetricsLogger getLogger() {
@@ -78,29 +96,43 @@
         final long startTime = System.currentTimeMillis();
         final String token = UUID.randomUUID().toString();
         if (DEBUG_EPHEMERAL) {
-            Log.d(TAG, "[" + token + "] Resolving phase 1");
+            Log.d(TAG, "[" + token + "] Phase1; resolving");
         }
         final Intent intent = requestObj.origIntent;
         final InstantAppDigest digest =
                 new InstantAppDigest(intent.getData().getHost(), 5 /*maxDigests*/);
         final int[] shaPrefix = digest.getDigestPrefix();
-        final List<InstantAppResolveInfo> instantAppResolveInfoList =
-                connection.getInstantAppResolveInfoList(shaPrefix, token);
-
-        if (instantAppResolveInfoList == null || instantAppResolveInfoList.size() == 0) {
-            // No hash prefix match; there are no instant apps for this domain.
-            if (DEBUG_EPHEMERAL) {
-                Log.d(TAG, "[" + token + "] No results returned");
+        AuxiliaryResolveInfo resolveInfo = null;
+        @ResolutionStatus int resolutionStatus = RESOLUTION_SUCCESS;
+        try {
+            final List<InstantAppResolveInfo> instantAppResolveInfoList =
+                    connection.getInstantAppResolveInfoList(shaPrefix, token);
+            if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
+                resolveInfo = InstantAppResolver.filterInstantAppIntent(
+                        instantAppResolveInfoList, intent, requestObj.resolvedType,
+                        requestObj.userId, intent.getPackage(), digest, token);
             }
-            return null;
+        } catch (ConnectionException e) {
+            if (e.failure == ConnectionException.FAILURE_BIND) {
+                resolutionStatus = RESOLUTION_BIND_TIMEOUT;
+            } else if (e.failure == ConnectionException.FAILURE_CALL) {
+                resolutionStatus = RESOLUTION_CALL_TIMEOUT;
+            } else {
+                resolutionStatus = RESOLUTION_FAILURE;
+            }
         }
-        final AuxiliaryResolveInfo resolveInfo = InstantAppResolver.filterInstantAppIntent(
-                instantAppResolveInfoList, intent, requestObj.resolvedType, requestObj.userId,
-                intent.getPackage(), digest, token);
         logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
-                RESOLUTION_SUCCESS);
+                resolutionStatus);
         if (DEBUG_EPHEMERAL && resolveInfo == null) {
-            Log.d(TAG, "[" + token + "] No results matched");
+            if (resolutionStatus == RESOLUTION_BIND_TIMEOUT) {
+                Log.d(TAG, "[" + token + "] Phase1; bind timed out");
+            } else if (resolutionStatus == RESOLUTION_CALL_TIMEOUT) {
+                Log.d(TAG, "[" + token + "] Phase1; call timed out");
+            } else if (resolutionStatus != RESOLUTION_SUCCESS) {
+                Log.d(TAG, "[" + token + "] Phase1; service connection error");
+            } else {
+                Log.d(TAG, "[" + token + "] Phase1; No results matched");
+            }
         }
         return resolveInfo;
     }
@@ -111,7 +143,7 @@
         final long startTime = System.currentTimeMillis();
         final String token = requestObj.responseObj.token;
         if (DEBUG_EPHEMERAL) {
-            Log.d(TAG, "[" + token + "] Resolving phase 2");
+            Log.d(TAG, "[" + token + "] Phase2; resolving");
         }
         final Intent intent = requestObj.origIntent;
         final String hostName = intent.getData().getHost();
@@ -170,8 +202,24 @@
                 context.startActivity(installerIntent);
             }
         };
-        connection.getInstantAppIntentFilterList(
-                shaPrefix, token, hostName, callback, callbackHandler, startTime);
+        try {
+            connection.getInstantAppIntentFilterList(
+                    shaPrefix, token, hostName, callback, callbackHandler, startTime);
+        } catch (ConnectionException e) {
+            @ResolutionStatus int resolutionStatus = RESOLUTION_FAILURE;
+            if (e.failure == ConnectionException.FAILURE_BIND) {
+                resolutionStatus = RESOLUTION_BIND_TIMEOUT;
+            }
+            logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO, startTime, token,
+                    resolutionStatus);
+            if (DEBUG_EPHEMERAL) {
+                if (resolutionStatus == RESOLUTION_BIND_TIMEOUT) {
+                    Log.d(TAG, "[" + token + "] Phase2; bind timed out");
+                } else {
+                    Log.d(TAG, "[" + token + "] Phase2; service connection error");
+                }
+            }
+        }
     }
 
     /**
@@ -322,7 +370,8 @@
         return null;
     }
 
-    private static void logMetrics(int action, long startTime, String token, int status) {
+    private static void logMetrics(int action, long startTime, String token,
+            @ResolutionStatus int status) {
         final LogMaker logMaker = new LogMaker(action)
                 .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
                 .addTaggedData(FIELD_INSTANT_APP_RESOLUTION_DELAY_MS,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f0ae1a7..6aff600 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5485,7 +5485,8 @@
                 // Maintain fullscreen layout until incoming animation is complete.
                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
                 // Transient status bar on the lockscreen is not allowed
-                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
+                if ((mForceStatusBarFromKeyguard || statusBarExpanded)
+                        && mStatusBarController.isTransientShowing()) {
                     mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
                             mLastSystemUiFlags, mLastSystemUiFlags);
                 }
diff --git a/services/core/java/com/android/server/text/TextClassificationService.java b/services/core/java/com/android/server/text/TextClassificationService.java
deleted file mode 100644
index 9358238..0000000
--- a/services/core/java/com/android/server/text/TextClassificationService.java
+++ /dev/null
@@ -1,71 +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.server.text;
-
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.text.ITextClassificationService;
-import android.util.Slog;
-
-import com.android.server.SystemService;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-/**
- * Text classification service.
- * This is used to provide access to the text classification LSTM model file.
- */
-public class TextClassificationService extends ITextClassificationService.Stub {
-
-    private static final String LOG_TAG = "TextClassificationService";
-
-    public static final class Lifecycle extends SystemService {
-
-        private TextClassificationService mService;
-
-        public Lifecycle(Context context) {
-            super(context);
-            mService = new TextClassificationService();
-        }
-
-        @Override
-        public void onStart() {
-            try {
-                publishBinderService(Context.TEXT_CLASSIFICATION_SERVICE, mService);
-            } catch (Throwable t) {
-                // Starting this service is not critical to the running of this device and should
-                // therefore not crash the device. If it fails, log the error and continue.
-                Slog.e(LOG_TAG, "Could not start the TextClassificationService.", t);
-            }
-        }
-    }
-
-    @Override
-    public synchronized ParcelFileDescriptor getModelFileFd() throws RemoteException {
-        try {
-            return ParcelFileDescriptor.open(
-                    new File("/etc/assistant/smart-selection.model"),
-                    ParcelFileDescriptor.MODE_READ_ONLY);
-        } catch (Throwable t) {
-            Slog.e(LOG_TAG, "Error retrieving an fd to the text classification model file.", t);
-            throw new RemoteException(t.getMessage());
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 92d26cb..257f285 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -759,16 +759,25 @@
         return token.asAppWindowToken();
     }
 
-    void addWindowToken(IBinder binder, WindowToken token) {
+    private void addWindowToken(IBinder binder, WindowToken token) {
         final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
         if (dc != null) {
             // We currently don't support adding a window token to the display if the display
             // already has the binder mapped to another token. If there is a use case for supporting
             // this moving forward we will either need to merge the WindowTokens some how or have
             // the binder map to a list of window tokens.
-            throw new IllegalArgumentException("Can't map token=" + token + " to display=" + this
-                    + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
+            throw new IllegalArgumentException("Can't map token=" + token + " to display="
+                    + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
         }
+        if (binder == null) {
+            throw new IllegalArgumentException("Can't map token=" + token + " to display="
+                    + getName() + " binder is null");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("Can't map null token to display="
+                    + getName() + " binder=" + binder);
+        }
+
         mTokenMap.put(binder, token);
 
         if (token.asAppWindowToken() == null) {
@@ -1503,16 +1512,8 @@
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
-    /**
-     * 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) {
+    @Override
+    int getOrientation() {
         final WindowManagerPolicy policy = mService.mPolicy;
 
         if (mService.mDisplayFrozen) {
@@ -1541,14 +1542,8 @@
             }
         }
 
-        // 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 */);
+        // Top system windows are not requesting an orientation. Start searching from apps.
+        return mTaskStackContainers.getOrientation();
     }
 
     void updateDisplayInfo() {
@@ -2499,7 +2494,8 @@
     void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade) {
         final WindowManagerPolicy policy = mService.mPolicy;
         forAllWindows(w -> {
-            if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)) {
+            if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
+                    && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
                 w.mWinAnimator.setAnimation(
                         policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a48397b..63cc9bf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1239,7 +1239,8 @@
                         return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                     }
                 }
-                token = new WindowToken(this, attrs.token, type, false, displayContent,
+                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
+                token = new WindowToken(this, binder, type, false, displayContent,
                         session.mCanAddInternalSystemWindow);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
@@ -1310,7 +1311,7 @@
                 // It is not valid to use an app token with other system types; we will
                 // instead make a new token for it (as if null had been passed in for the token).
                 attrs.token = null;
-                token = new WindowToken(this, null, type, false, displayContent,
+                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
                         session.mCanAddInternalSystemWindow);
             }
 
@@ -2373,7 +2374,7 @@
         try {
             synchronized(mWindowMap) {
                 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
-                        displayId, true /* includeAppContainers */);
+                        displayId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2384,13 @@
     }
 
     private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
+            IBinder freezeThisOneIfNeeded, int displayId) {
         if (!mDisplayReady) {
             return null;
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
+        if (updateOrientationFromAppTokensLocked(false, displayId)) {
             // 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,11 +2428,6 @@
         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
@@ -2442,25 +2438,13 @@
      * 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)
      */
-    private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
-            boolean includeAppContainers) {
-        final long ident = Binder.clearCallingIdentity();
+    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+        long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
-            final int req = dc.getOrientation(includeAppContainers);
+            final int req = dc.getOrientation();
             if (req != dc.getLastOrientation()) {
                 dc.setLastOrientation(req);
                 //send a message to Policy indicating orientation change to take
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 67516c1..25b6561 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1292,36 +1292,14 @@
 
     @Override
     boolean isVisible() {
-        // TODO: The check for hiddenRequested is commented out below, because the window can still
-        // be visible on screen when the flag is true. We would like the isVisible() method to
-        // return an answer closer to if the window is truly visible (can't be an exact answer
-        // without checking the surface state), so comment out the check for now so we can test to
-        // see what problem it causes.
-        // If it doesn't cause any issues, then we can remove just before we lock down the current
-        // release (O) and also consolidate this method with #isVisibleUnchecked() and possibly
-        // other methods like isVisibleNow().
-        // If it does cause problems, then we can look if there are other ways to solve the problem.
-        // If there isn't then uncomment and document here why it is needed.
-        if (/*(mAppToken == null || !mAppToken.hiddenRequested) && */isVisibleUnchecked()
-            // TODO: The window isn't considered visible when the token is hidden, however
-            // uncommenting the check below breaks the visual transition from an app to the launcher
-            // if the home buttons is pressed. Need to investigate an fix that issue before
-            // uncommenting.
-            /* && !mToken.hidden*/) {
-            // Is this window visible?  It is not visible if there is no surface, or we are in the
-            // process of running an exit animation that will remove the surface, or its app token
-            // has been hidden.
-            return true;
-        }
-        return false;
+        return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility;
     }
 
     /**
-     * Does the minimal check for visibility. Callers generally want to use one of the public
-     * methods as they perform additional checks on the app token.
-     * TODO: See if there are other places we can use this check below instead of duplicating...
+     * @return True if the window would be visible if we'd ignore policy visibility, false
+     *         otherwise.
      */
-    private boolean isVisibleUnchecked() {
+    boolean wouldBeVisibleIfPolicyIgnored() {
         return mHasSurface && mPolicyVisibility && !isParentWindowHidden()
                 && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
     }
@@ -1338,7 +1316,7 @@
     // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this?
     boolean isWinVisibleLw() {
         return (mAppToken == null || !mAppToken.hiddenRequested || mAppToken.mAppAnimator.animating)
-                && isVisibleUnchecked();
+                && isVisible();
     }
 
     /**
@@ -1347,7 +1325,7 @@
      */
     boolean isVisibleNow() {
         return (!mToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
-                && isVisibleUnchecked();
+                && isVisible();
     }
 
     /**
@@ -2063,7 +2041,7 @@
             // If app died visible, apply a dim over the window to indicate that it's inactive
             dc.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
         } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
-                && dc != null && !mAnimatingExit && isVisibleUnchecked()) {
+                && dc != null && !mAnimatingExit && isVisible()) {
             dc.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
         }
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 978803d..0965f03 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -104,7 +104,6 @@
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
-import com.android.server.text.TextClassificationService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.tv.TvRemoteService;
@@ -1042,12 +1041,6 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartTextClassificationService");
-                mSystemServiceManager.startService(TextClassificationService.Lifecycle.class);
-                traceEnd();
-            }
-
             if (!disableNetwork) {
                 traceBeginAndSlog("StartNetworkScoreService");
                 try {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
index ace65a6..02f645a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java
@@ -54,6 +54,7 @@
     private static int OTHER_VIEW_ID = 0xCAB2;
     private static int PARENT_VIEW_ID = 0xFED4;
     private static int CHILD_VIEW_ID = 0xFEED;
+    private static int OTHER_CHILD_VIEW_ID = 0xACE2;
     private static int MOCK_CONNECTION_ID = 1;
 
     AccessibilityCache mAccessibilityCache;
@@ -482,6 +483,30 @@
     }
 
     @Test
+    public void addNode_whenNodeBeingReplacedIsOwnGrandparent_doesntCrash() {
+        AccessibilityNodeInfo parentNodeInfo =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(CHILD_VIEW_ID, WINDOW_ID_1));
+        parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(OTHER_CHILD_VIEW_ID, WINDOW_ID_1));
+        AccessibilityNodeInfo childNodeInfo =
+                getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
+        childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+        childNodeInfo.addChild(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
+
+        AccessibilityNodeInfo replacementParentNodeInfo =
+                getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1);
+        try {
+            mAccessibilityCache.add(parentNodeInfo);
+            mAccessibilityCache.add(childNodeInfo);
+            mAccessibilityCache.add(replacementParentNodeInfo);
+        } finally {
+            parentNodeInfo.recycle();
+            childNodeInfo.recycle();
+            replacementParentNodeInfo.recycle();
+        }
+    }
+
+    @Test
     public void testCacheCriticalEventList_doesntLackEvents() {
         for (int i = 0; i < 32; i++) {
             int eventType = 1 << i;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 47ced99..d9349ed 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -66,8 +66,7 @@
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
             int userId) {
-        final Task newTask = new Task(WindowTestUtils.sNextTaskId++, stack, userId, service, null,
-                EMPTY, 0, false,
+        final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, EMPTY, 0, false,
                 false, new ActivityManager.TaskDescription(), null);
         stack.addTask(newTask, POSITION_TOP);
         return newTask;
@@ -92,7 +91,7 @@
     public static class TestAppWindowToken extends AppWindowToken {
 
         TestAppWindowToken(DisplayContent dc) {
-            super(dc.mService, null, false, dc, true /* fillsParent */,
+            super(dc.mService, new IApplicationToken.Stub() {}, false, dc, true /* fillsParent */,
                     null /* overrideConfig */, null /* bounds */);
         }
 
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 7cb176d..eddcbda 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -855,7 +855,7 @@
                         if (!mConnected) {
                             // restore defaults when USB is disconnected
                             Slog.i(TAG, "Disconnect, setting usb functions to null");
-                            setEnabledFunctions(null, false, false);
+                            setEnabledFunctions(null, true, false);
                         }
                         updateUsbFunctions();
                     } else {
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java
similarity index 99%
rename from core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
rename to tests/net/java/android/net/NetworkStatsHistoryTest.java
index 9a08f41..e7b91b5 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/tests/net/java/android/net/NetworkStatsHistoryTest.java
@@ -38,7 +38,7 @@
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.tests.net.R;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/NetworkStatsTest.java
rename to tests/net/java/android/net/NetworkStatsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
similarity index 99%
rename from core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
rename to tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index 7f13abc..978e5f5 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -30,7 +30,7 @@
 import android.net.TrafficStats;
 import android.test.AndroidTestCase;
 
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.tests.net.R;
 
 import java.io.File;
 import java.io.FileOutputStream;
diff --git a/core/tests/coretests/res/raw/history_v1 b/tests/net/res/raw/history_v1
similarity index 100%
rename from core/tests/coretests/res/raw/history_v1
rename to tests/net/res/raw/history_v1
Binary files differ
diff --git a/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical b/tests/net/res/raw/xt_qtaguid_iface_fmt_typical
similarity index 100%
rename from core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical
rename to tests/net/res/raw/xt_qtaguid_iface_fmt_typical
diff --git a/core/tests/coretests/res/raw/xt_qtaguid_iface_typical b/tests/net/res/raw/xt_qtaguid_iface_typical
similarity index 100%
rename from core/tests/coretests/res/raw/xt_qtaguid_iface_typical
rename to tests/net/res/raw/xt_qtaguid_iface_typical
diff --git a/core/tests/coretests/res/raw/xt_qtaguid_typical b/tests/net/res/raw/xt_qtaguid_typical
similarity index 100%
rename from core/tests/coretests/res/raw/xt_qtaguid_typical
rename to tests/net/res/raw/xt_qtaguid_typical
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index ce84993..064d365 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -402,4 +402,22 @@
   EXPECT_EQ(nullptr, Verify(input));
 }
 
+TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
+  std::string input = R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android">
+        <special:tag whoo="true" xmlns:special="http://google.com" />
+      </manifest>)EOF";
+  EXPECT_NE(nullptr, Verify(input));
+}
+
+TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
+  std::string input = R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android">
+        <tag whoo="true" />
+      </manifest>)EOF";
+  EXPECT_EQ(nullptr, Verify(input));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index 7580b46..352a933 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -19,8 +19,7 @@
 namespace aapt {
 namespace xml {
 
-static bool wrapper_one(XmlNodeAction::ActionFunc& f, Element* el,
-                        SourcePathDiagnostics*) {
+static bool wrapper_one(XmlNodeAction::ActionFunc& f, Element* el, SourcePathDiagnostics*) {
   return f(el);
 }
 
@@ -47,8 +46,8 @@
   *msg << el->name << ">";
 }
 
-bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy,
-                            SourcePathDiagnostics* diag, Element* el) const {
+bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
+                            Element* el) const {
   bool error = false;
   for (const ActionFuncWithDiag& action : actions_) {
     error |= !action(el, diag);
@@ -56,28 +55,27 @@
 
   for (Element* child_el : el->GetChildElements()) {
     if (child_el->namespace_uri.empty()) {
-      std::map<std::string, XmlNodeAction>::const_iterator iter =
-          map_.find(child_el->name);
+      std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name);
       if (iter != map_.end()) {
         error |= !iter->second.Execute(policy, diag, child_el);
         continue;
       }
-    }
 
-    if (policy == XmlActionExecutorPolicy::kWhitelist) {
-      DiagMessage error_msg(child_el->line_number);
-      error_msg << "unknown element ";
-      PrintElementToDiagMessage(child_el, &error_msg);
-      error_msg << " found";
-      diag->Error(error_msg);
-      error = true;
+      if (policy == XmlActionExecutorPolicy::kWhitelist) {
+        DiagMessage error_msg(child_el->line_number);
+        error_msg << "unknown element ";
+        PrintElementToDiagMessage(child_el, &error_msg);
+        error_msg << " found";
+        diag->Error(error_msg);
+        error = true;
+      }
     }
   }
   return !error;
 }
 
-bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy,
-                                IDiagnostics* diag, XmlResource* doc) const {
+bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
+                                XmlResource* doc) const {
   SourcePathDiagnostics source_diag(doc->file.source, diag);
 
   Element* el = FindRootElement(doc);
@@ -90,20 +88,19 @@
   }
 
   if (el->namespace_uri.empty()) {
-    std::map<std::string, XmlNodeAction>::const_iterator iter =
-        map_.find(el->name);
+    std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name);
     if (iter != map_.end()) {
       return iter->second.Execute(policy, &source_diag, el);
     }
-  }
 
-  if (policy == XmlActionExecutorPolicy::kWhitelist) {
-    DiagMessage error_msg(el->line_number);
-    error_msg << "unknown element ";
-    PrintElementToDiagMessage(el, &error_msg);
-    error_msg << " found";
-    source_diag.Error(error_msg);
-    return false;
+    if (policy == XmlActionExecutorPolicy::kWhitelist) {
+      DiagMessage error_msg(el->line_number);
+      error_msg << "unknown element ";
+      PrintElementToDiagMessage(el, &error_msg);
+      error_msg << " found";
+      source_diag.Error(error_msg);
+      return false;
+    }
   }
   return true;
 }
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 68e3563..1d70045 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -31,17 +31,12 @@
 namespace xml {
 
 enum class XmlActionExecutorPolicy {
-  /**
-   * Actions on run if elements are matched, errors occur only when actions
-   * return false.
-   */
+  // Actions are run if elements are matched, errors occur only when actions return false.
   kNone,
 
-  /**
-   * The actions defined must match and run. If an element is found that does
-   * not match
-   * an action, an error occurs.
-   */
+  // The actions defined must match and run. If an element is found that does
+  // not match an action, an error occurs.
+  // Note: namespaced elements are always ignored.
   kWhitelist,
 };
 
@@ -52,14 +47,12 @@
  */
 class XmlNodeAction {
  public:
-  using ActionFuncWithDiag =
-      std::function<bool(Element*, SourcePathDiagnostics*)>;
+  using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
   using ActionFunc = std::function<bool(Element*)>;
 
   /**
    * Find or create a child XmlNodeAction that will be performed for the child
-   * element
-   * with the name `name`.
+   * element with the name `name`.
    */
   XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
 
@@ -72,8 +65,7 @@
  private:
   friend class XmlActionExecutor;
 
-  bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
-               Element* el) const;
+  bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
 
   std::map<std::string, XmlNodeAction> map_;
   std::vector<ActionFuncWithDiag> actions_;
@@ -98,8 +90,7 @@
    * Execute the defined actions for this XmlResource.
    * Returns true if all actions return true, otherwise returns false.
    */
-  bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
-               XmlResource* doc) const;
+  bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
 
  private:
   std::map<std::string, XmlNodeAction> map_;