Merge "Expose NR State string method for use in RadioInfo" into rvc-d1-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9b290c6..2fd2e33 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -12,6 +12,8 @@
                services/incremental/
 
 [Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+
 strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
 
 hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0e10c42..0eb3c1e 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -38,7 +38,9 @@
  * Representation of a MAC address.
  *
  * This class only supports 48 bits long addresses and does not support 64 bits long addresses.
- * Instances of this class are immutable.
+ * Instances of this class are immutable. This class provides implementations of hashCode()
+ * and equals() that make it suitable for use as keys in standard implementations of
+ * {@link java.util.Map}.
  */
 public final class MacAddress implements Parcelable {
 
@@ -122,12 +124,22 @@
     }
 
     /**
+     * Convert this MacAddress to a byte array.
+     *
+     * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
+     * the returned array is [1, 2, 3, 4, 5, 6].
+     *
      * @return a byte array representation of this MacAddress.
      */
     public @NonNull byte[] toByteArray() {
         return byteAddrFromLongAddr(mAddr);
     }
 
+    /**
+     * Returns a human-readable representation of this MacAddress.
+     * The exact format is implementation-dependent and should not be assumed to have any
+     * particular format.
+     */
     @Override
     public @NonNull String toString() {
         return stringAddrFromLongAddr(mAddr);
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 825077ff..ad43f95 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -125,11 +125,11 @@
         final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         onViewFocusChanged(viewForWindowFocus, true);
 
-        // Skip starting input when the next focused view is same as served view and the served
-        // input connection still exists.
+        // Starting new input when the next focused view is same as served view but the
+        // editor is not aligned with the same editor or editor is inactive.
         final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
-        if (nextFocusIsServedView && immDelegate.isAcceptingText()) {
-            forceFocus = false;
+        if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) {
+            forceFocus = true;
         }
 
         immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
@@ -254,7 +254,7 @@
         void setCurrentRootView(ViewRootImpl rootView);
         boolean isCurrentRootView(ViewRootImpl rootView);
         boolean isRestartOnNextWindowFocus(boolean reset);
-        boolean isAcceptingText();
+        boolean isSameEditorAndAcceptingText(View view);
     }
 
     public View getServedView() {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c6be91f..a679b37 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -737,7 +737,7 @@
             }
         }
 
-        final boolean hasControl = mTmpControlArray.size() > 0;
+        boolean requestedStateStale = false;
         final int[] showTypes = new int[1];
         final int[] hideTypes = new int[1];
 
@@ -754,9 +754,26 @@
         // Ensure to create source consumers if not available yet.
         for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
             final InsetsSourceControl control = mTmpControlArray.valueAt(i);
-            InsetsSourceConsumer consumer = getSourceConsumer(control.getType());
+            final @InternalInsetsType int type = control.getType();
+            final InsetsSourceConsumer consumer = getSourceConsumer(type);
             consumer.setControl(control, showTypes, hideTypes);
 
+            if (!requestedStateStale) {
+                final boolean requestedVisible = consumer.isRequestedVisible();
+
+                // We might have changed our requested visibilities while we don't have the control,
+                // so we need to update our requested state once we have control. Otherwise, our
+                // requested state at the server side might be incorrect.
+                final boolean requestedVisibilityChanged =
+                        requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type);
+
+                // The IME client visibility will be reset by insets source provider while updating
+                // control, so if IME is requested visible, we need to send the request to server.
+                final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible;
+
+                requestedStateStale = requestedVisibilityChanged || imeRequestedVisible;
+            }
+
         }
         mTmpControlArray.clear();
 
@@ -772,10 +789,7 @@
         if (hideTypes[0] != 0) {
             applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
         }
-        if (hasControl && mRequestedState.hasSources()) {
-            // We might have changed our requested visibilities while we don't have the control,
-            // so we need to update our requested state once we have control. Otherwise, our
-            // requested state at the server side might be incorrect.
+        if (requestedStateStale) {
             updateRequestedState();
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2b7044d..fefe564 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1824,13 +1824,19 @@
     /**
      * Called after window layout to update the bounds surface. If the surface insets have changed
      * or the surface has resized, update the bounds surface.
+     *
+     * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl.
      */
-    private void updateBoundsLayer() {
+    private void updateBoundsLayer(boolean shouldReparent) {
         if (mBoundsLayer != null) {
             setBoundsLayerCrop();
-            mTransaction.deferTransactionUntil(mBoundsLayer,
-                    getRenderSurfaceControl(), mSurface.getNextFrameNumber())
-                    .apply();
+            mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+                    mSurface.getNextFrameNumber());
+
+            if (shouldReparent) {
+                mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl());
+            }
+            mTransaction.apply();
         }
     }
 
@@ -2912,7 +2918,16 @@
         }
 
         if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
-            updateBoundsLayer();
+            // If the surface has been replaced, there's a chance the bounds layer is not parented
+            // to the new layer. When updating bounds layer, also reparent to the main VRI
+            // SurfaceControl to ensure it's correctly placed in the hierarchy.
+            //
+            // This needs to be done on the client side since WMS won't reparent the children to the
+            // new surface if it thinks the app is closing. WMS gets the signal that the app is
+            // stopping, but on the client side it doesn't get stopped since it's restarted quick
+            // enough. WMS doesn't want to keep around old children since they will leak when the
+            // client creates new children.
+            updateBoundsLayer(surfaceReplaced);
         }
 
         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3be0a4d..37b3529 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -633,20 +633,21 @@
                 // we'll just do a window focus gain and call it a day.
                 try {
                     View servedView = controller.getServedView();
-                    boolean nextFocusIsServedView = servedView != null && servedView == focusedView;
+                    boolean nextFocusSameEditor = servedView != null && servedView == focusedView
+                            && isSameEditorAndAcceptingText(focusedView);
                     if (DEBUG) {
                         Log.v(TAG, "Reporting focus gain, without startInput"
-                                + ", nextFocusIsServedView=" + nextFocusIsServedView);
+                                + ", nextFocusIsServedView=" + nextFocusSameEditor);
                     }
                     final int startInputReason =
-                            nextFocusIsServedView ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
+                            nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
                                     : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
                     mService.startInputOrWindowGainedFocus(
                             startInputReason, mClient,
                             focusedView.getWindowToken(), startInputFlags, softInputMode,
                             windowFlags,
-                            nextFocusIsServedView ? mCurrentTextBoxAttribute : null,
-                            nextFocusIsServedView ? mServedInputConnectionWrapper : null,
+                            null,
+                            null,
                             0 /* missingMethodFlags */,
                             mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
                 } catch (RemoteException e) {
@@ -671,10 +672,6 @@
         @Override
         public void setCurrentRootView(ViewRootImpl rootView) {
             synchronized (mH) {
-                if (mCurRootView != null) {
-                    // Restart the input when the next window focus state of the root view changed.
-                    mRestartOnNextWindowFocus = true;
-                }
                 mCurRootView = rootView;
             }
         }
@@ -704,14 +701,33 @@
         }
 
         /**
-         * For {@link ImeFocusController} to check if the currently served view is accepting full
-         * text edits.
+         * For {@link ImeFocusController} to check if the given focused view aligns with the same
+         * editor and the editor is active to accept the text input.
+         *
+         * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to
+         *  ImeFocusController.
+         * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance,
+         * so that we we can directly check if the current focused view aligned with the same editor
+         * in the window without using this checking.
+         *
+         * Note that this method is only use for fixing start new input may ignored issue
+         * (e.g. b/160391516), DO NOT leverage this method to do another check.
          */
-        @Override
-        public boolean isAcceptingText() {
+        public boolean isSameEditorAndAcceptingText(View view) {
             synchronized (mH) {
-                return mServedInputConnectionWrapper != null
-                        && mServedInputConnectionWrapper.getInputConnection() != null;
+                if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) {
+                    return false;
+                }
+
+                final EditorInfo ic = mCurrentTextBoxAttribute;
+                // This sameEditor checking is based on using object hash comparison to check if
+                // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the
+                // hash code is same as the given focused view.
+                final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId
+                        && view.getAutofillId() == ic.autofillId
+                        && view.getContext().getOpPackageName() == ic.packageName;
+                return sameEditor && mServedInputConnectionWrapper != null
+                        && mServedInputConnectionWrapper.isActive();
             }
         }
     }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3d91474..19fe435 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4362,4 +4362,7 @@
     <bool name="config_pdp_reject_enable_retry">false</bool>
     <!-- pdp data reject retry delay in ms -->
     <integer name="config_pdp_reject_retry_delay_ms">-1</integer>
+
+    <!-- Component names of the services which will keep critical code path warm -->
+    <string-array name="config_keep_warming_services" translatable="false" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0c87453..4f9911f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4835,10 +4835,10 @@
     <string name="confirm_battery_saver">OK</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, with a "learn more" link. -->
-    <string name="battery_saver_description_with_learn_more">To extend battery life, Battery Saver:\n\n\u2022Turns on Dark theme\n\u2022Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d\n\n<annotation id="url">Learn more</annotation></string>
+    <string name="battery_saver_description_with_learn_more">To extend battery life, Battery Saver:\n\n\u2022 Turns on Dark theme\n\u2022 Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d\n\n<annotation id="url">Learn more</annotation></string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, without a "learn more" link. -->
-    <string name="battery_saver_description">To extend battery life, Battery Saver:\n\n\u2022Turns on Dark theme\n\u2022Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d</string>
+    <string name="battery_saver_description">To extend battery life, Battery Saver:\n\n\u2022 Turns on Dark theme\n\u2022 Turns off or restricts background activity, some visual effects, and other features like \u201cHey Google\u201d</string>
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8719242..20fef81 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4048,4 +4048,6 @@
   <java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
 
   <java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
+
+  <java-symbol type="array" name="config_keep_warming_services" />
 </resources>
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 702f2fa..c36f106 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -691,18 +691,57 @@
     @Test
     public void testRequestedState() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+
+            // The modified state can be controlled when we have control.
             mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
             mController.hide(statusBars());
             assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
-            mController.onControlsChanged(new InsetsSourceControl[0]);
+
+            // The modified state won't be changed while losing control.
+            mController.onControlsChanged(null /* activeControls */);
             assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+            // The modified state won't be changed while state changed while we don't have control.
             InsetsState newState = new InsetsState(mController.getState(), true /* copySource */);
             mController.onStateChanged(newState);
             assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+            // The modified state won't be changed while controlling an insets without having the
+            // control.
             mController.show(statusBars());
             assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+            // The modified state can be updated while gaining control.
             mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
             assertTrue(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+            // The modified state can still be updated if the local state and the requested state
+            // are the same.
+            mController.onControlsChanged(null /* activeControls */);
+            mController.hide(statusBars());
+            newState = new InsetsState(mController.getState(), true /* copySource */);
+            newState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+            mController.onStateChanged(newState);
+            mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
+            assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+            // The modified state will always be updated while receiving IME control if IME is
+            // requested visible.
+            mController.getSourceConsumer(ITYPE_IME).show(false /* fromIme */);
+            newState = new InsetsState(mController.getState(), true /* copySource */);
+            newState.getSource(ITYPE_IME).setVisible(true);
+            newState.getSource(ITYPE_IME).setFrame(1, 2, 3, 4);
+            mController.onStateChanged(newState);
+            mController.onControlsChanged(createSingletonControl(ITYPE_IME));
+            assertEquals(newState.getSource(ITYPE_IME),
+                    mTestHost.getModifiedState().peekSource(ITYPE_IME));
+            newState = new InsetsState(mController.getState(), true /* copySource */);
+            newState.getSource(ITYPE_IME).setVisible(true);
+            newState.getSource(ITYPE_IME).setFrame(5, 6, 7, 8);
+            mController.onStateChanged(newState);
+            mController.onControlsChanged(createSingletonControl(ITYPE_IME));
+            assertEquals(newState.getSource(ITYPE_IME),
+                    mTestHost.getModifiedState().peekSource(ITYPE_IME));
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b39eaf3..3acbfb8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -228,6 +228,7 @@
 
     private final Context mContext;
     private final boolean mIsPrimaryUser;
+    private final boolean mIsAutomotive;
     private final StatusBarStateController mStatusBarStateController;
     HashMap<Integer, SimData> mSimDatas = new HashMap<>();
     HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
@@ -1770,6 +1771,8 @@
             mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback);
         }
 
+        mIsAutomotive = isAutomotive();
+
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         mUserManager = context.getSystemService(UserManager.class);
         mIsPrimaryUser = mUserManager.isPrimaryUser();
@@ -2484,6 +2487,14 @@
                 .addCategory(Intent.CATEGORY_HOME);
         ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
                 0 /* flags */);
+
+        // TODO(b/160971249): Replace in the future by resolving activity as user.
+        if (resolveInfo == null && mIsAutomotive) {
+            Log.w(TAG, "resolveNeedsSlowUnlockTransition: returning false since activity "
+                    + "could not be resolved.");
+            return false;
+        }
+
         return FALLBACK_HOME_COMPONENT.equals(resolveInfo.getComponentInfo().getComponentName());
     }
 
@@ -2554,6 +2565,10 @@
         return false;
     }
 
+    private boolean isAutomotive() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+
     /**
      * Remove the given observer's callback.
      *
@@ -2990,5 +3005,8 @@
                 pw.println("    " + time + " " + model.toString());
             }
         }
+        if (mIsAutomotive) {
+            pw.println("  Running on Automotive build");
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 2043546..2a83aa0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -104,6 +104,8 @@
     private static final int INITIAL_DISMISS_DELAY = 3500;
     private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
     private static final long MENU_FADE_DURATION = 125;
+    private static final long MENU_SLOW_FADE_DURATION = 175;
+    private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
 
     private static final float MENU_BACKGROUND_ALPHA = 0.3f;
     private static final float DISMISS_BACKGROUND_ALPHA = 0.6f;
@@ -182,6 +184,7 @@
                     break;
                 }
                 case MESSAGE_MENU_EXPANDED : {
+                    mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
                     mMenuContainerAnimator.start();
                     break;
                 }
@@ -400,7 +403,9 @@
                 mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
             }
             mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
-            mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
+            mMenuContainerAnimator.setDuration(menuState == MENU_STATE_CLOSE
+                    ? MENU_FADE_DURATION
+                    : MENU_SLOW_FADE_DURATION);
             if (allowMenuTimeout) {
                 mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 2ef6934..201ed9c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -100,7 +100,8 @@
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size);
+                int avatarSize =
+                        (int) mContext.getResources().getDimension(R.dimen.qs_framed_avatar_size);
                 Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
                 drawable.setColorFilter(
                         item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 8a38199..370f9a7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -193,10 +193,11 @@
 
             @Override
             public void onKeyguardShowingChanged() {
-                if (!isDividerVisible() || mView == null) {
+                if (!isSplitActive() || mView == null) {
                     return;
                 }
                 mView.setHidden(mKeyguardStateController.isShowing());
+                mImePositionProcessor.updateAdjustForIme();
             }
 
             @Override
@@ -285,8 +286,9 @@
      * while this only cares if some things are (eg. while entering/exiting as well).
      */
     private boolean isSplitActive() {
-        return mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
-                || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED;
+        return mSplits.mPrimary != null && mSplits.mSecondary != null
+                && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
+                        || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
     }
 
     private void addDivider(Configuration configuration) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 47c8c0a..9db389e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -91,6 +91,7 @@
 
     private boolean mPaused = true;
     private boolean mPausedTargetAdjusted = false;
+    private boolean mAdjustedWhileHidden = false;
 
     DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler) {
         mSplits = splits;
@@ -170,11 +171,17 @@
             // If split is hidden, we don't want to trigger any relayouts that would cause the
             // divider to show again.
             updateImeAdjustState();
+        } else {
+            mAdjustedWhileHidden = true;
         }
     }
 
     private void updateImeAdjustState() {
-        if (mAdjusted != mTargetAdjusted) {
+        updateImeAdjustState(false /* force */);
+    }
+
+    private void updateImeAdjustState(boolean force) {
+        if (mAdjusted != mTargetAdjusted || force) {
             // Reposition the server's secondary split position so that it evaluates
             // insets properly.
             WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -231,6 +238,11 @@
         mSplits.mDivider.setAdjustedForIme(mTargetShown && !mPaused);
     }
 
+    public void updateAdjustForIme() {
+        updateImeAdjustState(mAdjustedWhileHidden);
+        mAdjustedWhileHidden = false;
+    }
+
     @Override
     public void onImePositionChanged(int displayId, int imeTop,
             SurfaceControl.Transaction t) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 5ec5ec6..f52a6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -288,7 +288,8 @@
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size);
+                int avatarSize =
+                        (int) mContext.getResources().getDimension(R.dimen.kg_framed_avatar_size);
                 Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
                 drawable.setColorFilter(
                         item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index c0089e5..1ce98eb 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -273,10 +273,8 @@
             if (imeSource == null || mImeSourceControl == null) {
                 return;
             }
-            // Set frame, but only if the new frame isn't empty -- this maintains continuity
             final Rect newFrame = imeSource.getFrame();
-            mImeFrame.set(newFrame);
-            final boolean isFloating = newFrame.height() == 0;
+            final boolean isFloating = newFrame.height() == 0 && show;
             if (isFloating) {
                 // This is likely a "floating" or "expanded" IME, so to get animations, just
                 // pretend the ime has some size just below the screen.
@@ -285,6 +283,9 @@
                         mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId).density()
                                 * FLOATING_IME_BOTTOM_INSET);
                 mImeFrame.bottom -= floatingInset;
+            } else if (newFrame.height() != 0) {
+                // Don't set a new frame if it's empty and hiding -- this maintains continuity
+                mImeFrame.set(newFrame);
             }
             if (DEBUG) {
                 Slog.d(TAG, "Run startAnim  show:" + show + "  was:"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 6d6a4d8..f48b3fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -25,6 +25,8 @@
 import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.util.UserIcons
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.QSUserSwitcherEvent
 import com.android.systemui.statusbar.policy.UserSwitcherController
@@ -50,10 +52,10 @@
     @Mock private lateinit var mOtherView: View
     @Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
     @Mock private lateinit var mUserInfo: UserInfo
-    @Mock private lateinit var mPicture: Bitmap
     @Mock private lateinit var mLayoutInflater: LayoutInflater
     private lateinit var adapter: UserDetailView.Adapter
     private lateinit var uiEventLogger: UiEventLoggerFake
+    private lateinit var mPicture: Bitmap
 
     @Before
     fun setUp() {
@@ -64,6 +66,7 @@
         `when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
                 .thenReturn(mInflatedUserDetailItemView)
         adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger)
+        mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user))
     }
 
     private fun clickableTest(
@@ -141,4 +144,4 @@
                     false /* isAddUser */,
                     false /* isRestricted */,
                     true /* isSwitchToEnabled */)
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 135ac9a..7be843f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -19,6 +19,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 
 import android.app.ActivityThread;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -336,6 +337,11 @@
      */
     public int PENDINGINTENT_WARNING_THRESHOLD =  DEFAULT_PENDINGINTENT_WARNING_THRESHOLD;
 
+    /**
+     * Component names of the services which will keep critical code path of the host warm
+     */
+    public final ArraySet<ComponentName> KEEP_WARMING_SERVICES = new ArraySet<ComponentName>();
+
     private List<String> mDefaultImperceptibleKillExemptPackages;
     private List<Integer> mDefaultImperceptibleKillExemptProcStates;
 
@@ -442,6 +448,10 @@
                 .boxed().collect(Collectors.toList());
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
         IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.addAll(mDefaultImperceptibleKillExemptProcStates);
+        KEEP_WARMING_SERVICES.addAll(Arrays.stream(
+                context.getResources().getStringArray(
+                        com.android.internal.R.array.config_keep_warming_services))
+                .map(ComponentName::unflattenFromString).collect(Collectors.toSet()));
     }
 
     public void start(ContentResolver resolver) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5124c4a..a2eea13 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -470,22 +470,23 @@
         // if this receiver was slow, impose deferral policy on the app.  This will kick in
         // when processNextBroadcastLocked() next finds this uid as a receiver identity.
         if (!r.timeoutExempt) {
-            if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+            // r.curApp can be null if finish has raced with process death - benign
+            // edge case, and we just ignore it because we're already cleaning up
+            // as expected.
+            if (r.curApp != null
+                    && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
                 // Core system packages are exempt from deferral policy
                 if (!UserHandle.isCore(r.curApp.uid)) {
                     if (DEBUG_BROADCAST_DEFERRAL) {
                         Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
                                 + " was slow: " + receiver + " br=" + r);
                     }
-                    if (r.curApp != null) {
-                        mDispatcher.startDeferring(r.curApp.uid);
-                    } else {
-                        Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
-                    }
+                    mDispatcher.startDeferring(r.curApp.uid);
                 } else {
                     if (DEBUG_BROADCAST_DEFERRAL) {
                         Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
-                                + " receiver was slow but not deferring: " + receiver + " br=" + r);
+                                + " receiver was slow but not deferring: "
+                                + receiver + " br=" + r);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index da5f489..f0343e1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -76,7 +76,11 @@
 import android.app.usage.UsageEvents;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ServiceInfo;
 import android.os.Debug;
 import android.os.Handler;
@@ -265,6 +269,43 @@
 
     void initSettings() {
         mCachedAppOptimizer.init();
+        if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) {
+            final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+            mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    synchronized (mService) {
+                        handleUserSwitchedLocked();
+                    }
+                }
+            }, filter, null, mService.mHandler);
+        }
+    }
+
+    /**
+     * Update the keep-warming service flags upon user switches
+     */
+    @VisibleForTesting
+    @GuardedBy("mService")
+    void handleUserSwitchedLocked() {
+        final ArraySet<ComponentName> warmServices = mService.mConstants.KEEP_WARMING_SERVICES;
+        final ArrayList<ProcessRecord> processes = mProcessList.mLruProcesses;
+        for (int i = processes.size() - 1; i >= 0; i--) {
+            final ProcessRecord app = processes.get(i);
+            boolean includeWarmPkg = false;
+            for (int j = warmServices.size() - 1; j >= 0; j--) {
+                if (app.pkgList.containsKey(warmServices.valueAt(j).getPackageName())) {
+                    includeWarmPkg = true;
+                    break;
+                }
+            }
+            if (!includeWarmPkg) {
+                continue;
+            }
+            for (int j = app.numberOfRunningServices() - 1; j >= 0; j--) {
+                app.getRunningServiceAt(j).updateKeepWarmLocked();
+            }
+        }
     }
 
     /**
@@ -1470,7 +1511,7 @@
                                 "Raise procstate to started service: " + app);
                     }
                 }
-                if (app.hasShownUi && !app.getCachedIsHomeProcess()) {
+                if (!s.mKeepWarming && app.hasShownUi && !app.getCachedIsHomeProcess()) {
                     // If this process has shown some UI, let it immediately
                     // go to the LRU list because it may be pretty heavy with
                     // UI stuff.  We'll tag it with a label just to help
@@ -1479,7 +1520,8 @@
                         app.adjType = "cch-started-ui-services";
                     }
                 } else {
-                    if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
+                    if (s.mKeepWarming
+                            || now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
                         // This service has seen some activity within
                         // recent memory, so we will keep its process ahead
                         // of the background processes.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 9c96e6e..fc17dde 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -40,6 +40,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.LocalServices;
@@ -146,6 +147,8 @@
 
     private int lastStartId;    // identifier of most recent start request.
 
+    boolean mKeepWarming; // Whether or not it'll keep critical code path of the host warm
+
     static class StartItem {
         final ServiceRecord sr;
         final boolean taskRemoved;
@@ -514,6 +517,7 @@
         lastActivity = SystemClock.uptimeMillis();
         userId = UserHandle.getUserId(appInfo.uid);
         createdFromFg = callerIsFg;
+        updateKeepWarmLocked();
     }
 
     public ServiceState getTracker() {
@@ -732,6 +736,14 @@
         }
     }
 
+    @GuardedBy("ams")
+    void updateKeepWarmLocked() {
+        mKeepWarming = ams.mConstants.KEEP_WARMING_SERVICES.contains(name)
+                && (ams.mUserController.getCurrentUserId() == userId
+                || ams.isSingleton(processName, appInfo, instanceName.getClassName(),
+                        serviceInfo.flags));
+    }
+
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
             ProcessRecord app) {
         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d8ee32e..0154fe0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -18,8 +18,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
-import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR;
-
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.Manifest;
@@ -719,11 +717,6 @@
      */
     int mImeWindowVis;
 
-    /**
-     * Checks if the client needs to start input.
-     */
-    private boolean mCurClientNeedStartInput = false;
-
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
     private IBinder mSwitchingDialogToken = new Binder();
@@ -3467,20 +3460,14 @@
         if (mCurFocusedWindow == windowToken) {
             if (DEBUG) {
                 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
-                        + " attribute=" + attribute + ", token = " + windowToken);
+                        + " attribute=" + attribute + ", token = " + windowToken
+                        + ", startInputReason="
+                        + InputMethodDebug.startInputReasonToString(startInputReason));
             }
-            // Needs to start input when the same window focus gain but not with the same editor,
-            // or when the current client needs to start input (e.g. when focusing the same
-            // window after device turned screen on).
-            if (attribute != null && (startInputReason != WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
-                    || mCurClientNeedStartInput)) {
-                if (mIsInteractive) {
-                    mCurClientNeedStartInput = false;
-                }
+            if (attribute != null) {
                 return startInputUncheckedLocked(cs, inputContext, missingMethods,
                         attribute, startInputFlags, startInputReason);
             }
-
             return new InputBindResult(
                     InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
                     null, null, null, -1, null);
@@ -4459,9 +4446,6 @@
     private void handleSetInteractive(final boolean interactive) {
         synchronized (mMethodMap) {
             mIsInteractive = interactive;
-            if (!interactive) {
-                mCurClientNeedStartInput = true;
-            }
             updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
 
             // Inform the current client of the change in active status
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 08cdd8f..330f995 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -865,7 +865,16 @@
 
     @Override
     public ParceledListSlice<SessionInfo> getStagedSessions() {
-        return mStagingManager.getSessions(Binder.getCallingUid());
+        final List<SessionInfo> result = new ArrayList<>();
+        synchronized (mSessions) {
+            for (int i = 0; i < mSessions.size(); i++) {
+                final PackageInstallerSession session = mSessions.valueAt(i);
+                if (session.isStaged() && !session.isDestroyed()) {
+                    result.add(session.generateInfoForCaller(false, Binder.getCallingUid()));
+                }
+            }
+        }
+        return new ParceledListSlice<>(result);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6cd66c6..5b1c0fd 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -38,7 +38,6 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
-import android.content.pm.ParceledListSlice;
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.rollback.IRollbackManager;
 import android.content.rollback.RollbackInfo;
@@ -180,20 +179,6 @@
         }
     }
 
-    ParceledListSlice<PackageInstaller.SessionInfo> getSessions(int callingUid) {
-        final List<PackageInstaller.SessionInfo> result = new ArrayList<>();
-        synchronized (mStagedSessions) {
-            for (int i = 0; i < mStagedSessions.size(); i++) {
-                final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
-                if (stagedSession.isDestroyed()) {
-                    continue;
-                }
-                result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
-            }
-        }
-        return new ParceledListSlice<>(result);
-    }
-
     /**
      * Validates the signature used to sign the container of the new apex package
      *
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b3e162d..8868a6c 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -396,6 +396,14 @@
             return false;
         }
 
+        /**
+         * Returns true if the window has a letterbox and any part of that letterbox overlaps with
+         * the given {@code rect}.
+         */
+        default boolean isLetterboxedOverlappingWith(Rect rect) {
+            return false;
+        }
+
         /** @return the current windowing mode of this window. */
         int getWindowingMode();
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 360e40b..40e558c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1395,10 +1395,11 @@
     }
 
     /**
-     * @see Letterbox#notIntersectsOrFullyContains(Rect)
+     * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
+     * the given {@code rect}.
      */
-    boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
-        return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
+    boolean isLetterboxOverlappingWith(Rect rect) {
+        return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
     }
 
     static class Token extends IApplicationToken.Stub {
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 26e0790..123fb6c 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -175,7 +175,7 @@
         }
         final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
         final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
-        return win.letterboxNotIntersectsOrFullyContains(contentFrame);
+        return !win.isLetterboxedOverlappingWith(contentFrame);
     }
 
     boolean setBarShowingLw(final boolean show) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b94fb04..de6501a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3506,12 +3506,13 @@
     }
 
     private boolean isImeControlledByApp() {
-        return mInputMethodTarget != null && !WindowConfiguration.isSplitScreenWindowingMode(
-                mInputMethodTarget.getWindowingMode());
+        return mInputMethodInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode(
+                        mInputMethodInputTarget.getWindowingMode());
     }
 
     boolean isImeAttachedToApp() {
         return isImeControlledByApp()
+                && mInputMethodTarget != null
                 && mInputMethodTarget.mActivityRecord != null
                 && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
                 // An activity with override bounds should be letterboxed inside its parent bounds,
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 5d1c85d..a685886 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -77,10 +77,10 @@
         mOuter.set(outer);
         mInner.set(inner);
 
-        mTop.layout(outer.left, outer.top, outer.right, inner.top, surfaceOrigin);
-        mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin);
-        mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
-        mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin);
+        mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin);
+        mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin);
+        mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
+        mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin);
     }
 
 
@@ -101,29 +101,17 @@
     }
 
     /**
-     * Returns {@code true} if the letterbox does not overlap with the bar, or the letterbox can
-     * fully cover the window frame.
-     *
-     * @param rect The area of the window frame.
+     * Returns true if any part of the letterbox overlaps with the given {@code rect}.
      */
-    boolean notIntersectsOrFullyContains(Rect rect) {
-        int emptyCount = 0;
-        int noOverlappingCount = 0;
+    public boolean isOverlappingWith(Rect rect) {
         for (LetterboxSurface surface : mSurfaces) {
-            final Rect surfaceRect = surface.mLayoutFrameGlobal;
-            if (surfaceRect.isEmpty()) {
-                // empty letterbox
-                emptyCount++;
-            } else if (!Rect.intersects(surfaceRect, rect)) {
-                // no overlapping
-                noOverlappingCount++;
-            } else if (surfaceRect.contains(rect)) {
-                // overlapping and covered
+            if (surface.isOverlappingWith(rect)) {
                 return true;
             }
         }
-        return (emptyCount + noOverlappingCount) == mSurfaces.length;
+        return false;
     }
+
     /**
      * Hides the letterbox.
      *
@@ -298,6 +286,17 @@
             return Math.max(0, mLayoutFrameGlobal.height());
         }
 
+        /**
+         * Returns if the given {@code rect} overlaps with this letterbox piece.
+         * @param rect the area to check for overlap in global coordinates
+         */
+        public boolean isOverlappingWith(Rect rect) {
+            if (mLayoutFrameGlobal.isEmpty()) {
+                return false;
+            }
+            return Rect.intersects(rect, mLayoutFrameGlobal);
+        }
+
         public void applySurfaceChanges(SurfaceControl.Transaction t) {
             if (mSurfaceFrameRelative.equals(mLayoutFrameRelative)) {
                 // Nothing changed.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 00be75f..26bcf3b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3797,12 +3797,9 @@
         return mActivityRecord.getBounds().equals(mTmpRect);
     }
 
-    /**
-     * @see Letterbox#notIntersectsOrFullyContains(Rect)
-     */
-    boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
-        return mActivityRecord == null
-                || mActivityRecord.letterboxNotIntersectsOrFullyContains(rect);
+    @Override
+    public boolean isLetterboxedOverlappingWith(Rect rect) {
+        return mActivityRecord != null && mActivityRecord.isLetterboxOverlappingWith(rect);
     }
 
     boolean isDragResizeChanged() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index fde40aa..2a267c4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -84,6 +84,7 @@
 import android.os.IBinder;
 import android.os.PowerManagerInternal;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -130,6 +131,7 @@
     private static final int MOCKAPP5_UID = MOCKAPP_UID + 4;
     private static final String MOCKAPP5_PROCESSNAME = "test #5";
     private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
+    private static final int MOCKAPP2_UID_OTHER = MOCKAPP2_UID + UserHandle.PER_USER_RANGE;
     private static Context sContext;
     private static PackageManagerInternal sPackageManagerInternal;
     private static ActivityManagerService sService;
@@ -168,6 +170,8 @@
                 mock(SparseArray.class));
         setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler",
                 mock(OomAdjProfiler.class));
+        setFieldValue(ActivityManagerService.class, sService, "mUserController",
+                mock(UserController.class));
         doReturn(new ActivityManagerService.ProcessChangeItem()).when(sService)
                 .enqueueProcessChangeItemLocked(anyInt(), anyInt());
         sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
@@ -1621,6 +1625,117 @@
         assertEquals(SERVICE_ADJ, app.setAdj);
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testUpdateOomAdj_DoAll_Service_KeepWarmingList() {
+        final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID_OTHER,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        final int userOwner = 0;
+        final int userOther = 1;
+        final int cachedAdj1 = CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+        final int cachedAdj2 = cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+        doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
+
+        final ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app2);
+        lru.add(app);
+
+        final ComponentName cn = ComponentName.unflattenFromString(
+                MOCKAPP_PACKAGENAME + "/.TestService");
+        final ComponentName cn2 = ComponentName.unflattenFromString(
+                MOCKAPP2_PACKAGENAME + "/.TestService");
+        final long now = SystemClock.uptimeMillis();
+
+        sService.mConstants.KEEP_WARMING_SERVICES.clear();
+        final ServiceInfo si = mock(ServiceInfo.class);
+        si.applicationInfo = mock(ApplicationInfo.class);
+        ServiceRecord s = spy(new ServiceRecord(sService, null, cn, cn, null, 0, null,
+                si, false, null));
+        doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
+        s.startRequested = true;
+        s.lastActivity = now;
+
+        app.setCached(false);
+        app.startService(s);
+        app.hasShownUi = true;
+
+        final ServiceInfo si2 = mock(ServiceInfo.class);
+        si2.applicationInfo = mock(ApplicationInfo.class);
+        si2.applicationInfo.uid = MOCKAPP2_UID_OTHER;
+        ServiceRecord s2 = spy(new ServiceRecord(sService, null, cn2, cn2, null, 0, null,
+                si2, false, null));
+        doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
+        s2.startRequested = true;
+        s2.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+
+        app2.setCached(false);
+        app2.startService(s2);
+        app2.hasShownUi = false;
+
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
+        assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj2, "cch-started-services");
+
+        app.setProcState = PROCESS_STATE_NONEXISTENT;
+        app.adjType = null;
+        app.setAdj = UNKNOWN_ADJ;
+        app.hasShownUi = false;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+
+        app.setCached(false);
+        app.setProcState = PROCESS_STATE_NONEXISTENT;
+        app.adjType = null;
+        app.setAdj = UNKNOWN_ADJ;
+        s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
+
+        app.stopService(s);
+        app.setProcState = PROCESS_STATE_NONEXISTENT;
+        app.adjType = null;
+        app.setAdj = UNKNOWN_ADJ;
+        app.hasShownUi = true;
+        sService.mConstants.KEEP_WARMING_SERVICES.add(cn);
+        sService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
+        s = spy(new ServiceRecord(sService, null, cn, cn, null, 0, null,
+                si, false, null));
+        doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
+        s.startRequested = true;
+        s.lastActivity = now;
+
+        app.startService(s);
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+        assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
+
+        app.setCached(true);
+        app.setProcState = PROCESS_STATE_NONEXISTENT;
+        app.adjType = null;
+        app.setAdj = UNKNOWN_ADJ;
+        app.hasShownUi = false;
+        s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+        assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
+
+        doReturn(userOther).when(sService.mUserController).getCurrentUserId();
+        sService.mOomAdjuster.handleUserSwitchedLocked();
+
+        sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+        assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
+        assertProcStates(app2, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+    }
+
     private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
             String packageName, boolean hasShownUi) {
         long now = SystemClock.uptimeMillis();
@@ -1747,4 +1862,12 @@
         assertEquals(expectedAdj, app.setAdj);
         assertEquals(expectedSchedGroup, app.setSchedGroup);
     }
+
+    private void assertProcStates(ProcessRecord app, boolean expectedCached,
+            int expectedProcState, int expectedAdj, String expectedAdjType) {
+        assertEquals(expectedCached, app.isCached());
+        assertEquals(expectedProcState, app.setProcState);
+        assertEquals(expectedAdj, app.setAdj);
+        assertEquals(expectedAdjType, app.adjType);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d64fdb8..94acd77 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -858,6 +858,7 @@
     public void testComputeImeParent_app() throws Exception {
         final DisplayContent dc = createNewDisplay();
         dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
+        dc.mInputMethodInputTarget = dc.mInputMethodTarget;
         assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(),
                 dc.computeImeParent());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index ce3f270..bf84aec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -55,102 +54,10 @@
         mTransaction = spy(StubTransaction.class);
     }
 
-    private static final int TOP_BAR = 0x1;
-    private static final int BOTTOM_BAR = 0x2;
-    private static final int LEFT_BAR = 0x4;
-    private static final int RIGHT_BAR = 0x8;
-
     @Test
-    public void testNotIntersectsOrFullyContains_usesGlobalCoordinates() {
-        final Rect outer = new Rect(0, 0, 10, 50);
-        final Point surfaceOrig = new Point(1000, 2000);
-
-        final Rect topBar = new Rect(0, 0, 10, 2);
-        final Rect bottomBar = new Rect(0, 45, 10, 50);
-        final Rect leftBar = new Rect(0, 0, 2, 50);
-        final Rect rightBar = new Rect(8, 0, 10, 50);
-
-        final LetterboxLayoutVerifier verifier =
-                new LetterboxLayoutVerifier(outer, surfaceOrig, mLetterbox);
-        verifier.setBarRect(topBar, bottomBar, leftBar, rightBar);
-
-        // top
-        verifier.setInner(0, 2, 10, 50).verifyPositions(TOP_BAR | BOTTOM_BAR, BOTTOM_BAR);
-        // bottom
-        verifier.setInner(0, 0, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, TOP_BAR);
-        // left
-        verifier.setInner(2, 0, 10, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, RIGHT_BAR);
-        // right
-        verifier.setInner(0, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, LEFT_BAR);
-        // top + bottom
-        verifier.setInner(0, 2, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, 0);
-        // left + right
-        verifier.setInner(2, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, 0);
-        // top + left
-        verifier.setInner(2, 2, 10, 50).verifyPositions(TOP_BAR | LEFT_BAR, 0);
-        // top + left + right
-        verifier.setInner(2, 2, 8, 50).verifyPositions(TOP_BAR | LEFT_BAR | RIGHT_BAR, 0);
-        // left + right + bottom
-        verifier.setInner(2, 0, 8, 45).verifyPositions(LEFT_BAR | RIGHT_BAR | BOTTOM_BAR, 0);
-        // all
-        verifier.setInner(2, 2, 8, 45)
-                .verifyPositions(TOP_BAR | BOTTOM_BAR | LEFT_BAR | RIGHT_BAR, 0);
-    }
-
-    private static class LetterboxLayoutVerifier {
-        final Rect mOuter;
-        final Rect mInner = new Rect();
-        final Point mSurfaceOrig;
-        final Letterbox mLetterbox;
-        final Rect mTempRect = new Rect();
-
-        final Rect mTop = new Rect();
-        final Rect mBottom = new Rect();
-        final Rect mLeft = new Rect();
-        final Rect mRight = new Rect();
-
-        LetterboxLayoutVerifier(Rect outer, Point surfaceOrig, Letterbox letterbox) {
-            mOuter = new Rect(outer);
-            mSurfaceOrig = new Point(surfaceOrig);
-            mLetterbox = letterbox;
-        }
-
-        LetterboxLayoutVerifier setInner(int left, int top, int right, int bottom) {
-            mInner.set(left, top, right, bottom);
-            mLetterbox.layout(mOuter, mInner, mSurfaceOrig);
-            return this;
-        }
-
-        void setBarRect(Rect top, Rect bottom, Rect left, Rect right) {
-            mTop.set(top);
-            mBottom.set(bottom);
-            mLeft.set(left);
-            mRight.set(right);
-        }
-
-        void verifyPositions(int allowedPos, int noOverlapPos) {
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mTop),
-                    (allowedPos & TOP_BAR) != 0);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mBottom),
-                    (allowedPos & BOTTOM_BAR) != 0);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mLeft),
-                    (allowedPos & LEFT_BAR) != 0);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mRight),
-                    (allowedPos & RIGHT_BAR) != 0);
-
-            mTempRect.set(mTop.left, mTop.top, mTop.right, mTop.bottom + 1);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
-                    (noOverlapPos & TOP_BAR) != 0);
-            mTempRect.set(mLeft.left, mLeft.top, mLeft.right + 1, mLeft.bottom);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
-                    (noOverlapPos & LEFT_BAR) != 0);
-            mTempRect.set(mRight.left - 1, mRight.top, mRight.right, mRight.bottom);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
-                    (noOverlapPos & RIGHT_BAR) != 0);
-            mTempRect.set(mBottom.left, mBottom.top - 1, mBottom.right, mBottom.bottom);
-            assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
-                    (noOverlapPos & BOTTOM_BAR) != 0);
-        }
+    public void testOverlappingWith_usesGlobalCoordinates() {
+        mLetterbox.layout(new Rect(0, 0, 10, 50), new Rect(0, 2, 10, 45), new Point(1000, 2000));
+        assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1)));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 3c98272..a979c86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -269,6 +269,8 @@
 
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
         mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity);
+        mActivity.mDisplayContent.mInputMethodInputTarget =
+                mActivity.mDisplayContent.mInputMethodTarget;
         // Because the aspect ratio of display doesn't exceed the max aspect ratio of activity.
         // The activity should still fill its parent container and IME can attach to the activity.
         assertTrue(mActivity.matchParentBounds());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6a95bc3..6c77a6f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3179,6 +3179,17 @@
             "5g_icon_display_secondary_grace_period_string";
 
     /**
+     * Whether device reset all of NR timers when device camped on a network that haven't 5G
+     * capability and RRC currently in IDLE state.
+     *
+     * The default value is false;
+     *
+     * @hide
+     */
+    public static final String KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL =
+            "nr_timers_reset_if_non_endc_and_rrc_idle_bool";
+
+    /**
      * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
      * @hide
      */
@@ -4277,6 +4288,7 @@
                         + "not_restricted_rrc_con:5G");
         sDefaults.putString(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "");
         sDefaults.putString(KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "");
+        sDefaults.putBoolean(KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL, false);
         /* Default value is 1 hour. */
         sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
         sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false);