Merge "Hook up nav-bar attach/detach logic to Shell Transitions" into sc-v2-dev
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user