Add an inputconsumer override method for modern recents transitions

Shell transitions doesn't use RecentsAnimationController anymore.
Instead, its more structured to just inform inputmonitor when it
is and isn't animating recents. InputMonitor then can use this extra
information to reroute focus to the recents input consumer at the
right times.

Unlike legacy transitions, recents will actually be on top and get
preferred focus when active. However, the live tile will still be
drawn above it. This means we need to also provide InputMonitor with
the live-tile activity (the "reference" activity) so it can place
the recents inputconsumer at the right z-order.

Bug: 193565597
Test: atest ReOpenImeWindowTest
Change-Id: Iad37888789e14bc049b1a52dd5142eb6c3ea2e99
This commit is contained in:
Evan Rosky
2021-07-28 15:54:46 -07:00
parent ef994701aa
commit aeb52f75d0
2 changed files with 99 additions and 7 deletions

View File

@@ -47,6 +47,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
@@ -66,6 +67,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.Set;
import java.util.function.Consumer;
@@ -99,6 +101,15 @@ final class InputMonitor {
*/
private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
/**
* Set when recents (overview) is active as part of a shell transition. While set, any focus
* going to the recents activity will be redirected to the Recents input consumer. Since we
* draw the live-tile above the recents activity, we also need to provide that activity as a
* z-layering reference so that we can place the recents input consumer above it.
*/
private WeakReference<ActivityRecord> mActiveRecentsActivity = null;
private WeakReference<ActivityRecord> mActiveRecentsLayerRef = null;
/**
* Representation of a input consumer that the policy has added to the window manager to consume
* input events going to windows below it.
@@ -394,6 +405,21 @@ final class InputMonitor {
}
}
/**
* Inform InputMonitor when recents is active so it can enable the recents input consumer.
* @param activity The active recents activity. {@code null} means recents is not active.
* @param layer An activity whose Z-layer is used as a reference for how to sort the consumer.
*/
void setActiveRecents(@Nullable ActivityRecord activity, @Nullable ActivityRecord layer) {
final boolean clear = activity == null;
mActiveRecentsActivity = clear ? null : new WeakReference<>(activity);
mActiveRecentsLayerRef = clear ? null : new WeakReference<>(layer);
}
private static <T> T getWeak(WeakReference<T> ref) {
return ref != null ? ref.get() : null;
}
/**
* Called when the current input focus changes.
*/
@@ -404,8 +430,10 @@ final class InputMonitor {
if (recentsAnimationInputConsumer != null && focus != null) {
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord);
final boolean shouldApplyRecentsInputConsumer = (recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord))
// Shell transitions doesn't use RecentsAnimationController
|| getWeak(mActiveRecentsActivity) != null;
if (shouldApplyRecentsInputConsumer) {
requestFocus(recentsAnimationInputConsumer.mWindowHandle.token,
recentsAnimationInputConsumer.mName);
@@ -505,6 +533,14 @@ final class InputMonitor {
mInDrag = inDrag;
resetInputConsumers(mInputTransaction);
// Update recents input consumer layer if active
if (mAddRecentsAnimationInputConsumerHandle
&& getWeak(mActiveRecentsActivity) != null) {
final WindowContainer layer = getWeak(mActiveRecentsLayerRef);
mRecentsAnimationInputConsumer.show(mInputTransaction,
layer != null ? layer : getWeak(mActiveRecentsActivity));
mAddRecentsAnimationInputConsumerHandle = false;
}
mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
updateInputFocusRequest(mRecentsAnimationInputConsumer);
@@ -539,6 +575,7 @@ final class InputMonitor {
final int privateFlags = w.mAttrs.privateFlags;
// This only works for legacy transitions.
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
mRecentsAnimationInputConsumer.mWindowHandle)) {

View File

@@ -16,10 +16,13 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -149,7 +152,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// TODO(b/188595497): remove when not needed.
/** @see RecentsAnimationController#mNavigationBarAttachedToApp */
private boolean mNavBarAttachedToApp = false;
private int mNavBarDisplayId = INVALID_DISPLAY;
private int mRecentsDisplayId = INVALID_DISPLAY;
Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
@@ -169,6 +172,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return mSyncId;
}
@TransitionFlags
int getFlags() {
return mFlags;
}
/**
* Formally starts the transition. Participants can be collected before this is started,
* but this won't consider itself ready until started -- even if all the participants have
@@ -390,6 +398,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
sendRemoteCallback(mClientAnimationFinishCallback);
legacyRestoreNavigationBarFromApp();
if (mRecentsDisplayId != INVALID_DISPLAY) {
// Clean up input monitors (for recents)
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
}
}
void abort() {
@@ -534,7 +549,43 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
if (dc == null || !dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
if (dc == null) return;
mRecentsDisplayId = displayId;
// Recents has an input-consumer to grab input from the "live tile" app. Set that up here
final InputConsumerImpl recentsAnimationInputConsumer =
dc.getInputMonitor().getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
if (recentsAnimationInputConsumer != null) {
// find the top-most going-away activity and the recents activity. The top-most
// is used as layer reference while the recents is used for registering the consumer
// override.
ActivityRecord recentsActivity = null;
ActivityRecord topActivity = null;
for (int i = 0; i < info.getChanges().size(); ++i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getTaskInfo() == null) continue;
final Task task = Task.fromWindowContainerToken(
info.getChanges().get(i).getTaskInfo().token);
if (task == null) continue;
final int activityType = change.getTaskInfo().topActivityType;
final boolean isRecents = activityType == ACTIVITY_TYPE_HOME
|| activityType == ACTIVITY_TYPE_RECENTS;
if (isRecents && recentsActivity == null) {
recentsActivity = task.getTopVisibleActivity();
} else if (!isRecents && topActivity == null) {
topActivity = task.getTopNonFinishingActivity();
}
}
if (recentsActivity != null && topActivity != null) {
recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(
topActivity.getBounds());
dc.getInputMonitor().setActiveRecents(recentsActivity, topActivity);
}
}
// The rest of this function handles nav-bar reparenting
if (!dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
// Skip the case where the nav bar is controlled by fade rotation.
|| dc.getFadeRotationAnimationController() != null) {
return;
@@ -561,7 +612,6 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return;
}
mNavBarAttachedToApp = true;
mNavBarDisplayId = displayId;
navWindow.mToken.cancelAnimation();
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
@@ -585,12 +635,17 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (!mNavBarAttachedToApp) return;
mNavBarAttachedToApp = false;
if (mRecentsDisplayId == INVALID_DISPLAY) {
Slog.e(TAG, "Reparented navigation bar without a valid display");
mRecentsDisplayId = DEFAULT_DISPLAY;
}
if (mController.mStatusBar != null) {
mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mNavBarDisplayId, true);
mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mRecentsDisplayId, true);
}
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(mNavBarDisplayId);
mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
if (navWindow == null) return;
navWindow.setSurfaceTranslationY(0);