From 1b5d055f2ea3823b62d694ded7ec19f18d2b1777 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 6 Apr 2020 19:28:49 -0700 Subject: Keep task hidden until task appeared - If the task is previously not visible or has no visible children at the point when we start controlling it in the task org, hide the task until we send taskAppeared to ensure that the task org can reparent and show it otherwise we could see a flash of the task. This happens mainly from two cases: - when starting a new task with a given win mode, we show it and wait for first draw before notifying the task org - when transitioning into pip from swipe up, the activity is hidden and when it requests to enter pip is made visible again Since we are hiding the task w/ the pending transaction, we also need to defer all task org callbacks until that's applied to ensure proper lifecycle of the calls. - Also skip app transitions for task org tasks for now This reverts commit d2fb07e4f632af9ab16667c58b1c1d40711f1544. Bug: 152809695 Bug: 152134460 Test: Open a bubble, ensure that we don't see the task in fullscreen first. Enter pip, ensure that we don't see flash of the task before SysUI can fade it in. Test: atest PipAnimationControllerTest Test: atest TaskOrganizerTests Test: atest SplitScreenTests Change-Id: I9f1fc5931df1d69a7086c02b633347162cda94bf --- .../android/window/TaskOrganizerTaskEmbedder.java | 4 +- .../systemui/pip/PipAnimationController.java | 2 + .../systemui/pip/PipAnimationControllerTest.java | 5 +- services/core/java/com/android/server/wm/Task.java | 11 ++ .../android/server/wm/TaskOrganizerController.java | 128 +++++++++++++++++---- .../com/android/server/wm/WindowContainer.java | 5 + .../com/android/server/wm/TaskOrganizerTests.java | 9 ++ 7 files changed, 141 insertions(+), 23 deletions(-) diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java index 2091c9398e95..39a0101bbf59 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index d219a9e65a3c..dba43430b490 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -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(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java index 0d66340a3917..56a748497d4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java @@ -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); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index d31939dec509..58326c38f259 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4145,6 +4145,17 @@ class Task extends WindowContainer { // Let the old organizer know it has lost control. sendTaskVanished(); 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(); onTaskOrganizerChanged(); return true; diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 22702dd6b566..243af14fece2 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -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,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 mDeferTaskOrgCallbacksConsumer; + + TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, + Consumer 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 final ITaskOrganizer mOrganizer; + private final TaskOrganizerCallbacks mOrganizer; private final DeathRecipient mDeathRecipient; private final ArrayList mOrganizedTasks = new ArrayList<>(); private final int mUid; private boolean mInterceptBackPressedOnTaskRoot; TaskOrganizerState(ITaskOrganizer organizer, int uid) { - mOrganizer = organizer; + final Consumer 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); @@ -114,7 +195,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { if (t.taskAppearedReady()) { try { t.mTaskAppearedSent = true; - mOrganizer.onTaskAppeared(t.getTaskInfo()); + mOrganizer.onTaskAppeared(t); } catch (Exception e) { Slog.e(TAG, "Exception sending taskAppeared callback" + e); } @@ -125,7 +206,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { if (t.mTaskAppearedSent) { try { t.mTaskAppearedSent = false; - mOrganizer.onTaskVanished(t.getTaskInfo()); + mOrganizer.onTaskVanished(t); } catch (Exception e) { Slog.e(TAG, "Exception sending taskVanished callback" + e); } @@ -136,7 +217,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 +230,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void unlinkDeath() { - mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0); + mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0); } } @@ -159,9 +240,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { private final WeakHashMap mLastSentTaskInfos = new WeakHashMap<>(); private final ArrayList mPendingTaskInfoChanges = new ArrayList<>(); - final ActivityTaskManagerService mService; + private final ActivityTaskManagerService mService; - RunningTaskInfo mTmpTaskInfo; + private RunningTaskInfo mTmpTaskInfo; + private Consumer mDeferTaskOrgCallbacksConsumer; TaskOrganizerController(ActivityTaskManagerService atm) { mService = atm; @@ -172,6 +254,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 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 +354,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,11 +459,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { // change. mTmpTaskInfo = null; - if (task.mTaskOrganizer != null) { - try { - task.mTaskOrganizer.onTaskInfoChanged(newInfo); - } catch (RemoteException e) { - } + if (task.isOrganized()) { + final TaskOrganizerState state = mTaskOrganizerStates.get( + task.mTaskOrganizer.asBinder()); + state.mOrganizer.onTaskInfoChanged(task, newInfo); } } @@ -531,11 +621,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 +638,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j)); final ArrayList 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)); } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f6e952c4cea1..d0def3d0644d 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2207,6 +2207,11 @@ class 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; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java index 06ca6c110613..f275e378ed26 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java @@ -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(); -- cgit v1.2.3-59-g8ed1b From 8b5d23ab108e80a4c6af5253733c3c6cf504e13f Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 6 Apr 2020 19:23:23 -0700 Subject: Fix a couple issues with previous CL (keeping tasks hidden) - Attempting to set the visiblity when the task org is set can happen too early and cause the app to not draw and preventing taskAppeared(). Instead, move this to setHasBeenVisible() to be in line with other cases in the system where we defer setting visibility until the apps are good to go. However, if we do this, we also need the first draw (including the starting window) to trigger setHasBeenVisible() to ensure the task org can hide it in time (the task org will also want to receive the task as soon as possible). As a result of moving it out of when the task org is set on the task the PIP transition then also has to defer setting the visibility of the activity until the first draw. - Also fix a case where we are dispatching task info change before taskAppeared(). There's a brief period where the task has an organizer set, but the task org state has not added that task yet or sent taskAppeared() because it has not yet drawn. But in that state, config changes still happen causing a task info changed call to the task org. Bug: 152809695 Bug: 152134460 Test: Open a bubble, ensure that we don't see the task in fullscreen first. Enter pip, ensure that we don't see flash of the task before SysUI can fade it in. Test: atest PipAnimationControllerTest Test: atest TaskOrganizerTests Test: atest SplitScreenTests Change-Id: I7d2ca2a2e538f07c73fff79686e040c159c1dce3 --- .../java/com/android/server/wm/ActivityRecord.java | 6 ++++ .../com/android/server/wm/RootWindowContainer.java | 13 ++++----- services/core/java/com/android/server/wm/Task.java | 19 ++++++------ .../android/server/wm/TaskOrganizerController.java | 34 +++++++++++++--------- .../java/com/android/server/wm/WindowState.java | 9 ++++-- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c47d2151a958..4e2b745ff409 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -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; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 80b8b5854966..42cd66e4e964 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -38,6 +38,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; @@ -2118,16 +2119,19 @@ class RootWindowContainer extends WindowContainer 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(); @@ -2150,11 +2154,6 @@ class RootWindowContainer extends WindowContainer 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(); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 58326c38f259..50a0ea837df3 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4100,8 +4100,18 @@ class Task extends 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); @@ -4146,15 +4156,6 @@ class Task extends WindowContainer { sendTaskVanished(); 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(); onTaskOrganizerChanged(); diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 243af14fece2..9873031e0138 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -131,6 +131,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } 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 @@ -145,6 +150,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } 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 @@ -193,23 +203,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mOrganizedTasks.add(t); } if (t.taskAppearedReady()) { - try { - t.mTaskAppearedSent = true; - mOrganizer.onTaskAppeared(t); - } 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); - } catch (Exception e) { - Slog.e(TAG, "Exception sending taskVanished callback" + e); - } + t.mTaskAppearedSent = false; + mOrganizer.onTaskVanished(t); } mOrganizedTasks.remove(t); } @@ -460,9 +462,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mTmpTaskInfo = null; 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()); - state.mOrganizer.onTaskInfoChanged(task, newInfo); + if (state != null) { + state.mOrganizer.onTaskInfoChanged(task, newInfo); + } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5a76bac67d64..627fdc342a9a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4274,9 +4274,12 @@ class WindowState extends WindowContainer 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()) { -- cgit v1.2.3-59-g8ed1b