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:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user