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.
* @hide

View File

@@ -330,4 +330,10 @@ interface IActivityTaskManager {
* When the Picture-in-picture state has changed.
*/
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;
/**
* 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
*/
@@ -476,7 +483,8 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
TRANSIT_FLAG_APP_CRASHED,
TRANSIT_FLAG_OPEN_BEHIND,
TRANSIT_FLAG_KEYGUARD_LOCKED
TRANSIT_FLAG_KEYGUARD_LOCKED,
TRANSIT_FLAG_IS_RECENTS
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}

View File

@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcelable;
@@ -135,7 +136,7 @@ public class RemoteTransitionCompat implements Parcelable {
}
t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTask,
leashMap);
leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
}
@@ -178,10 +179,11 @@ public class RemoteTransitionCompat implements Parcelable {
private TransitionInfo mInfo = null;
private SurfaceControl mOpeningLeash = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -191,6 +193,7 @@ public class RemoteTransitionCompat implements Parcelable {
mFinishCB = finishCB;
mPausingTask = pausingTask;
mLeashMap = leashMap;
mTransition = transition;
}
@SuppressLint("NewApi")
@@ -298,6 +301,7 @@ public class RemoteTransitionCompat implements Parcelable {
mInfo = null;
mOpeningLeash = null;
mLeashMap = null;
mTransition = null;
}
@Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
@@ -318,6 +322,17 @@ public class RemoteTransitionCompat implements Parcelable {
@Override public boolean removeTask(int taskId) {
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_TASK_TO_FRONT;
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_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -1547,6 +1548,11 @@ class ActivityStarter {
newTransition.setRemoteTransition(remoteTransition);
}
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 {
mService.deferWindowLayout();
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) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {

View File

@@ -16,10 +16,13 @@
package com.android.server.wm;
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.TRANSIT_CHANGE;
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_SUBTLE_ANIMATION;
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 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,
TransitionController controller, BLASTSyncEngine syncEngine) {
mType = type;
@@ -137,6 +145,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mSyncId = mSyncEngine.startSyncSet(this);
}
void addFlag(int flag) {
mFlags |= flag;
}
@VisibleForTesting
int getSyncId() {
return mSyncId;
@@ -299,6 +311,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
wt.commitVisibility(false /* visible */);
}
}
legacyRestoreNavigationBarFromApp();
}
void abort() {
@@ -353,6 +367,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
info.setAnimationOptions(mOverrideOptions);
// TODO(b/188669821): Move to animation impl in shell.
handleLegacyRecentsStartBehavior(displayId, info);
handleNonAppWindowsInTransition(displayId, mType, mFlags);
// Manually show any activities that are visibleRequested. This is needed to properly
@@ -407,6 +424,100 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
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,
@WindowManager.TransitionType int transit, int flags) {
final DisplayContent dc =

View File

@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
import static android.view.WindowManager.TRANSIT_OPEN;
import android.annotation.NonNull;
@@ -33,6 +34,8 @@ import android.window.TransitionRequestInfo;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.util.ArrayList;
@@ -63,8 +66,12 @@ class TransitionController {
/** The transition currently being constructed (collecting participants). */
private Transition mCollectingTransition = null;
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
TransitionController(ActivityTaskManagerService atm) {
mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
}
/** @see #createTransition(int, int) */
@@ -286,4 +293,22 @@ class TransitionController {
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();
}
}