Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e42507dd authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

[ShellTransition]: add WMS#setRecentsAppBehindSystemBars for recents

For legacy recents animation, launcher side use
RecentsAnimationController#setAnimationTargetsBehindSystemBars to
callback if the animating recents task target is valid to affect
system bar apparence according the gesture threadshold.

if the animating recents task is behind system bar, means the
gesture threshod not yet passed and the task still can affect
system bar apparence, and vice-versa.

with shell-transition, since launcher triggers recents animation
by normal startActivity without initiating RecentsAnimationController
with startRecentsActivity, the launcher will be top-resumed
(but the surface hierarchy the recents task is still be top-most) when
starting gesture on navbar, in this case, launcher can affect the
system appearence even though launcher is behind systembar.

beside, previously we also rely on setAnimationTargetsBehindSystemBars
to hide soft-keyboard in multi-windowing mode when quick-swich tasks,
without this, soft-keyboard will keep visible when swiping up to
recents.

As the result, we needs to backport the most logic of
setAnimationTargetsBehindSystemBars for fixing the above cases,
the only difference is we renaming the method with
setRecentsAppBehindSystemBars(behindSystemBars) to only set recents app
can affect systembar apparence, and placing hide IME/IME icon logic into
handleLegacyRecentsStartBehavior when starting recents animation.

Fix: 215504556
Test: manual as below CUJs with enabling shell-transition:
 CUJ1:
  1) Launching a app with showing IME
  2) Quick-switching to the next task or swiping task to home
  3) Expect no navbar icon flickering

 CUJ2:
  1) With entering split-screen and showing IME on the split task
  2) Swipe up to recents
  3) Expect IME shound be hidden

 CUJ3:
  1) Launching a app
  2) Hammer tapping on the navigation bar
  3) Expect the staus bar icon won't blinking

Change-Id: I552eea738aed5566eb897bb9c68507e83ac43e1d
parent e4590dbf
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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);
}
+8 −0
Original line number Diff line number Diff line
@@ -754,6 +754,14 @@ public final class WindowManagerGlobal {
            mWindowlessRoots.remove(impl);
	}
    }

    public void setRecentsAppBehindSystemBars(boolean behindSystemBars) {
        try {
            getWindowManagerService().setRecentsAppBehindSystemBars(behindSystemBars);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

final class WindowLeaked extends AndroidRuntimeException {
+34 −1
Original line number Diff line number Diff line
@@ -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()
+6 −2
Original line number Diff line number Diff line
@@ -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);
        }
    }

+21 −0
Original line number Diff line number Diff line
@@ -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;
@@ -8974,4 +8975,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);
        }
    }
}