diff options
| author | 2019-11-15 15:44:12 -0800 | |
|---|---|---|
| committer | 2020-04-30 08:48:09 -0700 | |
| commit | 5711b8fdaf2d99414c8167d142c140c02301c64c (patch) | |
| tree | 2e5263c89c916158ce828c1e07cacdcced851c08 | |
| parent | 265622e3c79afde612d39e4f74635f741cacf4c1 (diff) | |
Move PIP/MW mode callbacks to be on the client side
We now infer the PIP/MW mode change from the new configuration.
Note also that both
- Activity#isInPictureInPictureMode
- Activity#isInMultiWindowMode
infer the current state from the configuration rather than querying
against the WM.
Also in this CL:
- When in removePinnedStackInSurfaceTransaction, keep the pinned stack
hidden till the windowing mode is set to fullscreen, this is to surpress
the attempt to set the activities to be started in reparenting
- When in ActivityRecord#shouldBeVisible, should take account the force
hidden flag, which is not actually in use before
Bug: 144097203
Bug: 142282126
Bug: 138329093
Test: atest ActivityLifecyclePipTests \
ActivityLifecycleSplitScreenTests \
ActivityLifecycleTopResumedStateTests \
PinnedStackTests \
SplitScreenTests \
ActivityTaskManagerServiceTests \
RecentsAnimationTest \
AssistantStackTests \
StartActivityTests \
ActivityVisibilityTests \
MultiDisplaySecurityTests \
MultiDisplaySystemDecorationTests
Change-Id: Ibe032b5e50ba5c6d6bc44ebb54d07ac974ebe656
14 files changed, 94 insertions, 449 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index e0ae750ba5ee..17720a34c424 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2748,11 +2748,7 @@ public class Activity extends ContextThemeWrapper * @return True if the activity is in multi-window mode. */ public boolean isInMultiWindowMode() { - try { - return ActivityTaskManager.getService().isInMultiWindowMode(mToken); - } catch (RemoteException e) { - } - return false; + return mLastDispatchedIsInMultiWindowMode == Boolean.TRUE; } /** @@ -2795,11 +2791,7 @@ public class Activity extends ContextThemeWrapper * @return True if the activity is in picture-in-picture mode. */ public boolean isInPictureInPictureMode() { - try { - return ActivityTaskManager.getService().isInPictureInPictureMode(mToken); - } catch (RemoteException e) { - } - return false; + return mLastDispatchedIsInPictureInPictureMode == Boolean.TRUE; } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 51eaff1ae99f..73566d93afa0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -17,6 +17,8 @@ package android.app; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY; import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; @@ -407,6 +409,9 @@ public final class ActivityThread extends ClientTransactionHandler { @GuardedBy("this") private @Nullable Map<SafeCancellationTransport, CancellationSignal> mRemoteCancellations; + private final Map<IBinder, Integer> mLastReportedWindowingMode = Collections.synchronizedMap( + new ArrayMap<>()); + private static final class ProviderKey { final String authority; final int userId; @@ -3324,6 +3329,8 @@ public final class ActivityThread extends ClientTransactionHandler { " did not call through to super.onCreate()"); } r.activity = activity; + mLastReportedWindowingMode.put(activity.getActivityToken(), + config.windowConfiguration.getWindowingMode()); } r.setState(ON_CREATE); @@ -3747,32 +3754,6 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, - Configuration overrideConfig) { - final ActivityClientRecord r = mActivities.get(token); - if (r != null) { - final Configuration newConfig = new Configuration(mConfiguration); - if (overrideConfig != null) { - newConfig.updateFrom(overrideConfig); - } - r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig); - } - } - - @Override - public void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, - Configuration overrideConfig) { - final ActivityClientRecord r = mActivities.get(token); - if (r != null) { - final Configuration newConfig = new Configuration(mConfiguration); - if (overrideConfig != null) { - newConfig.updateFrom(overrideConfig); - } - r.activity.dispatchPictureInPictureModeChanged(isInPipMode, newConfig); - } - } - - @Override public void handlePictureInPictureRequested(IBinder token) { final ActivityClientRecord r = mActivities.get(token); if (r == null) { @@ -5269,8 +5250,15 @@ public final class ActivityThread extends ClientTransactionHandler { throw e.rethrowFromSystemServer(); } + // Save the current windowing mode to be restored and compared to the new configuration's + // windowing mode (needed because we update the last reported windowing mode when launching + // an activity and we can't tell inside performLaunchActivity whether we are relaunching) + final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault( + r.activity.getActivityToken(), WINDOWING_MODE_UNDEFINED); handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents, pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity"); + mLastReportedWindowingMode.put(r.activity.getActivityToken(), oldWindowingMode); + handleWindowingModeChangeIfNeeded(r.activity, r.activity.mCurrentConfig); if (pendingActions != null) { // Only report a successful relaunch to WindowManager. @@ -5553,6 +5541,10 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalArgumentException("Activity token not set. Is the activity attached?"); } + // multi-window / pip mode changes, if any, should be sent before the configuration change + // callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition + handleWindowingModeChangeIfNeeded(activity, newConfig); + boolean shouldChangeConfig = false; if (activity.mCurrentConfig == null) { shouldChangeConfig = true; @@ -5747,6 +5739,35 @@ public final class ActivityThread extends ClientTransactionHandler { } /** + * Sends windowing mode change callbacks to {@link Activity} if applicable. + * + * See also {@link Activity#onMultiWindowModeChanged(boolean, Configuration)} and + * {@link Activity#onPictureInPictureModeChanged(boolean, Configuration)} + */ + private void handleWindowingModeChangeIfNeeded(Activity activity, + Configuration newConfiguration) { + final int newWindowingMode = newConfiguration.windowConfiguration.getWindowingMode(); + final IBinder token = activity.getActivityToken(); + final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault(token, + WINDOWING_MODE_UNDEFINED); + if (oldWindowingMode == newWindowingMode) return; + // PiP callback is sent before the MW one. + if (newWindowingMode == WINDOWING_MODE_PINNED) { + activity.dispatchPictureInPictureModeChanged(true, newConfiguration); + } else if (oldWindowingMode == WINDOWING_MODE_PINNED) { + activity.dispatchPictureInPictureModeChanged(false, newConfiguration); + } + final boolean wasInMultiWindowMode = WindowConfiguration.inMultiWindowMode( + oldWindowingMode); + final boolean nowInMultiWindowMode = WindowConfiguration.inMultiWindowMode( + newWindowingMode); + if (wasInMultiWindowMode != nowInMultiWindowMode) { + activity.dispatchMultiWindowModeChanged(nowInMultiWindowMode, newConfiguration); + } + mLastReportedWindowingMode.put(token, newWindowingMode); + } + + /** * Updates the application info. * * This only works in the system process. Must be called on the main thread. diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index d2235f10da99..83465b0f8d36 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -146,17 +146,9 @@ public abstract class ClientTransactionHandler { /** Deliver result from another activity. */ public abstract void handleSendResult(IBinder token, List<ResultInfo> results, String reason); - /** Deliver multi-window mode change notification. */ - public abstract void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, - Configuration overrideConfig); - /** Deliver new intent. */ public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents); - /** Deliver picture-in-picture mode change notification. */ - public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, - Configuration overrideConfig); - /** Request that an activity enter picture-in-picture. */ public abstract void handlePictureInPictureRequested(IBinder token); diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index b7ceb6ae1b4c..3ce768944e48 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -300,8 +300,6 @@ interface IActivityTaskManager { void suppressResizeConfigChanges(boolean suppress); boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds); - boolean isInMultiWindowMode(in IBinder token); - boolean isInPictureInPictureMode(in IBinder token); boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params); void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params); void requestPictureInPictureMode(in IBinder token); diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 37e07de9809a..a486b9501e0c 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -727,6 +727,16 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu } /** + * Returns {@code true} if the windowingMode represents a window in multi-window mode. + * I.e. sharing the screen with another activity. + * @hide + */ + public static boolean inMultiWindowMode(int windowingMode) { + return windowingMode != WINDOWING_MODE_FULLSCREEN + && windowingMode != WINDOWING_MODE_UNDEFINED; + } + + /** * Returns true if the windowingMode represents a split window. * @hide */ diff --git a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java deleted file mode 100644 index b1507177f7e8..000000000000 --- a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.servertransaction; - -import android.app.ClientTransactionHandler; -import android.content.res.Configuration; -import android.os.IBinder; -import android.os.Parcel; - -import java.util.Objects; - -/** - * Multi-window mode change message. - * @hide - */ -// TODO(lifecycler): Remove the use of this and just use the configuration change message to -// communicate multi-window mode change with WindowConfiguration. -public class MultiWindowModeChangeItem extends ClientTransactionItem { - - private boolean mIsInMultiWindowMode; - private Configuration mOverrideConfig; - - @Override - public void execute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { - client.handleMultiWindowModeChanged(token, mIsInMultiWindowMode, mOverrideConfig); - } - - - // ObjectPoolItem implementation - - private MultiWindowModeChangeItem() {} - - /** Obtain an instance initialized with provided params. */ - public static MultiWindowModeChangeItem obtain(boolean isInMultiWindowMode, - Configuration overrideConfig) { - MultiWindowModeChangeItem instance = ObjectPool.obtain(MultiWindowModeChangeItem.class); - if (instance == null) { - instance = new MultiWindowModeChangeItem(); - } - instance.mIsInMultiWindowMode = isInMultiWindowMode; - instance.mOverrideConfig = overrideConfig; - - return instance; - } - - @Override - public void recycle() { - mIsInMultiWindowMode = false; - mOverrideConfig = null; - ObjectPool.recycle(this); - } - - - // Parcelable implementation - - /** Write to Parcel. */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeBoolean(mIsInMultiWindowMode); - dest.writeTypedObject(mOverrideConfig, flags); - } - - /** Read from Parcel. */ - private MultiWindowModeChangeItem(Parcel in) { - mIsInMultiWindowMode = in.readBoolean(); - mOverrideConfig = in.readTypedObject(Configuration.CREATOR); - } - - public static final @android.annotation.NonNull Creator<MultiWindowModeChangeItem> CREATOR = - new Creator<MultiWindowModeChangeItem>() { - public MultiWindowModeChangeItem createFromParcel(Parcel in) { - return new MultiWindowModeChangeItem(in); - } - - public MultiWindowModeChangeItem[] newArray(int size) { - return new MultiWindowModeChangeItem[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final MultiWindowModeChangeItem other = (MultiWindowModeChangeItem) o; - return mIsInMultiWindowMode == other.mIsInMultiWindowMode - && Objects.equals(mOverrideConfig, other.mOverrideConfig); - } - - @Override - public int hashCode() { - int result = 17; - result = 31 * result + (mIsInMultiWindowMode ? 1 : 0); - result = 31 * result + mOverrideConfig.hashCode(); - return result; - } - - @Override - public String toString() { - return "MultiWindowModeChangeItem{isInMultiWindowMode=" + mIsInMultiWindowMode - + ",overrideConfig=" + mOverrideConfig + "}"; - } -} diff --git a/core/java/android/app/servertransaction/PipModeChangeItem.java b/core/java/android/app/servertransaction/PipModeChangeItem.java deleted file mode 100644 index 1955897665be..000000000000 --- a/core/java/android/app/servertransaction/PipModeChangeItem.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.servertransaction; - -import android.app.ClientTransactionHandler; -import android.content.res.Configuration; -import android.os.IBinder; -import android.os.Parcel; - -import java.util.Objects; - -/** - * Picture in picture mode change message. - * @hide - */ -// TODO(lifecycler): Remove the use of this and just use the configuration change message to -// communicate multi-window mode change with WindowConfiguration. -public class PipModeChangeItem extends ClientTransactionItem { - - private boolean mIsInPipMode; - private Configuration mOverrideConfig; - - @Override - public void execute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { - client.handlePictureInPictureModeChanged(token, mIsInPipMode, mOverrideConfig); - } - - - // ObjectPoolItem implementation - - private PipModeChangeItem() {} - - /** Obtain an instance initialized with provided params. */ - public static PipModeChangeItem obtain(boolean isInPipMode, Configuration overrideConfig) { - PipModeChangeItem instance = ObjectPool.obtain(PipModeChangeItem.class); - if (instance == null) { - instance = new PipModeChangeItem(); - } - instance.mIsInPipMode = isInPipMode; - instance.mOverrideConfig = overrideConfig; - - return instance; - } - - @Override - public void recycle() { - mIsInPipMode = false; - mOverrideConfig = null; - ObjectPool.recycle(this); - } - - - // Parcelable implementation - - /** Write to Parcel. */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeBoolean(mIsInPipMode); - dest.writeTypedObject(mOverrideConfig, flags); - } - - /** Read from Parcel. */ - private PipModeChangeItem(Parcel in) { - mIsInPipMode = in.readBoolean(); - mOverrideConfig = in.readTypedObject(Configuration.CREATOR); - } - - public static final @android.annotation.NonNull Creator<PipModeChangeItem> CREATOR = - new Creator<PipModeChangeItem>() { - public PipModeChangeItem createFromParcel(Parcel in) { - return new PipModeChangeItem(in); - } - - public PipModeChangeItem[] newArray(int size) { - return new PipModeChangeItem[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final PipModeChangeItem other = (PipModeChangeItem) o; - return mIsInPipMode == other.mIsInPipMode - && Objects.equals(mOverrideConfig, other.mOverrideConfig); - } - - @Override - public int hashCode() { - int result = 17; - result = 31 * result + (mIsInPipMode ? 1 : 0); - result = 31 * result + mOverrideConfig.hashCode(); - return result; - } - - @Override - public String toString() { - return "PipModeChangeItem{isInPipMode=" + mIsInPipMode - + ",overrideConfig=" + mOverrideConfig + "}"; - } -} diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 4b29d59de332..107fe3f3ced5 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -198,21 +198,6 @@ public class ObjectPoolTests { } @Test - public void testRecycleMultiWindowModeChangeItem() { - MultiWindowModeChangeItem emptyItem = MultiWindowModeChangeItem.obtain(false, null); - MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain(true, config()); - assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); - - item.recycle(); - assertEquals(item, emptyItem); - - MultiWindowModeChangeItem item2 = MultiWindowModeChangeItem.obtain(true, config()); - assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); - } - - @Test public void testRecycleNewIntentItem() { NewIntentItem emptyItem = NewIntentItem.obtain(null, false); NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false); @@ -243,21 +228,6 @@ public class ObjectPoolTests { } @Test - public void testRecyclePipModeChangeItem() { - PipModeChangeItem emptyItem = PipModeChangeItem.obtain(false, null); - PipModeChangeItem item = PipModeChangeItem.obtain(true, config()); - assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); - - item.recycle(); - assertEquals(item, emptyItem); - - PipModeChangeItem item2 = PipModeChangeItem.obtain(true, config()); - assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); - } - - @Test public void testRecycleResumeActivityItem() { ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false); ResumeActivityItem item = ResumeActivityItem.obtain(3, true); diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 3766cf72d99e..47f9323a95f9 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -153,34 +153,6 @@ public class TransactionParcelTests { } @Test - public void testPipModeChange() { - // Write to parcel - PipModeChangeItem item = PipModeChangeItem.obtain(true /* isInPipMode */, config()); - writeAndPrepareForReading(item); - - // Read from parcel and assert - PipModeChangeItem result = PipModeChangeItem.CREATOR.createFromParcel(mParcel); - - assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); - } - - @Test - public void testMultiWindowModeChange() { - // Write to parcel - MultiWindowModeChangeItem item = MultiWindowModeChangeItem.obtain( - true /* isInMultiWindowMode */, config()); - writeAndPrepareForReading(item); - - // Read from parcel and assert - MultiWindowModeChangeItem result = - MultiWindowModeChangeItem.CREATOR.createFromParcel(mParcel); - - assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); - } - - @Test public void testDestroy() { DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */, 135 /* configChanges */); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index dcdbfdedb0c8..7bbe5cc9a099 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -235,10 +235,8 @@ import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; import android.app.servertransaction.DestroyActivityItem; import android.app.servertransaction.MoveToDisplayItem; -import android.app.servertransaction.MultiWindowModeChangeItem; import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; -import android.app.servertransaction.PipModeChangeItem; import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StartActivityItem; import android.app.servertransaction.StopActivityItem; @@ -1155,11 +1153,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } - if (task.getStack().deferScheduleMultiWindowModeChanged()) { - // Don't do anything if we are currently deferring multi-window mode change. - return; - } - // An activity is considered to be in multi-window mode if its task isn't fullscreen. final boolean inMultiWindowMode = inMultiWindowMode(); if (inMultiWindowMode != mLastReportedMultiWindowMode) { @@ -1167,20 +1160,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updatePictureInPictureMode(null, false); } else { mLastReportedMultiWindowMode = inMultiWindowMode; - scheduleMultiWindowModeChanged(getConfiguration()); + computeConfigurationAfterMultiWindowModeChange(); + ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, + true /* ignoreVisibility */); } } } - private void scheduleMultiWindowModeChanged(Configuration overrideConfig) { - try { - mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode, overrideConfig)); - } catch (Exception e) { - // If process died, I don't care. - } - } - void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) { if (task == null || task.getStack() == null || !attachedToProcess()) { return; @@ -1188,39 +1174,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { - // Picture-in-picture mode change normal triggers also multi-window mode change - // except transitions between pip and split screen mode, so update that here in order. - // Set the last reported MW state to the same as the PiP state since we haven't yet - // actually resized the task (these callbacks need to proceed the configuration change - // from the resize). - // TODO(110009072): Once we move these callbacks to the client, remove all logic related - // to forcing the update of the picture-in-picture mode as a part of the PiP animation. - final boolean shouldScheduleMultiWindowModeChange = - mLastReportedMultiWindowMode != inMultiWindowMode(); + // Picture-in-picture mode changes also trigger a multi-window mode change as well, so + // update that here in order. Set the last reported MW state to the same as the PiP + // state since we haven't yet actually resized the task (these callbacks need to + // precede the configuration change from the resize. mLastReportedPictureInPictureMode = inPictureInPictureMode; mLastReportedMultiWindowMode = inPictureInPictureMode; - final Configuration newConfig = new Configuration(); if (targetStackBounds != null && !targetStackBounds.isEmpty()) { - newConfig.setTo(task.getRequestedOverrideConfiguration()); - Rect outBounds = newConfig.windowConfiguration.getBounds(); - task.adjustForMinimalTaskDimensions(outBounds, outBounds); - task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); - } - schedulePictureInPictureModeChanged(newConfig); - if (shouldScheduleMultiWindowModeChange) { - scheduleMultiWindowModeChanged(newConfig); + computeConfigurationAfterMultiWindowModeChange(); } + ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, + true /* ignoreVisibility */); } } - private void schedulePictureInPictureModeChanged(Configuration overrideConfig) { - try { - mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - PipModeChangeItem.obtain(mLastReportedPictureInPictureMode, - overrideConfig)); - } catch (Exception e) { - // If process died, no one cares. - } + private void computeConfigurationAfterMultiWindowModeChange() { + final Configuration newConfig = new Configuration(); + newConfig.setTo(task.getRequestedOverrideConfiguration()); + Rect outBounds = newConfig.windowConfiguration.getBounds(); + task.adjustForMinimalTaskDimensions(outBounds, outBounds); + task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); } Task getTask() { @@ -4531,6 +4504,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } + // Activity in a pinned stack should not be visible if the stack is in force hidden state. + // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the stack, which is a + // work around to send onStop before windowing mode change callbacks. + // See also ActivityStackSupervisor#removePinnedStackInSurfaceTransaction + // TODO: Should we ever be visible if the stack/task is invisible? + if (inPinnedWindowingMode() && stack.isForceHidden()) { + return false; + } + // Check if the activity is on a sleeping display, and if it can turn it ON. if (getDisplay().isSleeping()) { final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn() diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 2ab03ce058b2..46b7b28c83ad 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -3344,23 +3344,6 @@ class ActivityStack extends Task { getDisplayContent().getPinnedStackController().setActions(actions); } - /** - * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen - * bounds and we have a deferred PiP mode changed callback set with the animation. - */ - public boolean deferScheduleMultiWindowModeChanged() { - if (inPinnedWindowingMode()) { - // For the pinned stack, the deferring of the multi-window mode changed is tied to the - // transition animation into picture-in-picture, and is called once the animation - // completes, or is interrupted in a way that would leave the stack in a non-fullscreen - // state. - // @see BoundsAnimationController - // @see BoundsAnimationControllerTests - return (mBoundsAnimatingRequested || mBoundsAnimating); - } - return false; - } - public boolean isForceScaled() { return mBoundsAnimating; } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index fe9e5f3ca09e..6f0a339c023e 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -1452,16 +1452,15 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { /** * Workaround: Force-stop all the activities in the pinned stack before we reparent them * to the fullscreen stack. This is to guarantee that when we are removing a stack, - * that the client receives onStop() before it is reparented. We do this by detaching - * the stack from the display so that it will be considered invisible when - * ensureActivitiesVisible() is called, and all of its activities will be marked - * invisible as well and added to the stopping list. After which we process the + * that the client receives onStop() before new windowing mode is set. + * We do this by detaching the stack from the display so that it will be considered + * invisible when ensureActivitiesVisible() is called, and all of its activities will be + * marked invisible as well and added to the stopping list. After which we process the * stopping list by handling the idle. */ stack.cancelAnimation(); stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); activityIdleInternal(null /* idleActivity */, false /* fromTimeout */, true /* processPausingActivities */, null /* configuration */); @@ -1478,6 +1477,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { toDisplay.getDefaultTaskDisplayArea().positionStackAtBottom(stack); } + // Follow on the workaround: activities are kept force hidden till the new windowing + // mode is set. + stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); mRootWindowContainer.resumeFocusedStacksTopActivities(); } finally { @@ -2242,12 +2244,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void scheduleUpdateMultiWindowMode(Task task) { - // If the stack is animating in a way where we will be forcing a multi-mode change at the - // end, then ensure that we defer all in between multi-window mode changes - if (task.getStack().deferScheduleMultiWindowModeChanged()) { - return; - } - final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStackSupervisor::addToMultiWindowModeChangedList, this, PooledLambda.__(ActivityRecord.class)); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 5220fb25af74..511baa540d5a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4036,36 +4036,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - @Override - public boolean isInMultiWindowMode(IBinder token) { - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.isInStackLocked(token); - if (r == null) { - return false; - } - // An activity is consider to be in multi-window mode if its task isn't fullscreen. - return r.inMultiWindowMode(); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - @Override - public boolean isInPictureInPictureMode(IBinder token) { - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - return isInPictureInPictureMode(ActivityRecord.forTokenLocked(token)); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - private boolean isInPictureInPictureMode(ActivityRecord r) { + @VisibleForTesting + boolean isInPictureInPictureMode(ActivityRecord r) { return r != null && r.getRootTask() != null && r.inPinnedWindowingMode() diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 1036af67c0db..51357d1c5d94 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -23,11 +23,9 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.activityTypeToString; import static android.app.WindowConfiguration.windowingModeToString; @@ -391,8 +389,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { public boolean inMultiWindowMode() { /*@WindowConfiguration.WindowingMode*/ int windowingMode = mFullConfiguration.windowConfiguration.getWindowingMode(); - return windowingMode != WINDOWING_MODE_FULLSCREEN - && windowingMode != WINDOWING_MODE_UNDEFINED; + return WindowConfiguration.inMultiWindowMode(windowingMode); } /** Returns true if this container is currently in split-screen windowing mode. */ |