Merge changes I7d2ca2a2,I9f1fc593 into rvc-dev
* changes: Fix a couple issues with previous CL (keeping tasks hidden) Keep task hidden until task appeared
This commit is contained in:
@@ -254,7 +254,9 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
|
||||
mTaskToken = taskInfo.token;
|
||||
mTaskLeash = mTaskToken.getLeash();
|
||||
mTransaction.reparent(mTaskLeash, mSurfaceControl)
|
||||
.show(mSurfaceControl).apply();
|
||||
.show(mTaskLeash)
|
||||
.show(mSurfaceControl)
|
||||
.apply();
|
||||
if (mPendingNotifyBoundsChanged) {
|
||||
// TODO: Either defer show or hide and synchronize show with the resize
|
||||
notifyBoundsChanged();
|
||||
|
||||
@@ -319,6 +319,7 @@ public class PipAnimationController {
|
||||
getSurfaceTransactionHelper()
|
||||
.crop(tx, leash, getDestinationBounds())
|
||||
.round(tx, leash, shouldApplyCornerRadius());
|
||||
tx.show(leash);
|
||||
tx.apply();
|
||||
}
|
||||
};
|
||||
@@ -359,6 +360,7 @@ public class PipAnimationController {
|
||||
getSurfaceTransactionHelper()
|
||||
.alpha(tx, leash, 1f)
|
||||
.round(tx, leash, shouldApplyCornerRadius());
|
||||
tx.show(leash);
|
||||
tx.apply();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
private PipAnimationController mPipAnimationController;
|
||||
|
||||
@Mock
|
||||
private SurfaceControl mLeash;
|
||||
|
||||
@Mock
|
||||
@@ -61,6 +60,10 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
||||
public void setUp() throws Exception {
|
||||
mPipAnimationController = new PipAnimationController(
|
||||
mContext, new PipSurfaceTransactionHelper(mContext));
|
||||
mLeash = new SurfaceControl.Builder()
|
||||
.setContainerLayer()
|
||||
.setName("FakeLeash")
|
||||
.build();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -5212,6 +5212,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
updateReportedVisibilityLocked();
|
||||
}
|
||||
|
||||
void onStartingWindowDrawn() {
|
||||
if (task != null) {
|
||||
task.setHasBeenVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the windows associated app window container are drawn. */
|
||||
void onWindowsDrawn(boolean drawn, long timestampNs) {
|
||||
mDrawn = drawn;
|
||||
|
||||
@@ -37,6 +37,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
|
||||
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
|
||||
|
||||
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
|
||||
@@ -2116,16 +2117,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
|
||||
try {
|
||||
final Task task = r.getTask();
|
||||
|
||||
final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask();
|
||||
|
||||
// This will change the pinned stack's windowing mode to its original mode, ensuring
|
||||
// we only have one stack that is in pinned mode.
|
||||
if (pinnedStack != null) {
|
||||
pinnedStack.dismissPip();
|
||||
}
|
||||
|
||||
final boolean singleActivity = task.getChildCount() == 1;
|
||||
// Set a transition to ensure that we don't immediately try and update the visibility
|
||||
// of the activity entering PIP
|
||||
r.getDisplayContent().prepareAppTransition(TRANSIT_NONE, false);
|
||||
|
||||
final boolean singleActivity = task.getChildCount() == 1;
|
||||
final ActivityStack stack;
|
||||
if (singleActivity) {
|
||||
stack = r.getRootTask();
|
||||
@@ -2148,11 +2152,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
mService.continueWindowLayout();
|
||||
}
|
||||
|
||||
// TODO: revisit the following statement after the animation is moved from WM to SysUI.
|
||||
// Update the visibility of all activities after the they have been reparented to the new
|
||||
// stack. This MUST run after the animation above is scheduled to ensure that the windows
|
||||
// drawn signal is scheduled after the bounds animation start call on the bounds animator
|
||||
// thread.
|
||||
ensureActivitiesVisible(null, 0, false /* preserveWindows */);
|
||||
resumeFocusedStacksTopActivities();
|
||||
|
||||
|
||||
@@ -4098,8 +4098,18 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
}
|
||||
|
||||
void setHasBeenVisible(boolean hasBeenVisible) {
|
||||
final boolean prevHasBeenVisible = mHasBeenVisible;
|
||||
mHasBeenVisible = hasBeenVisible;
|
||||
if (hasBeenVisible) {
|
||||
// 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 && mTaskOrganizer != null && !prevHasBeenVisible) {
|
||||
getPendingTransaction().hide(getSurfaceControl());
|
||||
commitPendingTransaction();
|
||||
}
|
||||
|
||||
sendTaskAppeared();
|
||||
if (!isRootTask()) {
|
||||
getRootTask().setHasBeenVisible(true);
|
||||
@@ -4143,6 +4153,8 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
// Let the old organizer know it has lost control.
|
||||
sendTaskVanished();
|
||||
mTaskOrganizer = organizer;
|
||||
|
||||
|
||||
sendTaskAppeared();
|
||||
onTaskOrganizerChanged();
|
||||
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 android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.Intent;
|
||||
@@ -38,6 +39,7 @@ import android.window.ITaskOrganizer;
|
||||
import android.window.ITaskOrganizerController;
|
||||
import android.window.WindowContainerToken;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -46,6 +48,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Stores the TaskOrganizers associated with a given windowing mode and
|
||||
@@ -81,17 +84,105 @@ 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) {
|
||||
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
|
||||
// Skip if the task has not yet received taskAppeared(), except for tasks created
|
||||
// by the organizer that don't receive that signal
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
|
||||
// Skip if the task has not yet received taskAppeared(), except for tasks created
|
||||
// by the organizer that don't receive that signal
|
||||
return;
|
||||
}
|
||||
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 final ITaskOrganizer mOrganizer;
|
||||
private final TaskOrganizerCallbacks mOrganizer;
|
||||
private final DeathRecipient mDeathRecipient;
|
||||
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
|
||||
private final int mUid;
|
||||
private boolean mInterceptBackPressedOnTaskRoot;
|
||||
|
||||
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);
|
||||
try {
|
||||
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
|
||||
@@ -112,23 +203,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
mOrganizedTasks.add(t);
|
||||
}
|
||||
if (t.taskAppearedReady()) {
|
||||
try {
|
||||
t.mTaskAppearedSent = true;
|
||||
mOrganizer.onTaskAppeared(t.getTaskInfo());
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Exception sending taskAppeared callback" + e);
|
||||
}
|
||||
t.mTaskAppearedSent = true;
|
||||
mOrganizer.onTaskAppeared(t);
|
||||
}
|
||||
}
|
||||
|
||||
void removeTask(Task t) {
|
||||
if (t.mTaskAppearedSent) {
|
||||
try {
|
||||
t.mTaskAppearedSent = false;
|
||||
mOrganizer.onTaskVanished(t.getTaskInfo());
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Exception sending taskVanished callback" + e);
|
||||
}
|
||||
t.mTaskAppearedSent = false;
|
||||
mOrganizer.onTaskVanished(t);
|
||||
}
|
||||
mOrganizedTasks.remove(t);
|
||||
}
|
||||
@@ -136,7 +219,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
void dispose() {
|
||||
releaseTasks();
|
||||
for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
|
||||
mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder());
|
||||
mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +232,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
}
|
||||
|
||||
void unlinkDeath() {
|
||||
mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
|
||||
mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,9 +242,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
|
||||
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) {
|
||||
mService = atm;
|
||||
@@ -172,6 +256,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
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.
|
||||
* If there was already a TaskOrganizer for this windowing mode it will be evicted
|
||||
@@ -263,7 +356,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
return state.mOrganizer;
|
||||
return state.mOrganizer.mTaskOrganizer;
|
||||
}
|
||||
|
||||
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
|
||||
@@ -368,10 +461,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
// change.
|
||||
mTmpTaskInfo = null;
|
||||
|
||||
if (task.mTaskOrganizer != null) {
|
||||
try {
|
||||
task.mTaskOrganizer.onTaskInfoChanged(newInfo);
|
||||
} catch (RemoteException e) {
|
||||
if (task.isOrganized()) {
|
||||
// Because we defer sending taskAppeared() until the app has drawn, we may receive a
|
||||
// configuration change before the state actually has the task registered. As such we
|
||||
// should ignore these change events to the organizer until taskAppeared(). If the task
|
||||
// was created by the organizer, then we always send the info change.
|
||||
final TaskOrganizerState state = mTaskOrganizerStates.get(
|
||||
task.mTaskOrganizer.asBinder());
|
||||
if (state != null) {
|
||||
state.mOrganizer.onTaskInfoChanged(task, newInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -531,11 +629,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e);
|
||||
}
|
||||
state.mOrganizer.onBackPressedOnTaskRoot(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -552,7 +646,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
||||
final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
|
||||
final ArrayList<Task> tasks = state.mOrganizedTasks;
|
||||
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++) {
|
||||
pw.println(innerPrefix + " " + tasks.get(k));
|
||||
}
|
||||
|
||||
@@ -2207,6 +2207,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
|
||||
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
|
||||
boolean isVoiceInteraction) {
|
||||
if (isOrganized()) {
|
||||
// Defer to the task organizer to run animations
|
||||
return null;
|
||||
}
|
||||
|
||||
final DisplayContent displayContent = getDisplayContent();
|
||||
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
|
||||
final int width = displayInfo.appWidth;
|
||||
|
||||
@@ -4274,9 +4274,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
logPerformShow("performShow on ");
|
||||
|
||||
final int drawState = mWinAnimator.mDrawState;
|
||||
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
|
||||
&& mAttrs.type != TYPE_APPLICATION_STARTING && mActivityRecord != null) {
|
||||
mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
|
||||
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
|
||||
if (mAttrs.type != TYPE_APPLICATION_STARTING) {
|
||||
mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
|
||||
} else {
|
||||
mActivityRecord.onStartingWindowDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
|
||||
|
||||
@@ -69,6 +69,8 @@ import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -117,6 +119,13 @@ public class TaskOrganizerTests extends WindowTestsBase {
|
||||
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
|
||||
public void testAppearVanish() throws RemoteException {
|
||||
final ActivityStack stack = createStack();
|
||||
|
||||
Reference in New Issue
Block a user