Merge "Hook up nav-bar attach/detach logic to Shell Transitions" into sc-v2-dev

This commit is contained in:
Evan Rosky
2021-05-21 23:28:32 +00:00
committed by Android (Google) Code Review
8 changed files with 201 additions and 3 deletions

View File

@@ -475,6 +475,19 @@ public class ActivityTaskManager {
} }
} }
/**
* Detaches the navigation bar from the app it was attached to during a transition.
* @hide
*/
@RequiresPermission(android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
public void detachNavigationBarFromApp(@NonNull IBinder transition) {
try {
getService().detachNavigationBarFromApp(transition);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** /**
* Information you can retrieve about a root task in the system. * Information you can retrieve about a root task in the system.
* @hide * @hide

View File

@@ -330,4 +330,10 @@ interface IActivityTaskManager {
* When the Picture-in-picture state has changed. * When the Picture-in-picture state has changed.
*/ */
void onPictureInPictureStateChanged(in PictureInPictureUiState pipState); void onPictureInPictureStateChanged(in PictureInPictureUiState pipState);
/**
* Re-attach navbar to the display during a recents transition.
* TODO(188595497): Remove this once navbar attachment is in shell.
*/
void detachNavigationBarFromApp(in IBinder transition);
} }

View File

@@ -466,6 +466,13 @@ public interface WindowManager extends ViewManager {
*/ */
int TRANSIT_FLAG_KEYGUARD_LOCKED = 0x40; int TRANSIT_FLAG_KEYGUARD_LOCKED = 0x40;
/**
* Transition flag: Indicates that this transition is for recents animation.
* TODO(b/188669821): Remove once special-case logic moves to shell.
* @hide
*/
int TRANSIT_FLAG_IS_RECENTS = 0x80;
/** /**
* @hide * @hide
*/ */
@@ -476,7 +483,8 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION, TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
TRANSIT_FLAG_APP_CRASHED, TRANSIT_FLAG_APP_CRASHED,
TRANSIT_FLAG_OPEN_BEHIND, TRANSIT_FLAG_OPEN_BEHIND,
TRANSIT_FLAG_KEYGUARD_LOCKED TRANSIT_FLAG_KEYGUARD_LOCKED,
TRANSIT_FLAG_IS_RECENTS
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {} @interface TransitionFlags {}

View File

@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ActivityTaskManager;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcelable; import android.os.Parcelable;
@@ -135,7 +136,7 @@ public class RemoteTransitionCompat implements Parcelable {
} }
t.apply(); t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTask, mRecentsSession.setup(controller, info, finishedCallback, pausingTask,
leashMap); leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect()); new Rect());
} }
@@ -178,10 +179,11 @@ public class RemoteTransitionCompat implements Parcelable {
private TransitionInfo mInfo = null; private TransitionInfo mInfo = null;
private SurfaceControl mOpeningLeash = null; private SurfaceControl mOpeningLeash = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
ArrayMap<SurfaceControl, SurfaceControl> leashMap) { ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
if (mInfo != null) { if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while" throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active."); + " recents is already active.");
@@ -191,6 +193,7 @@ public class RemoteTransitionCompat implements Parcelable {
mFinishCB = finishCB; mFinishCB = finishCB;
mPausingTask = pausingTask; mPausingTask = pausingTask;
mLeashMap = leashMap; mLeashMap = leashMap;
mTransition = transition;
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@@ -298,6 +301,7 @@ public class RemoteTransitionCompat implements Parcelable {
mInfo = null; mInfo = null;
mOpeningLeash = null; mOpeningLeash = null;
mLeashMap = null; mLeashMap = null;
mTransition = null;
} }
@Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
@@ -318,6 +322,17 @@ public class RemoteTransitionCompat implements Parcelable {
@Override public boolean removeTask(int taskId) { @Override public boolean removeTask(int taskId) {
return mWrapped != null ? mWrapped.removeTask(taskId) : false; return mWrapped != null ? mWrapped.removeTask(taskId) : false;
} }
/**
* @see IRecentsAnimationController#detachNavigationBarFromApp
*/
@Override public void detachNavigationBarFromApp(boolean moveHomeToTop) {
try {
ActivityTaskManager.getService().detachNavigationBarFromApp(mTransition);
} catch (RemoteException e) {
Log.e(TAG, "Failed to detach the navigation bar from app", e);
}
}
} }

View File

@@ -28,6 +28,7 @@ import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -1547,6 +1548,11 @@ class ActivityStarter {
newTransition.setRemoteTransition(remoteTransition); newTransition.setRemoteTransition(remoteTransition);
} }
mService.getTransitionController().collect(r); mService.getTransitionController().collect(r);
// TODO(b/188669821): Remove when navbar reparenting moves to shell
if (r.getActivityType() == ACTIVITY_TYPE_HOME && r.getOptions() != null
&& r.getOptions().getTransientLaunch()) {
mService.getTransitionController().setIsLegacyRecents();
}
try { try {
mService.deferWindowLayout(); mService.deferWindowLayout();
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");

View File

@@ -3721,6 +3721,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} }
} }
@Override
public void detachNavigationBarFromApp(@NonNull IBinder transition) {
mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
"detachNavigationBarFromApp");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
getTransitionController().legacyDetachNavigationBarFromApp(transition);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
void dumpLastANRLocked(PrintWriter pw) { void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)"); pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) { if (mLastANRState == null) {

View File

@@ -16,10 +16,13 @@
package com.android.server.wm; package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -128,6 +131,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
private @TransitionState int mState = STATE_COLLECTING; private @TransitionState int mState = STATE_COLLECTING;
private boolean mReadyCalled = false; private boolean mReadyCalled = false;
// TODO(b/188595497): remove when not needed.
/** @see RecentsAnimationController#mNavigationBarAttachedToApp */
private boolean mNavBarAttachedToApp = false;
private int mNavBarDisplayId = INVALID_DISPLAY;
Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags, Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) { TransitionController controller, BLASTSyncEngine syncEngine) {
mType = type; mType = type;
@@ -137,6 +145,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mSyncId = mSyncEngine.startSyncSet(this); mSyncId = mSyncEngine.startSyncSet(this);
} }
void addFlag(int flag) {
mFlags |= flag;
}
@VisibleForTesting @VisibleForTesting
int getSyncId() { int getSyncId() {
return mSyncId; return mSyncId;
@@ -299,6 +311,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
wt.commitVisibility(false /* visible */); wt.commitVisibility(false /* visible */);
} }
} }
legacyRestoreNavigationBarFromApp();
} }
void abort() { void abort() {
@@ -353,6 +367,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
info.setAnimationOptions(mOverrideOptions); info.setAnimationOptions(mOverrideOptions);
// TODO(b/188669821): Move to animation impl in shell.
handleLegacyRecentsStartBehavior(displayId, info);
handleNonAppWindowsInTransition(displayId, mType, mFlags); handleNonAppWindowsInTransition(displayId, mType, mFlags);
// Manually show any activities that are visibleRequested. This is needed to properly // Manually show any activities that are visibleRequested. This is needed to properly
@@ -407,6 +424,100 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
finishTransition(); finishTransition();
} }
/** @see RecentsAnimationController#attachNavigationBarToApp */
private void handleLegacyRecentsStartBehavior(int displayId, TransitionInfo info) {
if ((mFlags & TRANSIT_FLAG_IS_RECENTS) == 0) {
return;
}
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
if (dc == null || !dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
// Skip the case where the nav bar is controlled by fade rotation.
|| dc.getFadeRotationAnimationController() != null) {
return;
}
WindowContainer topWC = null;
// Find the top-most non-home, closing app.
for (int i = 0; i < info.getChanges().size(); ++i) {
final TransitionInfo.Change c = info.getChanges().get(i);
if (c.getTaskInfo() == null || c.getTaskInfo().displayId != displayId
|| c.getTaskInfo().getActivityType() != ACTIVITY_TYPE_STANDARD
|| !(c.getMode() == TRANSIT_CLOSE || c.getMode() == TRANSIT_TO_BACK)) {
continue;
}
topWC = WindowContainer.fromBinder(c.getContainer().asBinder());
break;
}
if (topWC == null || topWC.inMultiWindowMode()) {
return;
}
final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
if (navWindow == null || navWindow.mToken == null) {
return;
}
mNavBarAttachedToApp = true;
mNavBarDisplayId = displayId;
navWindow.mToken.cancelAnimation();
final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
t.reparent(navSurfaceControl, topWC.getSurfaceControl());
t.show(navSurfaceControl);
final WindowContainer imeContainer = dc.getImeContainer();
if (imeContainer.isVisible()) {
t.setRelativeLayer(navSurfaceControl, imeContainer.getSurfaceControl(), 1);
} else {
// Place the nav bar on top of anything else in the top activity.
t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
}
if (mController.mStatusBar != null) {
mController.mStatusBar.setNavigationBarLumaSamplingEnabled(displayId, false);
}
}
/** @see RecentsAnimationController#restoreNavigationBarFromApp */
void legacyRestoreNavigationBarFromApp() {
if (!mNavBarAttachedToApp) return;
mNavBarAttachedToApp = false;
if (mController.mStatusBar != null) {
mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mNavBarDisplayId, true);
}
final DisplayContent dc =
mController.mAtm.mRootWindowContainer.getDisplayContent(mNavBarDisplayId);
final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
if (navWindow == null) return;
navWindow.setSurfaceTranslationY(0);
final WindowToken navToken = navWindow.mToken;
if (navToken == null) return;
final SurfaceControl.Transaction t = dc.getPendingTransaction();
final WindowContainer parent = navToken.getParent();
t.setLayer(navToken.getSurfaceControl(), navToken.getLastLayer());
boolean animate = false;
// Search for the home task. If it is supposed to be visible, then the navbar is not at
// the bottom of the screen, so we need to animate it.
for (int i = 0; i < mTargets.size(); ++i) {
final Task task = mTargets.valueAt(i).asTask();
if (task == null || !task.isHomeOrRecentsRootTask()) continue;
animate = task.isVisibleRequested();
break;
}
if (animate) {
final NavBarFadeAnimationController controller =
new NavBarFadeAnimationController(dc);
controller.fadeWindowToken(true);
} else {
// Reparent the SurfaceControl of nav bar token back.
t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
}
}
private void handleNonAppWindowsInTransition(int displayId, private void handleNonAppWindowsInTransition(int displayId,
@WindowManager.TransitionType int transit, int flags) { @WindowManager.TransitionType int transit, int flags) {
final DisplayContent dc = final DisplayContent dc =

View File

@@ -17,6 +17,7 @@
package com.android.server.wm; package com.android.server.wm;
import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN;
import android.annotation.NonNull; import android.annotation.NonNull;
@@ -33,6 +34,8 @@ import android.window.TransitionRequestInfo;
import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.util.ArrayList; import java.util.ArrayList;
@@ -63,8 +66,12 @@ class TransitionController {
/** The transition currently being constructed (collecting participants). */ /** The transition currently being constructed (collecting participants). */
private Transition mCollectingTransition = null; private Transition mCollectingTransition = null;
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
TransitionController(ActivityTaskManagerService atm) { TransitionController(ActivityTaskManagerService atm) {
mAtm = atm; mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
} }
/** @see #createTransition(int, int) */ /** @see #createTransition(int, int) */
@@ -286,4 +293,22 @@ class TransitionController {
mCollectingTransition = null; mCollectingTransition = null;
} }
/**
* Explicitly mark the collectingTransition as being part of recents gesture. Used for legacy
* behaviors.
* TODO(b/188669821): Remove once legacy recents behavior is moved to shell.
*/
void setIsLegacyRecents() {
if (mCollectingTransition == null) return;
mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS);
}
void legacyDetachNavigationBarFromApp(@NonNull IBinder token) {
final Transition transition = Transition.fromBinder(token);
if (transition == null || !mPlayingTransitions.contains(transition)) {
Slog.e(TAG, "Transition isn't playing: " + token);
return;
}
transition.legacyRestoreNavigationBarFromApp();
}
} }