Merge "Fix open ActivityEmbedding split with Shell transition" into tm-qpr-dev

This commit is contained in:
Chris Li
2022-07-27 06:50:21 +00:00
committed by Android (Google) Code Review
6 changed files with 94 additions and 13 deletions

View File

@@ -3139,6 +3139,12 @@
"group": "WM_DEBUG_LOCKTASK", "group": "WM_DEBUG_LOCKTASK",
"at": "com\/android\/server\/wm\/LockTaskController.java" "at": "com\/android\/server\/wm\/LockTaskController.java"
}, },
"956467125": {
"message": "Reparenting Activity to embedded TaskFragment, but the Activity is not collected",
"level": "WARN",
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/WindowOrganizerController.java"
},
"958338552": { "958338552": {
"message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found", "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
"level": "VERBOSE", "level": "VERBOSE",

View File

@@ -483,11 +483,11 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
postStartTransactionCallbacks.add(t -> postStartTransactionCallbacks.add(t ->
startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish, startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
mTransactionPool, mMainExecutor, mAnimExecutor, mTransactionPool, mMainExecutor, mAnimExecutor,
null /* position */, cornerRadius, clipRect)); change.getEndRelOffset(), cornerRadius, clipRect));
} else { } else {
startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish, startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
mTransactionPool, mMainExecutor, mAnimExecutor, null /* position */, mTransactionPool, mMainExecutor, mAnimExecutor,
cornerRadius, clipRect); change.getEndRelOffset(), cornerRadius, clipRect);
} }
if (info.getAnimationOptions() != null) { if (info.getAnimationOptions() != null) {
@@ -934,7 +934,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
a.restrictDuration(MAX_ANIMATION_DURATION); a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting); a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool, startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
mMainExecutor, mAnimExecutor, new Point(bounds.left, bounds.top), mMainExecutor, mAnimExecutor, change.getEndRelOffset(),
cornerRadius, change.getEndAbsBounds()); cornerRadius, change.getEndAbsBounds());
} }
@@ -959,7 +959,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
a.restrictDuration(MAX_ANIMATION_DURATION); a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting); a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool, startSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
mMainExecutor, mAnimExecutor, null /* position */, mMainExecutor, mAnimExecutor, change.getEndRelOffset(),
cornerRadius, change.getEndAbsBounds()); cornerRadius, change.getEndAbsBounds());
} }

View File

@@ -2973,6 +2973,10 @@ class ActivityStarter {
newParent = candidateTf; newParent = candidateTf;
} }
} }
if (newParent.canHaveEmbeddingActivityTransition(mStartActivity)) {
// Make sure the embedded TaskFragment is included in the start activity transition.
newParent.collectEmbeddedTaskFragmentIfNeeded();
}
if (mStartActivity.getTaskFragment() == null if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) { || mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP); newParent.addChild(mStartActivity, POSITION_TOP);

View File

@@ -2316,6 +2316,26 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return !startBounds.equals(getBounds()); return !startBounds.equals(getBounds());
} }
boolean canHaveEmbeddingActivityTransition(@NonNull ActivityRecord child) {
if (!isOrganizedTaskFragment() || !mTransitionController.isShellTransitionsEnabled()) {
return false;
}
// The activity should request open transition when it is becoming visible.
return child.isVisibleRequested();
}
void collectEmbeddedTaskFragmentIfNeeded() {
if (!isOrganizedTaskFragment() || mTransitionController.isCollecting(this)) {
return;
}
if (getChildCount() == 0) {
// The TaskFragment is new created, and just becoming non-empty.
mTransitionController.collectExistenceChange(this);
} else {
mTransitionController.collect(this);
}
}
@Override @Override
void setSurfaceControl(SurfaceControl sc) { void setSurfaceControl(SurfaceControl sc) {
super.setSurfaceControl(sc); super.setSurfaceControl(sc);

View File

@@ -1149,6 +1149,26 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return false; return false;
} }
private static boolean isTranslucent(@NonNull WindowContainer wc) {
final TaskFragment taskFragment = wc.asTaskFragment();
if (taskFragment != null) {
if (taskFragment.isTranslucent(null /* starting */)) {
return true;
}
final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
if (adjacentTaskFragment != null) {
// Treat the TaskFragment as translucent if its adjacent TF is, otherwise everything
// behind two adjacent TaskFragments are occluded.
return adjacentTaskFragment.isTranslucent(null /* starting */);
}
}
// TODO(b/172695805): hierarchical check. This is non-trivial because for containers
// it is effected by child visibility but needs to work even
// before visibility is committed. This means refactoring some
// checks to use requested visibility.
return !wc.fillsParent();
}
/** /**
* Under some conditions (eg. all visible targets within a parent container are transitioning * Under some conditions (eg. all visible targets within a parent container are transitioning
* the same way) the transition can be "promoted" to the parent container. This means an * the same way) the transition can be "promoted" to the parent container. This means an
@@ -1701,20 +1721,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (mShowWallpaper || wc.showWallpaper()) { if (mShowWallpaper || wc.showWallpaper()) {
flags |= FLAG_SHOW_WALLPAPER; flags |= FLAG_SHOW_WALLPAPER;
} }
if (!wc.fillsParent()) { if (isTranslucent(wc)) {
// TODO(b/172695805): hierarchical check. This is non-trivial because for containers
// it is effected by child visibility but needs to work even
// before visibility is committed. This means refactoring some
// checks to use requested visibility.
flags |= FLAG_TRANSLUCENT; flags |= FLAG_TRANSLUCENT;
} }
final Task task = wc.asTask(); final Task task = wc.asTask();
if (task != null && task.voiceSession != null) { if (task != null && task.voiceSession != null) {
flags |= FLAG_IS_VOICE_INTERACTION; flags |= FLAG_IS_VOICE_INTERACTION;
} }
if (task != null && task.isTranslucent(null)) {
flags |= FLAG_TRANSLUCENT;
}
final ActivityRecord record = wc.asActivityRecord(); final ActivityRecord record = wc.asActivityRecord();
if (record != null) { if (record != null) {
if (record.mUseTransferredAnimation) { if (record.mUseTransferredAnimation) {

View File

@@ -21,6 +21,7 @@ import static android.app.ActivityManager.isStartResultSuccessful;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -837,6 +838,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break; break;
} }
prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(parent,
activity);
activity.reparent(parent, POSITION_TOP); activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE; effects |= TRANSACT_EFFECTS_LIFECYCLE;
break; break;
@@ -1061,6 +1064,41 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects; return effects;
} }
private void prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(
@NonNull TaskFragment taskFragment, @NonNull ActivityRecord activity) {
if (!taskFragment.canHaveEmbeddingActivityTransition(activity)) {
return;
}
// The reparent can happen in the following cases:
// 1. Reparent an existing activity to split when app launches new intent.
// - This happens after app calls to start activity, but before the activity is actually
// started, so we don't expect any collecting transition, but if it does, we can't
// queue the WCT because the start activity won't wait.
// 2. Reparent an existing activity to split to launch placeholder when Task size changed.
// - We expect to have a collecting transition for the Task resize, so just collect.
// 3. Reparent a new launching activity to an always-expand container.
// 4. Reparent a new launching activity to split to launch placeholder together.
// 5. Reparent a new launching activity to an existing split.
// - The new launching activity should have start an OPEN transition, so just collect.
// 6. Reparent PiP activity back to the original Task.
// - This should be part of the exiting PiP transition, so just collect.
if (!taskFragment.getBounds().equals(activity.getBounds()) && activity.isVisible()
&& !mTransitionController.isCollecting()) {
// 1. Reparent an existing activity to split when app launches new intent.
mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE, activity);
}
// We expect the activity to be in the transition already, so just collect the TaskFragment.
if (mTransitionController.isCollecting(activity)) {
taskFragment.collectEmbeddedTaskFragmentIfNeeded();
} else {
ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Reparenting Activity"
+ " to embedded TaskFragment, but the Activity is not collected");
}
}
/** A helper method to send minimum dimension violation error to the client. */ /** A helper method to send minimum dimension violation error to the client. */
private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions, private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
IBinder errorCallbackToken, String reason) { IBinder errorCallbackToken, String reason) {