Loading core/java/android/window/WindowContainerTransaction.java +53 −16 Original line number Diff line number Diff line Loading @@ -351,20 +351,6 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Used in conjunction with a shell-transition call (usually finishTransition). This is * basically a message to the transition system that a particular task should NOT go into * PIP even though it normally would. This is to deal with some edge-case situations where * Recents will "commit" the transition to go home, but then not actually go-home. * @hide */ @NonNull public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; return this; } /** * Resizes a container by providing a bounds in its parent coordinate. * This is only used by {@link TaskFragmentOrganizer}. Loading Loading @@ -913,6 +899,41 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Used in conjunction with a shell-transition call (usually finishTransition). This is * basically a message to the transition system that a particular task should NOT go into * PIP even though it normally would. This is to deal with some edge-case situations where * Recents will "commit" the transition to go home, but then not actually go-home. * @hide */ @NonNull public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; return this; } /** * Sets whether a Task or any of its children can enter picture-in-picture. * When {@code false}, the container and its children won't be able to enter PiP. * * Note: this is different from {@link #setDoNotPip}, which is to temporarily disable PiP during * finishTransition. * @hide */ @NonNull public WindowContainerTransaction setDisablePip( @NonNull WindowContainerToken container, boolean disablePip) { if (!Flags.disallowBubbleToEnterPip()) { throw new IllegalStateException( "Flag " + Flags.FLAG_DISALLOW_BUBBLE_TO_ENTER_PIP + " is not enabled"); } final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_DISABLE_PIP; chg.mDisablePip = disablePip; return this; } /* * =========================================================================================== * Insets Loading Loading @@ -1355,6 +1376,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_RELATIVE_BOUNDS = 1 << 8; public static final int CHANGE_FORCE_EXCLUDED_FROM_RECENTS = 1 << 9; public static final int CHANGE_LAUNCH_NEXT_TO_BUBBLE = 1 << 10; public static final int CHANGE_DISABLE_PIP = 1 << 11; @IntDef(flag = true, prefix = { "CHANGE_" }, value = { CHANGE_FOCUSABLE, Loading @@ -1368,6 +1390,7 @@ public final class WindowContainerTransaction implements Parcelable { CHANGE_RELATIVE_BOUNDS, CHANGE_FORCE_EXCLUDED_FROM_RECENTS, CHANGE_LAUNCH_NEXT_TO_BUBBLE, CHANGE_DISABLE_PIP, }) @Retention(RetentionPolicy.SOURCE) public @interface ChangeMask {} Loading @@ -1379,6 +1402,7 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mForceTranslucent = false; private boolean mDragResizing = false; private boolean mForceExcludedFromRecents = false; private boolean mDisablePip = false; private @ChangeMask int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; Loading @@ -1404,6 +1428,8 @@ public final class WindowContainerTransaction implements Parcelable { mForceTranslucent = in.readBoolean(); mDragResizing = in.readBoolean(); mForceExcludedFromRecents = in.readBoolean(); mLaunchNextToBubble = in.readBoolean(); mDisablePip = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); Loading @@ -1419,7 +1445,6 @@ public final class WindowContainerTransaction implements Parcelable { mWindowingMode = in.readInt(); mActivityWindowingMode = in.readInt(); mLaunchNextToBubble = in.readBoolean(); } /** Loading Loading @@ -1456,6 +1481,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((other.mChangeMask & CHANGE_LAUNCH_NEXT_TO_BUBBLE) != 0) { mLaunchNextToBubble = other.mLaunchNextToBubble; } if ((other.mChangeMask & CHANGE_DISABLE_PIP) != 0) { mDisablePip = other.mDisablePip; } mChangeMask |= other.mChangeMask; if (other.mActivityWindowingMode >= WINDOWING_MODE_UNDEFINED) { mActivityWindowingMode = other.mActivityWindowingMode; Loading Loading @@ -1546,6 +1574,11 @@ public final class WindowContainerTransaction implements Parcelable { return mForceExcludedFromRecents; } /** Gets whether the task is disabled to enter picture-in-picture. */ public boolean getDisablePip() { return mDisablePip; } /** Gets whether the config should be sent to the client at the end of the transition. */ public boolean getConfigAtTransitionEnd() { return mConfigAtTransitionEnd; Loading Loading @@ -1619,6 +1652,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((mChangeMask & CHANGE_FORCE_EXCLUDED_FROM_RECENTS) != 0) { sb.append("forceExcludedFromRecents:" + mForceExcludedFromRecents + ","); } if ((mChangeMask & CHANGE_DISABLE_PIP) != 0) { sb.append("disablePip:" + mDisablePip + ","); } if (mBoundsChangeTransaction != null) { sb.append("hasBoundsTransaction,"); } Loading Loading @@ -1647,6 +1683,8 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeBoolean(mForceTranslucent); dest.writeBoolean(mDragResizing); dest.writeBoolean(mForceExcludedFromRecents); dest.writeBoolean(mLaunchNextToBubble); dest.writeBoolean(mDisablePip); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); Loading @@ -1661,7 +1699,6 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeInt(mWindowingMode); dest.writeInt(mActivityWindowingMode); dest.writeBoolean(mLaunchNextToBubble); } @Override Loading core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -221,3 +221,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { namespace: "windowing_sdk" name: "disallow_bubble_to_enter_pip" description: "Prevent Bubble task to enter picture-in-picture" bug: "389158353" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/wm/ActivityRecord.java +9 −1 Original line number Diff line number Diff line Loading @@ -3190,6 +3190,14 @@ final class ActivityRecord extends WindowToken { && info.supportsPictureInPicture(); } /** * Whether this activity can enter PiP now. This can be {@code false} if the system has disabled * this Task from entering PiP. */ boolean canEnterPictureInPicture() { return supportsPictureInPicture() && (task == null || !task.isDisablePip()); } boolean supportsFreeform() { return supportsFreeformInDisplayArea(getDisplayArea()); } Loading Loading @@ -3252,7 +3260,7 @@ final class ActivityRecord extends WindowToken { * @return whether this activity is currently allowed to enter PIP. */ boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) { if (!supportsPictureInPicture()) { if (!canEnterPictureInPicture()) { return false; } Loading services/core/java/com/android/server/wm/Task.java +38 −0 Original line number Diff line number Diff line Loading @@ -634,6 +634,9 @@ class Task extends TaskFragment { /** @see #isForceExcludedFromRecents() */ private boolean mForceExcludedFromRecents; /** @see #isDisablePip() */ private boolean mDisablePip; private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, Loading Loading @@ -4606,6 +4609,35 @@ class Task extends TaskFragment { mForceExcludedFromRecents = excluded; } /** * Whether this Task and its children are disallowed from entering picture-in-picture. * * This is different from {@link #mSupportsPictureInPicture} which is determined based on the * activity manifest. This flag is set by WM Shell to disable PiP for the current Task status. */ boolean isDisablePip() { if (!Flags.disallowBubbleToEnterPip()) { return false; } if (mDisablePip) { return true; } // Check if PIP is disabled on any parent Task. final WindowContainer parent = getParent(); if (parent != null && parent.asTask() != null) { return parent.asTask().isDisablePip(); } return false; } void setDisablePip(boolean disablePip) { if (!Flags.disallowBubbleToEnterPip()) { Slog.w(TAG, "Flag " + Flags.FLAG_DISALLOW_BUBBLE_TO_ENTER_PIP + " is not enabled"); return; } mDisablePip = disablePip; } boolean isForceHiddenForPinnedTask() { return (mForceHiddenFlags & FLAG_FORCE_HIDDEN_FOR_PINNED_TASK) != 0; } Loading Loading @@ -5392,6 +5424,9 @@ class Task extends TaskFragment { } final ActivityRecord[] candidate = new ActivityRecord[1]; topTask.forAllLeafTaskFragments(tf -> { if (tf.getTask().isDisablePip()) { return false; } // Find the top activity that may enter Pip while pausing. final ActivityRecord topActivity = tf.getTopNonFinishingActivity(); if (topActivity != null && topActivity.isState(RESUMED, PAUSING) Loading Loading @@ -5970,6 +6005,9 @@ class Task extends TaskFragment { if (mLaunchNextToBubble) { pw.println(prefix + " mLaunchNextToBubble=true"); } if (mDisablePip) { pw.println(prefix + " mDisablePip=true"); } if (mLastNonFullscreenBounds != null) { pw.print(prefix); pw.print(" mLastNonFullscreenBounds="); pw.println(mLastNonFullscreenBounds); Loading services/core/java/com/android/server/wm/TaskDisplayArea.java +2 −1 Original line number Diff line number Diff line Loading @@ -1383,9 +1383,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // it can be moved to a new created PIP Task, so WINDOWING_MODE_PINNED is // always valid for Task as long as the device supports it. || (windowingMode == WINDOWING_MODE_PINNED && supportsPip); supportsPip &= !task.isDisablePip(); } else if (r != null) { supportsFreeform = r.supportsFreeformInDisplayArea(this); supportsPip = r.supportsPictureInPicture(); supportsPip = r.canEnterPictureInPicture(); supportsMultiWindow = r.supportsMultiWindowInDisplayArea(this); } } Loading Loading
core/java/android/window/WindowContainerTransaction.java +53 −16 Original line number Diff line number Diff line Loading @@ -351,20 +351,6 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Used in conjunction with a shell-transition call (usually finishTransition). This is * basically a message to the transition system that a particular task should NOT go into * PIP even though it normally would. This is to deal with some edge-case situations where * Recents will "commit" the transition to go home, but then not actually go-home. * @hide */ @NonNull public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; return this; } /** * Resizes a container by providing a bounds in its parent coordinate. * This is only used by {@link TaskFragmentOrganizer}. Loading Loading @@ -913,6 +899,41 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Used in conjunction with a shell-transition call (usually finishTransition). This is * basically a message to the transition system that a particular task should NOT go into * PIP even though it normally would. This is to deal with some edge-case situations where * Recents will "commit" the transition to go home, but then not actually go-home. * @hide */ @NonNull public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; return this; } /** * Sets whether a Task or any of its children can enter picture-in-picture. * When {@code false}, the container and its children won't be able to enter PiP. * * Note: this is different from {@link #setDoNotPip}, which is to temporarily disable PiP during * finishTransition. * @hide */ @NonNull public WindowContainerTransaction setDisablePip( @NonNull WindowContainerToken container, boolean disablePip) { if (!Flags.disallowBubbleToEnterPip()) { throw new IllegalStateException( "Flag " + Flags.FLAG_DISALLOW_BUBBLE_TO_ENTER_PIP + " is not enabled"); } final Change chg = getOrCreateChange(container.asBinder()); chg.mChangeMask |= Change.CHANGE_DISABLE_PIP; chg.mDisablePip = disablePip; return this; } /* * =========================================================================================== * Insets Loading Loading @@ -1355,6 +1376,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_RELATIVE_BOUNDS = 1 << 8; public static final int CHANGE_FORCE_EXCLUDED_FROM_RECENTS = 1 << 9; public static final int CHANGE_LAUNCH_NEXT_TO_BUBBLE = 1 << 10; public static final int CHANGE_DISABLE_PIP = 1 << 11; @IntDef(flag = true, prefix = { "CHANGE_" }, value = { CHANGE_FOCUSABLE, Loading @@ -1368,6 +1390,7 @@ public final class WindowContainerTransaction implements Parcelable { CHANGE_RELATIVE_BOUNDS, CHANGE_FORCE_EXCLUDED_FROM_RECENTS, CHANGE_LAUNCH_NEXT_TO_BUBBLE, CHANGE_DISABLE_PIP, }) @Retention(RetentionPolicy.SOURCE) public @interface ChangeMask {} Loading @@ -1379,6 +1402,7 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mForceTranslucent = false; private boolean mDragResizing = false; private boolean mForceExcludedFromRecents = false; private boolean mDisablePip = false; private @ChangeMask int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; Loading @@ -1404,6 +1428,8 @@ public final class WindowContainerTransaction implements Parcelable { mForceTranslucent = in.readBoolean(); mDragResizing = in.readBoolean(); mForceExcludedFromRecents = in.readBoolean(); mLaunchNextToBubble = in.readBoolean(); mDisablePip = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); Loading @@ -1419,7 +1445,6 @@ public final class WindowContainerTransaction implements Parcelable { mWindowingMode = in.readInt(); mActivityWindowingMode = in.readInt(); mLaunchNextToBubble = in.readBoolean(); } /** Loading Loading @@ -1456,6 +1481,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((other.mChangeMask & CHANGE_LAUNCH_NEXT_TO_BUBBLE) != 0) { mLaunchNextToBubble = other.mLaunchNextToBubble; } if ((other.mChangeMask & CHANGE_DISABLE_PIP) != 0) { mDisablePip = other.mDisablePip; } mChangeMask |= other.mChangeMask; if (other.mActivityWindowingMode >= WINDOWING_MODE_UNDEFINED) { mActivityWindowingMode = other.mActivityWindowingMode; Loading Loading @@ -1546,6 +1574,11 @@ public final class WindowContainerTransaction implements Parcelable { return mForceExcludedFromRecents; } /** Gets whether the task is disabled to enter picture-in-picture. */ public boolean getDisablePip() { return mDisablePip; } /** Gets whether the config should be sent to the client at the end of the transition. */ public boolean getConfigAtTransitionEnd() { return mConfigAtTransitionEnd; Loading Loading @@ -1619,6 +1652,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((mChangeMask & CHANGE_FORCE_EXCLUDED_FROM_RECENTS) != 0) { sb.append("forceExcludedFromRecents:" + mForceExcludedFromRecents + ","); } if ((mChangeMask & CHANGE_DISABLE_PIP) != 0) { sb.append("disablePip:" + mDisablePip + ","); } if (mBoundsChangeTransaction != null) { sb.append("hasBoundsTransaction,"); } Loading Loading @@ -1647,6 +1683,8 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeBoolean(mForceTranslucent); dest.writeBoolean(mDragResizing); dest.writeBoolean(mForceExcludedFromRecents); dest.writeBoolean(mLaunchNextToBubble); dest.writeBoolean(mDisablePip); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); Loading @@ -1661,7 +1699,6 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeInt(mWindowingMode); dest.writeInt(mActivityWindowingMode); dest.writeBoolean(mLaunchNextToBubble); } @Override Loading
core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -221,3 +221,14 @@ flag { purpose: PURPOSE_BUGFIX } } flag { namespace: "windowing_sdk" name: "disallow_bubble_to_enter_pip" description: "Prevent Bubble task to enter picture-in-picture" bug: "389158353" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/wm/ActivityRecord.java +9 −1 Original line number Diff line number Diff line Loading @@ -3190,6 +3190,14 @@ final class ActivityRecord extends WindowToken { && info.supportsPictureInPicture(); } /** * Whether this activity can enter PiP now. This can be {@code false} if the system has disabled * this Task from entering PiP. */ boolean canEnterPictureInPicture() { return supportsPictureInPicture() && (task == null || !task.isDisablePip()); } boolean supportsFreeform() { return supportsFreeformInDisplayArea(getDisplayArea()); } Loading Loading @@ -3252,7 +3260,7 @@ final class ActivityRecord extends WindowToken { * @return whether this activity is currently allowed to enter PIP. */ boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) { if (!supportsPictureInPicture()) { if (!canEnterPictureInPicture()) { return false; } Loading
services/core/java/com/android/server/wm/Task.java +38 −0 Original line number Diff line number Diff line Loading @@ -634,6 +634,9 @@ class Task extends TaskFragment { /** @see #isForceExcludedFromRecents() */ private boolean mForceExcludedFromRecents; /** @see #isDisablePip() */ private boolean mDisablePip; private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, Loading Loading @@ -4606,6 +4609,35 @@ class Task extends TaskFragment { mForceExcludedFromRecents = excluded; } /** * Whether this Task and its children are disallowed from entering picture-in-picture. * * This is different from {@link #mSupportsPictureInPicture} which is determined based on the * activity manifest. This flag is set by WM Shell to disable PiP for the current Task status. */ boolean isDisablePip() { if (!Flags.disallowBubbleToEnterPip()) { return false; } if (mDisablePip) { return true; } // Check if PIP is disabled on any parent Task. final WindowContainer parent = getParent(); if (parent != null && parent.asTask() != null) { return parent.asTask().isDisablePip(); } return false; } void setDisablePip(boolean disablePip) { if (!Flags.disallowBubbleToEnterPip()) { Slog.w(TAG, "Flag " + Flags.FLAG_DISALLOW_BUBBLE_TO_ENTER_PIP + " is not enabled"); return; } mDisablePip = disablePip; } boolean isForceHiddenForPinnedTask() { return (mForceHiddenFlags & FLAG_FORCE_HIDDEN_FOR_PINNED_TASK) != 0; } Loading Loading @@ -5392,6 +5424,9 @@ class Task extends TaskFragment { } final ActivityRecord[] candidate = new ActivityRecord[1]; topTask.forAllLeafTaskFragments(tf -> { if (tf.getTask().isDisablePip()) { return false; } // Find the top activity that may enter Pip while pausing. final ActivityRecord topActivity = tf.getTopNonFinishingActivity(); if (topActivity != null && topActivity.isState(RESUMED, PAUSING) Loading Loading @@ -5970,6 +6005,9 @@ class Task extends TaskFragment { if (mLaunchNextToBubble) { pw.println(prefix + " mLaunchNextToBubble=true"); } if (mDisablePip) { pw.println(prefix + " mDisablePip=true"); } if (mLastNonFullscreenBounds != null) { pw.print(prefix); pw.print(" mLastNonFullscreenBounds="); pw.println(mLastNonFullscreenBounds); Loading
services/core/java/com/android/server/wm/TaskDisplayArea.java +2 −1 Original line number Diff line number Diff line Loading @@ -1383,9 +1383,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // it can be moved to a new created PIP Task, so WINDOWING_MODE_PINNED is // always valid for Task as long as the device supports it. || (windowingMode == WINDOWING_MODE_PINNED && supportsPip); supportsPip &= !task.isDisablePip(); } else if (r != null) { supportsFreeform = r.supportsFreeformInDisplayArea(this); supportsPip = r.supportsPictureInPicture(); supportsPip = r.canEnterPictureInPicture(); supportsMultiWindow = r.supportsMultiWindowInDisplayArea(this); } } Loading