Merge "Move PIP/MW mode callbacks to be on the client side" into rvc-dev am: 28c136e1cb am: 33e9c04263

Change-Id: Id7c50738ac561a8a716e0f53f10cbf430a889d73
This commit is contained in:
Hongwei Wang
2020-05-01 00:10:01 +00:00
committed by Automerger Merge Worker
14 changed files with 94 additions and 449 deletions

View File

@@ -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;
}
/**

View File

@@ -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);
@@ -3751,32 +3758,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);
@@ -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;
@@ -5751,6 +5743,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.
*

View File

@@ -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);

View File

@@ -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);

View File

@@ -726,6 +726,16 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED;
}
/**
* 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

View File

@@ -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 + "}";
}
}

View File

@@ -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 + "}";
}
}

View File

@@ -197,21 +197,6 @@ public class ObjectPoolTests {
assertFalse(item2.equals(emptyItem));
}
@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);
@@ -242,21 +227,6 @@ public class ObjectPoolTests {
assertFalse(item2.equals(emptyItem));
}
@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);

View File

@@ -152,34 +152,6 @@ public class TransactionParcelTests {
assertTrue(item.equals(result));
}
@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 */,

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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()

View File

@@ -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. */