diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 53b842a0f3a2c..f8a1b45a1c75c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -955,4 +955,10 @@ interface IWindowManager * @hide */ Bitmap snapshotTaskForRecents(int taskId); + + /** + * Informs the system whether the recents app is currently behind the system bars. If so, + * means the recents app can control the SystemUI flags, and vice-versa. + */ + void setRecentsAppBehindSystemBars(boolean behindSystemBars); } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 93cb0dd7a2348..2dc5fbd5439f3 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -752,6 +752,14 @@ public final class WindowManagerGlobal { public void removeWindowlessRoot(ViewRootImpl impl) { synchronized (mLock) { mWindowlessRoots.remove(impl); + } + } + + public void setRecentsAppBehindSystemBars(boolean behindSystemBars) { + try { + getWindowManagerService().setRecentsAppBehindSystemBars(behindSystemBars); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 785867b391ca8..29d17429fa6a5 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -80,9 +80,12 @@ import android.window.TransitionInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; +import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.LocalServices; +import com.android.server.inputmethod.InputMethodManagerInternal; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -552,14 +555,24 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe asyncRotationController.onTransitionFinished(); } if (mTransientLaunches != null) { + InsetsControlTarget prevImeTarget = dc.getImeTarget( + DisplayContent.IME_TARGET_CONTROL); + InsetsControlTarget newImeTarget = null; // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget), // so re-compute in case the IME target is changed after transition. for (int t = 0; t < mTransientLaunches.size(); ++t) { if (mTransientLaunches.keyAt(t).getDisplayContent() == dc) { - dc.computeImeTarget(true /* updateImeTarget */); + newImeTarget = dc.computeImeTarget(true /* updateImeTarget */); break; } } + if (mRecentsDisplayId != INVALID_DISPLAY && prevImeTarget == newImeTarget) { + // Restore IME icon only when moving the original app task to front from + // recents, in case IME icon may missing if the moving task has already been + // the current focused task. + InputMethodManagerInternal.get().updateImeWindowStatus( + false /* disableImeIcon */); + } } dc.handleCompleteDeferredRemoval(); } @@ -781,6 +794,26 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } + // Hiding IME/IME icon when starting quick-step with resents animation. + if (!mTargetDisplays.get(mRecentsDisplayId).isImeAttachedToApp()) { + // Hiding IME if IME window is not attached to app. + // Since some windowing mode is not proper to snapshot Task with IME window + // while the app transitioning to the next task (e.g. split-screen mode) + final InputMethodManagerInternal inputMethodManagerInternal = + LocalServices.getService(InputMethodManagerInternal.class); + if (inputMethodManagerInternal != null) { + inputMethodManagerInternal.hideCurrentInputMethod( + SoftInputShowHideReason.HIDE_RECENTS_ANIMATION); + } + } else { + // Disable IME icon explicitly when IME attached to the app in case + // IME icon might flickering while swiping to the next app task still + // in animating before the next app window focused, or IME icon + // persists on the bottom when swiping the task to recents. + InputMethodManagerInternal.get().updateImeWindowStatus( + true /* disableImeIcon */); + } + // The rest of this function handles nav-bar reparenting if (!dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition() diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 0cfc702018a07..a6ff15b9d45d7 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; @@ -514,8 +513,13 @@ class TransitionController { // TODO(b/188669821): Remove once legacy recents behavior is moved to shell. // Also interpret HOME transient launch as recents - if (activity.getActivityType() == ACTIVITY_TYPE_HOME) { + if (activity.isActivityTypeHomeOrRecents()) { mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS); + // When starting recents animation, we assume the recents activity is behind the app + // task and should not affect system bar appearance, + // until WMS#setRecentsAppBehindSystemBars be called from launcher when passing + // the gesture threshold. + activity.getTask().setCanAffectSystemUiFlags(false); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6445d1e657dae..04f135e3e1b96 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,6 +25,7 @@ import static android.Manifest.permission.MODIFY_TOUCH_MODE_STATE; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; +import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; @@ -8983,4 +8984,24 @@ public class WindowManagerService extends IWindowManager.Stub return Bitmap.wrapHardwareBuffer(taskSnapshot.getHardwareBuffer(), taskSnapshot.getColorSpace()); } + + @Override + public void setRecentsAppBehindSystemBars(boolean behindSystemBars) { + if (!checkCallingPermission(START_TASKS_FROM_RECENTS, "setRecentsAppBehindSystemBars()")) { + throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission"); + } + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final Task recentsApp = mRoot.getTask(task -> task.isActivityTypeHomeOrRecents() + && task.getTopVisibleActivity() != null); + if (recentsApp != null) { + recentsApp.getTask().setCanAffectSystemUiFlags(behindSystemBars); + mWindowPlacerLocked.requestTraversal(); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }