summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hongwei Wang <hwwang@google.com> 2020-04-30 23:38:56 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-30 23:38:56 +0000
commit28c136e1cb243730b86f94aa8237137d4f6d8ff9 (patch)
treed1f115253c3d25046c27ed67759d9962076a0f84
parent6ff27423b86b9f6b05859f9f5e0390992fe41be1 (diff)
parent5711b8fdaf2d99414c8167d142c140c02301c64c (diff)
Merge "Move PIP/MW mode callbacks to be on the client side" into rvc-dev
-rw-r--r--core/java/android/app/Activity.java12
-rw-r--r--core/java/android/app/ActivityThread.java73
-rw-r--r--core/java/android/app/ClientTransactionHandler.java8
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl2
-rw-r--r--core/java/android/app/WindowConfiguration.java10
-rw-r--r--core/java/android/app/servertransaction/MultiWindowModeChangeItem.java121
-rw-r--r--core/java/android/app/servertransaction/PipModeChangeItem.java119
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java30
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java28
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java68
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java32
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java5
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. */