Only override ActivityEmbedding animation for embedded activities
Before, we check if there is any split rule meeting the bounds requirement for the given Task bounds in order to determine whether or not to override the animation. This can cause issue when the apps later unregister the split rules while there is existing split. Also, this is hard to determine as we now have SplitAttributesCalculator which can change the split state for the same bounds. To fix these problem, we now check if the app transition contains any embedded activity (embedded TaskFragment that is not filling Task), to determine if the animation should be played by the organizer. Fix: 242051445 Test: atest WmTests:AppTransitionControllerTest Change-Id: Ie90ba085cab3d4072f47cc3599d0494324fa39a9
This commit is contained in:
@@ -39,13 +39,13 @@ interface ITaskFragmentOrganizerController {
|
||||
* animations if the transition only contains windows that belong to the organized
|
||||
* TaskFragments in the given Task.
|
||||
*/
|
||||
void registerRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId,
|
||||
void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
|
||||
in RemoteAnimationDefinition definition);
|
||||
|
||||
/**
|
||||
* Unregisters remote animations per transition type for the organizer.
|
||||
*/
|
||||
void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId);
|
||||
void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
|
||||
|
||||
/**
|
||||
* Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and
|
||||
|
||||
@@ -140,16 +140,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
/**
|
||||
* Registers remote animations per transition type for the organizer. It will override the
|
||||
* animations if the transition only contains windows that belong to the organized
|
||||
* TaskFragments in the given Task.
|
||||
*
|
||||
* @param taskId overrides if the transition only contains windows belonging to this Task.
|
||||
* TaskFragments, and at least one of the transition window is embedded (not filling the Task).
|
||||
* @hide
|
||||
*/
|
||||
@CallSuper
|
||||
public void registerRemoteAnimations(int taskId,
|
||||
@NonNull RemoteAnimationDefinition definition) {
|
||||
public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
|
||||
try {
|
||||
getController().registerRemoteAnimations(mInterface, taskId, definition);
|
||||
getController().registerRemoteAnimations(mInterface, definition);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -160,9 +157,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
* @hide
|
||||
*/
|
||||
@CallSuper
|
||||
public void unregisterRemoteAnimations(int taskId) {
|
||||
public void unregisterRemoteAnimations() {
|
||||
try {
|
||||
getController().unregisterRemoteAnimations(mInterface, taskId);
|
||||
getController().unregisterRemoteAnimations(mInterface);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.window.TaskFragmentOrganizer;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -79,26 +78,20 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
||||
@Override
|
||||
public void unregisterOrganizer() {
|
||||
if (mAnimationController != null) {
|
||||
mAnimationController.unregisterAllRemoteAnimations();
|
||||
mAnimationController.unregisterRemoteAnimations();
|
||||
mAnimationController = null;
|
||||
}
|
||||
super.unregisterOrganizer();
|
||||
}
|
||||
|
||||
/** Overrides the animation if the transition is on the given Task. */
|
||||
void startOverrideSplitAnimation(int taskId) {
|
||||
/**
|
||||
* Overrides the animation for transitions of embedded activities organized by this organizer.
|
||||
*/
|
||||
void overrideSplitAnimation() {
|
||||
if (mAnimationController == null) {
|
||||
mAnimationController = new TaskFragmentAnimationController(this);
|
||||
}
|
||||
mAnimationController.registerRemoteAnimations(taskId);
|
||||
}
|
||||
|
||||
/** No longer overrides the animation if the transition is on the given Task. */
|
||||
@GuardedBy("mLock")
|
||||
void stopOverrideSplitAnimation(int taskId) {
|
||||
if (mAnimationController != null) {
|
||||
mAnimationController.unregisterRemoteAnimations(taskId);
|
||||
}
|
||||
mAnimationController.registerRemoteAnimations();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -193,7 +193,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
continue;
|
||||
}
|
||||
updateContainersInTask(wct, taskContainer);
|
||||
updateAnimationOverride(taskContainer);
|
||||
}
|
||||
// The WCT should be applied and merged to the device state change transition if
|
||||
// there is one.
|
||||
@@ -208,9 +207,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
synchronized (mLock) {
|
||||
mSplitRules.clear();
|
||||
mSplitRules.addAll(rules);
|
||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||
updateAnimationOverride(mTaskContainers.valueAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +604,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
}
|
||||
if (taskContainer.isEmpty()) {
|
||||
// Cleanup the TaskContainer if it becomes empty.
|
||||
mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
|
||||
mTaskContainers.remove(taskContainer.getTaskId());
|
||||
}
|
||||
return;
|
||||
@@ -618,43 +613,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
@GuardedBy("mLock")
|
||||
private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer,
|
||||
@NonNull Configuration config) {
|
||||
final boolean wasInPip = taskContainer.isInPictureInPicture();
|
||||
final boolean isInPIp = isInPictureInPicture(config);
|
||||
|
||||
// We need to check the animation override when enter/exit PIP or has bounds changed.
|
||||
boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
|
||||
if (taskContainer.setTaskBounds(config.windowConfiguration.getBounds())
|
||||
&& !isInPIp) {
|
||||
// We don't care the bounds change when it has already entered PIP.
|
||||
shouldUpdateAnimationOverride = true;
|
||||
}
|
||||
if (shouldUpdateAnimationOverride) {
|
||||
updateAnimationOverride(taskContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates if we should override transition animation. We only want to override if the Task
|
||||
* bounds is large enough for at least one split rule.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
|
||||
if (ENABLE_SHELL_TRANSITIONS) {
|
||||
// TODO(b/207070762): cleanup with legacy app transition
|
||||
// Animation will be handled by WM Shell with Shell transition enabled.
|
||||
return;
|
||||
}
|
||||
if (!taskContainer.isTaskBoundsInitialized()) {
|
||||
// We don't know about the Task bounds/windowingMode yet.
|
||||
return;
|
||||
}
|
||||
|
||||
// We only want to override if the TaskContainer may show split.
|
||||
if (mayShowSplit(taskContainer)) {
|
||||
mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
|
||||
} else {
|
||||
mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
|
||||
}
|
||||
taskContainer.setTaskBounds(config.windowConfiguration.getBounds());
|
||||
}
|
||||
|
||||
/** Returns whether the given {@link TaskContainer} may show in split. */
|
||||
@@ -1279,7 +1238,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
|
||||
}
|
||||
}
|
||||
updateAnimationOverride(taskContainer);
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
super(executor, controller);
|
||||
mController = controller;
|
||||
registerOrganizer();
|
||||
if (!SplitController.ENABLE_SHELL_TRANSITIONS) {
|
||||
// TODO(b/207070762): cleanup with legacy app transition
|
||||
// Animation will be handled by WM Shell when Shell transition is enabled.
|
||||
overrideSplitAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,13 +18,10 @@ package androidx.window.extensions.embedding;
|
||||
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
|
||||
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
@@ -44,8 +41,7 @@ class TaskFragmentAnimationController {
|
||||
private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
|
||||
@VisibleForTesting
|
||||
final RemoteAnimationDefinition mDefinition;
|
||||
/** Task Ids that we have registered for remote animation. */
|
||||
private final ArraySet<Integer> mRegisterTasks = new ArraySet<>();
|
||||
private boolean mIsRegistered;
|
||||
|
||||
TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
|
||||
mOrganizer = organizer;
|
||||
@@ -54,39 +50,30 @@ class TaskFragmentAnimationController {
|
||||
new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter);
|
||||
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
|
||||
}
|
||||
|
||||
void registerRemoteAnimations(int taskId) {
|
||||
void registerRemoteAnimations() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "registerRemoteAnimations");
|
||||
}
|
||||
if (mRegisterTasks.contains(taskId)) {
|
||||
if (mIsRegistered) {
|
||||
return;
|
||||
}
|
||||
mOrganizer.registerRemoteAnimations(taskId, mDefinition);
|
||||
mRegisterTasks.add(taskId);
|
||||
mOrganizer.registerRemoteAnimations(mDefinition);
|
||||
mIsRegistered = true;
|
||||
}
|
||||
|
||||
void unregisterRemoteAnimations(int taskId) {
|
||||
void unregisterRemoteAnimations() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "unregisterRemoteAnimations");
|
||||
}
|
||||
if (!mRegisterTasks.contains(taskId)) {
|
||||
if (!mIsRegistered) {
|
||||
return;
|
||||
}
|
||||
mOrganizer.unregisterRemoteAnimations(taskId);
|
||||
mRegisterTasks.remove(taskId);
|
||||
}
|
||||
|
||||
void unregisterAllRemoteAnimations() {
|
||||
final ArraySet<Integer> tasks = new ArraySet<>(mRegisterTasks);
|
||||
for (int taskId : tasks) {
|
||||
unregisterRemoteAnimations(taskId);
|
||||
}
|
||||
mOrganizer.unregisterRemoteAnimations();
|
||||
mIsRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@ import static android.os.Process.THREAD_PRIORITY_DISPLAY;
|
||||
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
|
||||
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -169,11 +167,9 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
|
||||
switch (transit) {
|
||||
case TRANSIT_OLD_ACTIVITY_OPEN:
|
||||
case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
|
||||
case TRANSIT_OLD_TASK_OPEN:
|
||||
return createOpenAnimationAdapters(targets);
|
||||
case TRANSIT_OLD_ACTIVITY_CLOSE:
|
||||
case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
|
||||
case TRANSIT_OLD_TASK_CLOSE:
|
||||
return createCloseAnimationAdapters(targets);
|
||||
case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
|
||||
return createChangeAnimationAdapters(targets);
|
||||
|
||||
@@ -18,7 +18,6 @@ package androidx.window.extensions.embedding;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
@@ -26,10 +25,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
@@ -85,35 +82,20 @@ public class JetpackTaskFragmentOrganizerTest {
|
||||
|
||||
@Test
|
||||
public void testUnregisterOrganizer() {
|
||||
mOrganizer.startOverrideSplitAnimation(TASK_ID);
|
||||
mOrganizer.startOverrideSplitAnimation(TASK_ID + 1);
|
||||
mOrganizer.overrideSplitAnimation();
|
||||
mOrganizer.unregisterOrganizer();
|
||||
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1);
|
||||
verify(mOrganizer).unregisterRemoteAnimations();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartOverrideSplitAnimation() {
|
||||
public void testOverrideSplitAnimation() {
|
||||
assertNull(mOrganizer.mAnimationController);
|
||||
|
||||
mOrganizer.startOverrideSplitAnimation(TASK_ID);
|
||||
mOrganizer.overrideSplitAnimation();
|
||||
|
||||
assertNotNull(mOrganizer.mAnimationController);
|
||||
verify(mOrganizer).registerRemoteAnimations(TASK_ID,
|
||||
mOrganizer.mAnimationController.mDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopOverrideSplitAnimation() {
|
||||
mOrganizer.stopOverrideSplitAnimation(TASK_ID);
|
||||
|
||||
verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt());
|
||||
|
||||
mOrganizer.startOverrideSplitAnimation(TASK_ID);
|
||||
mOrganizer.stopOverrideSplitAnimation(TASK_ID);
|
||||
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
|
||||
verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
package androidx.window.extensions.embedding;
|
||||
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -57,41 +54,31 @@ public class TaskFragmentAnimationControllerTest {
|
||||
|
||||
@Test
|
||||
public void testRegisterRemoteAnimations() {
|
||||
mAnimationController.registerRemoteAnimations(TASK_ID);
|
||||
mAnimationController.registerRemoteAnimations();
|
||||
|
||||
verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition);
|
||||
verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
|
||||
|
||||
mAnimationController.registerRemoteAnimations(TASK_ID);
|
||||
mAnimationController.registerRemoteAnimations();
|
||||
|
||||
// No extra call if it has been registered.
|
||||
verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition);
|
||||
verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregisterRemoteAnimations() {
|
||||
mAnimationController.unregisterRemoteAnimations(TASK_ID);
|
||||
mAnimationController.unregisterRemoteAnimations();
|
||||
|
||||
// No call if it is not registered.
|
||||
verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt());
|
||||
verify(mOrganizer, never()).unregisterRemoteAnimations();
|
||||
|
||||
mAnimationController.registerRemoteAnimations(TASK_ID);
|
||||
mAnimationController.unregisterRemoteAnimations(TASK_ID);
|
||||
mAnimationController.registerRemoteAnimations();
|
||||
mAnimationController.unregisterRemoteAnimations();
|
||||
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
|
||||
verify(mOrganizer).unregisterRemoteAnimations();
|
||||
|
||||
mAnimationController.unregisterRemoteAnimations(TASK_ID);
|
||||
mAnimationController.unregisterRemoteAnimations();
|
||||
|
||||
// No extra call if it has been unregistered.
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregisterAllRemoteAnimations() {
|
||||
mAnimationController.registerRemoteAnimations(TASK_ID);
|
||||
mAnimationController.registerRemoteAnimations(TASK_ID + 1);
|
||||
mAnimationController.unregisterAllRemoteAnimations();
|
||||
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
|
||||
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1);
|
||||
verify(mOrganizer).unregisterRemoteAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,6 +561,34 @@ public class AppTransitionController {
|
||||
|| shouldStartWallpaperAnimation(mDisplayContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the transition contains any embedded {@link TaskFragment} that does not fill the
|
||||
* parent {@link Task} before or after the transition.
|
||||
*/
|
||||
private boolean transitionContainsTaskFragmentWithBoundsOverride() {
|
||||
for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) {
|
||||
final WindowContainer wc = mDisplayContent.mChangingContainers.valueAt(i);
|
||||
if (wc.isEmbedded()) {
|
||||
// Contains embedded TaskFragment with bounds changed.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mTempTransitionWindows.clear();
|
||||
mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
|
||||
mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
|
||||
boolean containsTaskFragmentWithBoundsOverride = false;
|
||||
for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) {
|
||||
final ActivityRecord r = mTempTransitionWindows.get(i).asActivityRecord();
|
||||
final TaskFragment tf = r.getTaskFragment();
|
||||
if (tf != null && tf.isEmbeddedWithBoundsOverride()) {
|
||||
containsTaskFragmentWithBoundsOverride = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mTempTransitionWindows.clear();
|
||||
return containsTaskFragmentWithBoundsOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the common parent {@link Task} that is parent of all embedded app windows in the
|
||||
* current transition.
|
||||
@@ -664,12 +692,17 @@ public class AppTransitionController {
|
||||
if (transitionMayContainNonAppWindows(transit)) {
|
||||
return false;
|
||||
}
|
||||
if (!transitionContainsTaskFragmentWithBoundsOverride()) {
|
||||
// No need to play TaskFragment remote animation if all embedded TaskFragment in the
|
||||
// transition fill the Task.
|
||||
return false;
|
||||
}
|
||||
|
||||
final Task task = findParentTaskForAllEmbeddedWindows();
|
||||
final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
|
||||
final RemoteAnimationDefinition definition = organizer != null
|
||||
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
|
||||
.getRemoteAnimationDefinition(organizer, task.mTaskId)
|
||||
.getRemoteAnimationDefinition(organizer)
|
||||
: null;
|
||||
final RemoteAnimationAdapter adapter = definition != null
|
||||
? definition.getAdapter(transit, activityTypes)
|
||||
|
||||
@@ -559,15 +559,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
|
||||
@Override
|
||||
boolean isEmbedded() {
|
||||
if (mIsEmbedded) {
|
||||
return true;
|
||||
}
|
||||
final WindowContainer<?> parent = getParent();
|
||||
if (parent != null) {
|
||||
final TaskFragment taskFragment = parent.asTaskFragment();
|
||||
return taskFragment != null && taskFragment.isEmbedded();
|
||||
}
|
||||
return false;
|
||||
return mIsEmbedded;
|
||||
}
|
||||
|
||||
@EmbeddingCheckResult
|
||||
@@ -2495,6 +2487,22 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
return mTaskFragmentOrganizer != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is an embedded {@link TaskFragment} that does not fill the parent {@link Task}.
|
||||
*/
|
||||
boolean isEmbeddedWithBoundsOverride() {
|
||||
if (!mIsEmbedded) {
|
||||
return false;
|
||||
}
|
||||
final Task task = getTask();
|
||||
if (task == null) {
|
||||
return false;
|
||||
}
|
||||
final Rect taskBounds = task.getBounds();
|
||||
final Rect taskFragBounds = getBounds();
|
||||
return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds);
|
||||
}
|
||||
|
||||
/** Whether the Task should be visible. */
|
||||
boolean isTaskVisibleRequested() {
|
||||
final Task task = getTask();
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -132,12 +131,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Map from Task Id to {@link RemoteAnimationDefinition}.
|
||||
* @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(int,
|
||||
* RemoteAnimationDefinition) )
|
||||
* {@link RemoteAnimationDefinition} for embedded activities transition animation that is
|
||||
* organized by this organizer.
|
||||
*/
|
||||
private final SparseArray<RemoteAnimationDefinition> mRemoteAnimationDefinitions =
|
||||
new SparseArray<>();
|
||||
@Nullable
|
||||
private RemoteAnimationDefinition mRemoteAnimationDefinition;
|
||||
|
||||
/**
|
||||
* Map from {@link TaskFragmentTransaction#getTransactionToken()} to the
|
||||
@@ -453,7 +451,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId,
|
||||
public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull RemoteAnimationDefinition definition) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
@@ -466,20 +464,19 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
if (organizerState == null) {
|
||||
throw new IllegalStateException("The organizer hasn't been registered.");
|
||||
}
|
||||
if (organizerState.mRemoteAnimationDefinitions.contains(taskId)) {
|
||||
if (organizerState.mRemoteAnimationDefinition != null) {
|
||||
throw new IllegalStateException(
|
||||
"The organizer has already registered remote animations="
|
||||
+ organizerState.mRemoteAnimationDefinitions.get(taskId)
|
||||
+ " for TaskId=" + taskId);
|
||||
+ organizerState.mRemoteAnimationDefinition);
|
||||
}
|
||||
|
||||
definition.setCallingPidUid(pid, uid);
|
||||
organizerState.mRemoteAnimationDefinitions.put(taskId, definition);
|
||||
organizerState.mRemoteAnimationDefinition = definition;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) {
|
||||
public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final long uid = Binder.getCallingUid();
|
||||
synchronized (mGlobalLock) {
|
||||
@@ -493,7 +490,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
return;
|
||||
}
|
||||
|
||||
organizerState.mRemoteAnimationDefinitions.remove(taskId);
|
||||
organizerState.mRemoteAnimationDefinition = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,16 +522,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
|
||||
/**
|
||||
* Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
|
||||
* {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
|
||||
* {@code null} if it doesn't.
|
||||
*/
|
||||
@Nullable
|
||||
public RemoteAnimationDefinition getRemoteAnimationDefinition(
|
||||
@NonNull ITaskFragmentOrganizer organizer, int taskId) {
|
||||
@NonNull ITaskFragmentOrganizer organizer) {
|
||||
synchronized (mGlobalLock) {
|
||||
final TaskFragmentOrganizerState organizerState =
|
||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
||||
return organizerState != null
|
||||
? organizerState.mRemoteAnimationDefinitions.get(taskId)
|
||||
? organizerState.mRemoteAnimationDefinition
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@@ -1083,16 +1080,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
return false;
|
||||
}
|
||||
final TaskFragment taskFragment = activity.getOrganizedTaskFragment();
|
||||
if (taskFragment == null) {
|
||||
return false;
|
||||
}
|
||||
final Task parentTask = taskFragment.getTask();
|
||||
if (parentTask != null) {
|
||||
final Rect taskBounds = parentTask.getBounds();
|
||||
final Rect taskFragBounds = taskFragment.getBounds();
|
||||
return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds);
|
||||
}
|
||||
return false;
|
||||
return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
|
||||
@@ -56,6 +57,7 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Rect;
|
||||
import android.gui.DropInputMode;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
@@ -918,7 +920,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
@@ -934,12 +936,78 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final ActivityRecord closingActivity = createActivityRecord(task);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
|
||||
// Make sure the TaskFragment is not embedded.
|
||||
assertFalse(taskFragment.isEmbeddedWithBoundsOverride());
|
||||
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
||||
prepareActivityForAppTransition(closingActivity);
|
||||
prepareActivityForAppTransition(openingActivity);
|
||||
final int uid = 12345;
|
||||
closingActivity.info.applicationInfo.uid = uid;
|
||||
openingActivity.info.applicationInfo.uid = uid;
|
||||
task.effectiveUid = uid;
|
||||
spyOn(mDisplayContent.mAppTransition);
|
||||
|
||||
// Prepare and start transition.
|
||||
prepareAndTriggerAppTransition(openingActivity, closingActivity,
|
||||
null /* changingTaskFragment */);
|
||||
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||
|
||||
// Animation is not run by the remote handler because the activity is filling the Task.
|
||||
assertFalse(remoteAnimationRunner.isAnimationStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final ActivityRecord closingActivity = createActivityRecord(task);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
|
||||
// Make sure the TaskFragment is embedded.
|
||||
taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
final Rect embeddedBounds = new Rect(task.getBounds());
|
||||
embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2;
|
||||
taskFragment.setBounds(embeddedBounds);
|
||||
assertTrue(taskFragment.isEmbeddedWithBoundsOverride());
|
||||
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
||||
prepareActivityForAppTransition(closingActivity);
|
||||
prepareActivityForAppTransition(openingActivity);
|
||||
final int uid = 12345;
|
||||
closingActivity.info.applicationInfo.uid = uid;
|
||||
openingActivity.info.applicationInfo.uid = uid;
|
||||
task.effectiveUid = uid;
|
||||
spyOn(mDisplayContent.mAppTransition);
|
||||
|
||||
// Prepare and start transition.
|
||||
prepareAndTriggerAppTransition(openingActivity, closingActivity,
|
||||
null /* changingTaskFragment */);
|
||||
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||
|
||||
// Animation run by the remote handler.
|
||||
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Closing non-embedded activity.
|
||||
final ActivityRecord closingActivity = createActivityRecord(task);
|
||||
@@ -964,7 +1032,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Closing TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
@@ -991,7 +1059,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Closing activity in Task1.
|
||||
final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
|
||||
@@ -1015,7 +1083,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Closing TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
@@ -1043,7 +1111,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with embedded activity.
|
||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||
@@ -1069,7 +1137,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with embedded activities, one is trusted embedded, and the other
|
||||
// one is untrusted embedded.
|
||||
@@ -1128,7 +1196,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with only trusted embedded activity
|
||||
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
|
||||
@@ -1168,7 +1236,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner);
|
||||
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||
|
||||
// Create a TaskFragment with only trusted embedded activity
|
||||
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
|
||||
@@ -1259,7 +1327,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
/** Registers remote animation for the organizer. */
|
||||
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, int taskId,
|
||||
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
|
||||
TestRemoteAnimationRunner remoteAnimationRunner) {
|
||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
||||
remoteAnimationRunner, 10, 1);
|
||||
@@ -1268,9 +1336,10 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
||||
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
|
||||
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
|
||||
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter);
|
||||
definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
|
||||
definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter);
|
||||
mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
|
||||
mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, taskId,
|
||||
definition);
|
||||
mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
|
||||
}
|
||||
|
||||
private static ITaskFragmentOrganizer getITaskFragmentOrganizer(
|
||||
|
||||
@@ -416,13 +416,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testRegisterRemoteAnimations() {
|
||||
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
|
||||
mController.registerRemoteAnimations(mIOrganizer, mDefinition);
|
||||
|
||||
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
|
||||
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
|
||||
|
||||
mController.unregisterRemoteAnimations(mIOrganizer, TASK_ID);
|
||||
mController.unregisterRemoteAnimations(mIOrganizer);
|
||||
|
||||
assertNull(mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
|
||||
assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user