diff options
author | 2020-04-30 23:38:56 +0000 | |
---|---|---|
committer | 2020-04-30 23:38:56 +0000 | |
commit | 28c136e1cb243730b86f94aa8237137d4f6d8ff9 (patch) | |
tree | d1f115253c3d25046c27ed67759d9962076a0f84 | |
parent | 6ff27423b86b9f6b05859f9f5e0390992fe41be1 (diff) | |
parent | 5711b8fdaf2d99414c8167d142c140c02301c64c (diff) |
Merge "Move PIP/MW mode callbacks to be on the client side" into rvc-dev
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 e19d5ecdd7d2..e97ebd7eee06 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; @@ -3329,6 +3334,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); @@ -3752,32 +3759,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) { @@ -5274,8 +5255,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. @@ -5558,6 +5546,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; @@ -5752,6 +5744,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 0474af268b8e..9edc03eaf3c3 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 1340b04148fa..68c6627c3d24 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. */ |