Merge "Keep task hidden until task appeared" into rvc-dev am: 17849976da
Change-Id: I81b83bdcad1c86382910648f510fb9141c6caf41
This commit is contained in:
@@ -254,7 +254,9 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
|
|||||||
mTaskToken = taskInfo.token;
|
mTaskToken = taskInfo.token;
|
||||||
mTaskLeash = mTaskToken.getLeash();
|
mTaskLeash = mTaskToken.getLeash();
|
||||||
mTransaction.reparent(mTaskLeash, mSurfaceControl)
|
mTransaction.reparent(mTaskLeash, mSurfaceControl)
|
||||||
.show(mSurfaceControl).apply();
|
.show(mTaskLeash)
|
||||||
|
.show(mSurfaceControl)
|
||||||
|
.apply();
|
||||||
if (mPendingNotifyBoundsChanged) {
|
if (mPendingNotifyBoundsChanged) {
|
||||||
// TODO: Either defer show or hide and synchronize show with the resize
|
// TODO: Either defer show or hide and synchronize show with the resize
|
||||||
notifyBoundsChanged();
|
notifyBoundsChanged();
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ public class PipAnimationController {
|
|||||||
getSurfaceTransactionHelper()
|
getSurfaceTransactionHelper()
|
||||||
.crop(tx, leash, getDestinationBounds())
|
.crop(tx, leash, getDestinationBounds())
|
||||||
.round(tx, leash, shouldApplyCornerRadius());
|
.round(tx, leash, shouldApplyCornerRadius());
|
||||||
|
tx.show(leash);
|
||||||
tx.apply();
|
tx.apply();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -359,6 +360,7 @@ public class PipAnimationController {
|
|||||||
getSurfaceTransactionHelper()
|
getSurfaceTransactionHelper()
|
||||||
.alpha(tx, leash, 1f)
|
.alpha(tx, leash, 1f)
|
||||||
.round(tx, leash, shouldApplyCornerRadius());
|
.round(tx, leash, shouldApplyCornerRadius());
|
||||||
|
tx.show(leash);
|
||||||
tx.apply();
|
tx.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
private PipAnimationController mPipAnimationController;
|
private PipAnimationController mPipAnimationController;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SurfaceControl mLeash;
|
private SurfaceControl mLeash;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@@ -61,6 +60,10 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mPipAnimationController = new PipAnimationController(
|
mPipAnimationController = new PipAnimationController(
|
||||||
mContext, new PipSurfaceTransactionHelper(mContext));
|
mContext, new PipSurfaceTransactionHelper(mContext));
|
||||||
|
mLeash = new SurfaceControl.Builder()
|
||||||
|
.setContainerLayer()
|
||||||
|
.setName("FakeLeash")
|
||||||
|
.build();
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4131,6 +4131,17 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
// Let the old organizer know it has lost control.
|
// Let the old organizer know it has lost control.
|
||||||
sendTaskVanished();
|
sendTaskVanished();
|
||||||
mTaskOrganizer = organizer;
|
mTaskOrganizer = organizer;
|
||||||
|
|
||||||
|
// If the task is not yet visible when it is added to the task organizer, then we should
|
||||||
|
// hide it to allow the task organizer to show it when it is properly reparented. We skip
|
||||||
|
// this for tasks created by the organizer because they can synchronously update the leash
|
||||||
|
// before new children are added to the task.
|
||||||
|
if (!mCreatedByOrganizer && organizer != null
|
||||||
|
&& (!getHasBeenVisible() || !hasVisibleChildren())) {
|
||||||
|
getPendingTransaction().hide(getSurfaceControl());
|
||||||
|
commitPendingTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
sendTaskAppeared();
|
sendTaskAppeared();
|
||||||
onTaskOrganizerChanged();
|
onTaskOrganizerChanged();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFI
|
|||||||
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
|
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.app.WindowConfiguration;
|
import android.app.WindowConfiguration;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -38,6 +39,7 @@ import android.window.ITaskOrganizer;
|
|||||||
import android.window.ITaskOrganizerController;
|
import android.window.ITaskOrganizerController;
|
||||||
import android.window.WindowContainerToken;
|
import android.window.WindowContainerToken;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -46,6 +48,7 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the TaskOrganizers associated with a given windowing mode and
|
* Stores the TaskOrganizers associated with a given windowing mode and
|
||||||
@@ -81,17 +84,95 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper class around ITaskOrganizer to ensure that the calls are made in the right
|
||||||
|
* lifecycle order since we may be updating the visibility of task surface controls in a pending
|
||||||
|
* transaction before they are presented to the task org.
|
||||||
|
*/
|
||||||
|
private class TaskOrganizerCallbacks {
|
||||||
|
final WindowManagerService mService;
|
||||||
|
final ITaskOrganizer mTaskOrganizer;
|
||||||
|
final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
|
||||||
|
|
||||||
|
TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
|
||||||
|
Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
|
||||||
|
mService = wm;
|
||||||
|
mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
|
||||||
|
mTaskOrganizer = taskOrg;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBinder getBinder() {
|
||||||
|
return mTaskOrganizer.asBinder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTaskAppeared(Task task) {
|
||||||
|
final RunningTaskInfo taskInfo = task.getTaskInfo();
|
||||||
|
mDeferTaskOrgCallbacksConsumer.accept(() -> {
|
||||||
|
try {
|
||||||
|
mTaskOrganizer.onTaskAppeared(taskInfo);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void onTaskVanished(Task task) {
|
||||||
|
final RunningTaskInfo taskInfo = task.getTaskInfo();
|
||||||
|
mDeferTaskOrgCallbacksConsumer.accept(() -> {
|
||||||
|
try {
|
||||||
|
mTaskOrganizer.onTaskVanished(taskInfo);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Exception sending onTaskVanished callback", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
|
mDeferTaskOrgCallbacksConsumer.accept(() -> {
|
||||||
|
if (!task.isOrganized()) {
|
||||||
|
// This is safe to ignore if the task is no longer organized
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mTaskOrganizer.onTaskInfoChanged(taskInfo);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBackPressedOnTaskRoot(Task task) {
|
||||||
|
mDeferTaskOrgCallbacksConsumer.accept(() -> {
|
||||||
|
if (!task.isOrganized()) {
|
||||||
|
// This is safe to ignore if the task is no longer organized
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class TaskOrganizerState {
|
private class TaskOrganizerState {
|
||||||
private final ITaskOrganizer mOrganizer;
|
private final TaskOrganizerCallbacks mOrganizer;
|
||||||
private final DeathRecipient mDeathRecipient;
|
private final DeathRecipient mDeathRecipient;
|
||||||
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
|
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
|
||||||
private final int mUid;
|
private final int mUid;
|
||||||
private boolean mInterceptBackPressedOnTaskRoot;
|
private boolean mInterceptBackPressedOnTaskRoot;
|
||||||
|
|
||||||
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
|
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
|
||||||
mOrganizer = organizer;
|
final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
|
||||||
|
mDeferTaskOrgCallbacksConsumer != null
|
||||||
|
? mDeferTaskOrgCallbacksConsumer
|
||||||
|
: mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
|
||||||
|
mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
|
||||||
|
deferTaskOrgCallbacksConsumer);
|
||||||
mDeathRecipient = new DeathRecipient(organizer);
|
mDeathRecipient = new DeathRecipient(organizer);
|
||||||
try {
|
try {
|
||||||
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
|
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
|
||||||
@@ -107,26 +188,18 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
|
|
||||||
void addTask(Task t) {
|
void addTask(Task t) {
|
||||||
mOrganizedTasks.add(t);
|
mOrganizedTasks.add(t);
|
||||||
try {
|
mOrganizer.onTaskAppeared(t);
|
||||||
mOrganizer.onTaskAppeared(t.getTaskInfo());
|
|
||||||
} catch (Exception e) {
|
|
||||||
Slog.e(TAG, "Exception sending taskAppeared callback" + e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTask(Task t) {
|
void removeTask(Task t) {
|
||||||
try {
|
|
||||||
mOrganizer.onTaskVanished(t.getTaskInfo());
|
|
||||||
} catch (Exception e) {
|
|
||||||
Slog.e(TAG, "Exception sending taskVanished callback" + e);
|
|
||||||
}
|
|
||||||
mOrganizedTasks.remove(t);
|
mOrganizedTasks.remove(t);
|
||||||
|
mOrganizer.onTaskVanished(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
releaseTasks();
|
releaseTasks();
|
||||||
for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
|
for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
|
||||||
mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder());
|
mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +212,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void unlinkDeath() {
|
void unlinkDeath() {
|
||||||
mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
|
mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,9 +222,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
|
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
|
||||||
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
|
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
|
||||||
|
|
||||||
final ActivityTaskManagerService mService;
|
private final ActivityTaskManagerService mService;
|
||||||
|
|
||||||
RunningTaskInfo mTmpTaskInfo;
|
private RunningTaskInfo mTmpTaskInfo;
|
||||||
|
private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
|
||||||
|
|
||||||
TaskOrganizerController(ActivityTaskManagerService atm) {
|
TaskOrganizerController(ActivityTaskManagerService atm) {
|
||||||
mService = atm;
|
mService = atm;
|
||||||
@@ -162,6 +236,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
|
mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the consumer to run to defer the task org callbacks. Can be overridden while
|
||||||
|
* testing to allow the callbacks to be sent synchronously.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
|
||||||
|
mDeferTaskOrgCallbacksConsumer = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
|
* Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
|
||||||
* If there was already a TaskOrganizer for this windowing mode it will be evicted
|
* If there was already a TaskOrganizer for this windowing mode it will be evicted
|
||||||
@@ -253,7 +336,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
if (state == null) {
|
if (state == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return state.mOrganizer;
|
return state.mOrganizer.mTaskOrganizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
|
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
|
||||||
@@ -358,11 +441,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
// change.
|
// change.
|
||||||
mTmpTaskInfo = null;
|
mTmpTaskInfo = null;
|
||||||
|
|
||||||
if (task.mTaskOrganizer != null) {
|
if (task.isOrganized()) {
|
||||||
try {
|
final TaskOrganizerState state = mTaskOrganizerStates.get(
|
||||||
task.mTaskOrganizer.onTaskInfoChanged(newInfo);
|
task.mTaskOrganizer.asBinder());
|
||||||
} catch (RemoteException e) {
|
state.mOrganizer.onTaskInfoChanged(task, newInfo);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,11 +599,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
state.mOrganizer.onBackPressedOnTaskRoot(task);
|
||||||
state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
|
|
||||||
} catch (Exception e) {
|
|
||||||
Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +616,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
|
final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
|
||||||
final ArrayList<Task> tasks = state.mOrganizedTasks;
|
final ArrayList<Task> tasks = state.mOrganizedTasks;
|
||||||
pw.print(innerPrefix + " ");
|
pw.print(innerPrefix + " ");
|
||||||
pw.println(state.mOrganizer + " uid=" + state.mUid + ":");
|
pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
|
||||||
for (int k = 0; k < tasks.size(); k++) {
|
for (int k = 0; k < tasks.size(); k++) {
|
||||||
pw.println(innerPrefix + " " + tasks.get(k));
|
pw.println(innerPrefix + " " + tasks.get(k));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2180,6 +2180,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
|||||||
|
|
||||||
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
|
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
|
||||||
boolean isVoiceInteraction) {
|
boolean isVoiceInteraction) {
|
||||||
|
if (isOrganized()) {
|
||||||
|
// Defer to the task organizer to run animations
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final DisplayContent displayContent = getDisplayContent();
|
final DisplayContent displayContent = getDisplayContent();
|
||||||
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
|
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
|
||||||
final int width = displayInfo.appWidth;
|
final int width = displayInfo.appWidth;
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ import android.window.WindowContainerTransaction;
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@@ -117,6 +119,13 @@ public class TaskOrganizerTests extends WindowTestsBase {
|
|||||||
return createTaskStackOnDisplay(mDisplayContent);
|
return createTaskStackOnDisplay(mDisplayContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
// We defer callbacks since we need to adjust task surface visibility, but for these tests,
|
||||||
|
// just run the callbacks synchronously
|
||||||
|
mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAppearVanish() throws RemoteException {
|
public void testAppearVanish() throws RemoteException {
|
||||||
final ActivityStack stack = createStack();
|
final ActivityStack stack = createStack();
|
||||||
|
|||||||
Reference in New Issue
Block a user