Loading core/java/android/window/TaskFragmentCreationParams.java +34 −2 Original line number Original line Diff line number Diff line Loading @@ -94,11 +94,18 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable @Nullable private final IBinder mPairedActivityToken; private final IBinder mPairedActivityToken; /** * If {@code true}, transitions are allowed even if the TaskFragment is empty. If * {@code false}, transitions will wait until the TaskFragment becomes non-empty or other * conditions are met. Default to {@code false}. */ private final boolean mAllowTransitionWhenEmpty; private TaskFragmentCreationParams( private TaskFragmentCreationParams( @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @Nullable IBinder pairedActivityToken) { @Nullable IBinder pairedActivityToken, boolean allowTransitionWhenEmpty) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { throw new IllegalArgumentException("pairedPrimaryFragmentToken and" throw new IllegalArgumentException("pairedPrimaryFragmentToken and" + " pairedActivityToken should not be set at the same time."); + " pairedActivityToken should not be set at the same time."); Loading @@ -110,6 +117,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mWindowingMode = windowingMode; mWindowingMode = windowingMode; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedActivityToken = pairedActivityToken; mPairedActivityToken = pairedActivityToken; mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; } } @NonNull @NonNull Loading Loading @@ -155,6 +163,11 @@ public final class TaskFragmentCreationParams implements Parcelable { return mPairedActivityToken; return mPairedActivityToken; } } /** @hide */ public boolean getAllowTransitionWhenEmpty() { return mAllowTransitionWhenEmpty; } private TaskFragmentCreationParams(Parcel in) { private TaskFragmentCreationParams(Parcel in) { mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mFragmentToken = in.readStrongBinder(); mFragmentToken = in.readStrongBinder(); Loading @@ -163,6 +176,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mWindowingMode = in.readInt(); mWindowingMode = in.readInt(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); mAllowTransitionWhenEmpty = in.readBoolean(); } } /** @hide */ /** @hide */ Loading @@ -175,6 +189,7 @@ public final class TaskFragmentCreationParams implements Parcelable { dest.writeInt(mWindowingMode); dest.writeInt(mWindowingMode); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedActivityToken); dest.writeStrongBinder(mPairedActivityToken); dest.writeBoolean(mAllowTransitionWhenEmpty); } } @NonNull @NonNull Loading @@ -201,6 +216,7 @@ public final class TaskFragmentCreationParams implements Parcelable { + " windowingMode=" + mWindowingMode + " windowingMode=" + mWindowingMode + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedActivityToken=" + mPairedActivityToken + " pairedActivityToken=" + mPairedActivityToken + " allowTransitionWhenEmpty=" + mAllowTransitionWhenEmpty + "}"; + "}"; } } Loading Loading @@ -234,6 +250,8 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable @Nullable private IBinder mPairedActivityToken; private IBinder mPairedActivityToken; private boolean mAllowTransitionWhenEmpty; public Builder(@NonNull TaskFragmentOrganizerToken organizer, public Builder(@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { mOrganizer = organizer; mOrganizer = organizer; Loading Loading @@ -298,12 +316,26 @@ public final class TaskFragmentCreationParams implements Parcelable { return this; return this; } } /** * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions * will wait until the TaskFragment becomes non-empty or other conditions are met. Default * to {@code false}. * * @hide */ @NonNull public Builder setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; return this; } /** Constructs the options to create TaskFragment with. */ /** Constructs the options to create TaskFragment with. */ @NonNull @NonNull public TaskFragmentCreationParams build() { public TaskFragmentCreationParams build() { return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken, mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken, mPairedActivityToken); mPairedActivityToken, mAllowTransitionWhenEmpty); } } } } } } services/core/java/com/android/server/wm/TaskFragment.java +25 −2 Original line number Original line Diff line number Diff line Loading @@ -369,6 +369,15 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ */ private boolean mMoveToBottomIfClearWhenLaunch; private boolean mMoveToBottomIfClearWhenLaunch; /** * If {@code true}, transitions are allowed even if this TaskFragment is empty. If * {@code false}, transitions will wait until this TaskFragment becomes non-empty or other * conditions are met. Default to {@code false}. * * @see #isReadyToTransit */ private boolean mAllowTransitionWhenEmpty; /** When set, will force the task to report as invisible. */ /** When set, will force the task to report as invisible. */ static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; Loading Loading @@ -509,6 +518,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { mIsolatedNav = isolatedNav; mIsolatedNav = isolatedNav; } } /** * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions * will wait until the TaskFragment becomes non-empty or other conditions are met. Default * to {@code false}. */ void setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { if (!isEmbedded()) { return; } mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; } /** @see #mIsolatedNav */ /** @see #mIsolatedNav */ boolean isIsolatedNav() { boolean isIsolatedNav() { return isEmbedded() && mIsolatedNav; return isEmbedded() && mIsolatedNav; Loading Loading @@ -2827,8 +2849,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { return true; return true; } } // We don't want to start the transition if the organized TaskFragment is empty, unless // We don't want to start the transition if the organized TaskFragment is empty, unless // it is requested to be removed. // it is requested to be removed or the mAllowTransitionWhenEmpty flag is true. if (getTopNonFinishingActivity() != null || mIsRemovalRequested) { if (getTopNonFinishingActivity() != null || mIsRemovalRequested || mAllowTransitionWhenEmpty) { return true; return true; } } // Organizer shouldn't change embedded TaskFragment in PiP. // Organizer shouldn't change embedded TaskFragment in PiP. Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -2202,6 +2202,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } final TaskFragment taskFragment = new TaskFragment(mService, final TaskFragment taskFragment = new TaskFragment(mService, creationParams.getFragmentToken(), true /* createdByOrganizer */); creationParams.getFragmentToken(), true /* createdByOrganizer */); taskFragment.setAllowTransitionWhenEmpty(creationParams.getAllowTransitionWhenEmpty()); // Set task fragment organizer immediately, since it might have to be notified about further // Set task fragment organizer immediately, since it might have to be notified about further // actions. // actions. TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer(); TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer(); Loading services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -444,6 +444,10 @@ public class TaskFragmentTest extends WindowTestsBase { // Not ready if the task is still visible when the TaskFragment becomes empty. // Not ready if the task is still visible when the TaskFragment becomes empty. doReturn(true).when(task).isVisibleRequested(); doReturn(true).when(task).isVisibleRequested(); assertFalse(taskFragment.isReadyToTransit()); assertFalse(taskFragment.isReadyToTransit()); // Ready if the mAllowTransitionWhenEmpty flag is true. taskFragment.setAllowTransitionWhenEmpty(true); assertTrue(taskFragment.isReadyToTransit()); } } @Test @Test Loading Loading
core/java/android/window/TaskFragmentCreationParams.java +34 −2 Original line number Original line Diff line number Diff line Loading @@ -94,11 +94,18 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable @Nullable private final IBinder mPairedActivityToken; private final IBinder mPairedActivityToken; /** * If {@code true}, transitions are allowed even if the TaskFragment is empty. If * {@code false}, transitions will wait until the TaskFragment becomes non-empty or other * conditions are met. Default to {@code false}. */ private final boolean mAllowTransitionWhenEmpty; private TaskFragmentCreationParams( private TaskFragmentCreationParams( @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, @NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken, @Nullable IBinder pairedActivityToken) { @Nullable IBinder pairedActivityToken, boolean allowTransitionWhenEmpty) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) { throw new IllegalArgumentException("pairedPrimaryFragmentToken and" throw new IllegalArgumentException("pairedPrimaryFragmentToken and" + " pairedActivityToken should not be set at the same time."); + " pairedActivityToken should not be set at the same time."); Loading @@ -110,6 +117,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mWindowingMode = windowingMode; mWindowingMode = windowingMode; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken; mPairedActivityToken = pairedActivityToken; mPairedActivityToken = pairedActivityToken; mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; } } @NonNull @NonNull Loading Loading @@ -155,6 +163,11 @@ public final class TaskFragmentCreationParams implements Parcelable { return mPairedActivityToken; return mPairedActivityToken; } } /** @hide */ public boolean getAllowTransitionWhenEmpty() { return mAllowTransitionWhenEmpty; } private TaskFragmentCreationParams(Parcel in) { private TaskFragmentCreationParams(Parcel in) { mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); mFragmentToken = in.readStrongBinder(); mFragmentToken = in.readStrongBinder(); Loading @@ -163,6 +176,7 @@ public final class TaskFragmentCreationParams implements Parcelable { mWindowingMode = in.readInt(); mWindowingMode = in.readInt(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedPrimaryFragmentToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); mPairedActivityToken = in.readStrongBinder(); mAllowTransitionWhenEmpty = in.readBoolean(); } } /** @hide */ /** @hide */ Loading @@ -175,6 +189,7 @@ public final class TaskFragmentCreationParams implements Parcelable { dest.writeInt(mWindowingMode); dest.writeInt(mWindowingMode); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedPrimaryFragmentToken); dest.writeStrongBinder(mPairedActivityToken); dest.writeStrongBinder(mPairedActivityToken); dest.writeBoolean(mAllowTransitionWhenEmpty); } } @NonNull @NonNull Loading @@ -201,6 +216,7 @@ public final class TaskFragmentCreationParams implements Parcelable { + " windowingMode=" + mWindowingMode + " windowingMode=" + mWindowingMode + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedFragmentToken=" + mPairedPrimaryFragmentToken + " pairedActivityToken=" + mPairedActivityToken + " pairedActivityToken=" + mPairedActivityToken + " allowTransitionWhenEmpty=" + mAllowTransitionWhenEmpty + "}"; + "}"; } } Loading Loading @@ -234,6 +250,8 @@ public final class TaskFragmentCreationParams implements Parcelable { @Nullable @Nullable private IBinder mPairedActivityToken; private IBinder mPairedActivityToken; private boolean mAllowTransitionWhenEmpty; public Builder(@NonNull TaskFragmentOrganizerToken organizer, public Builder(@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { mOrganizer = organizer; mOrganizer = organizer; Loading Loading @@ -298,12 +316,26 @@ public final class TaskFragmentCreationParams implements Parcelable { return this; return this; } } /** * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions * will wait until the TaskFragment becomes non-empty or other conditions are met. Default * to {@code false}. * * @hide */ @NonNull public Builder setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; return this; } /** Constructs the options to create TaskFragment with. */ /** Constructs the options to create TaskFragment with. */ @NonNull @NonNull public TaskFragmentCreationParams build() { public TaskFragmentCreationParams build() { return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken, mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken, mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken, mPairedActivityToken); mPairedActivityToken, mAllowTransitionWhenEmpty); } } } } } }
services/core/java/com/android/server/wm/TaskFragment.java +25 −2 Original line number Original line Diff line number Diff line Loading @@ -369,6 +369,15 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ */ private boolean mMoveToBottomIfClearWhenLaunch; private boolean mMoveToBottomIfClearWhenLaunch; /** * If {@code true}, transitions are allowed even if this TaskFragment is empty. If * {@code false}, transitions will wait until this TaskFragment becomes non-empty or other * conditions are met. Default to {@code false}. * * @see #isReadyToTransit */ private boolean mAllowTransitionWhenEmpty; /** When set, will force the task to report as invisible. */ /** When set, will force the task to report as invisible. */ static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; Loading Loading @@ -509,6 +518,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { mIsolatedNav = isolatedNav; mIsolatedNav = isolatedNav; } } /** * Sets whether transitions are allowed when the TaskFragment is empty. If {@code true}, * transitions are allowed when the TaskFragment is empty. If {@code false}, transitions * will wait until the TaskFragment becomes non-empty or other conditions are met. Default * to {@code false}. */ void setAllowTransitionWhenEmpty(boolean allowTransitionWhenEmpty) { if (!isEmbedded()) { return; } mAllowTransitionWhenEmpty = allowTransitionWhenEmpty; } /** @see #mIsolatedNav */ /** @see #mIsolatedNav */ boolean isIsolatedNav() { boolean isIsolatedNav() { return isEmbedded() && mIsolatedNav; return isEmbedded() && mIsolatedNav; Loading Loading @@ -2827,8 +2849,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { return true; return true; } } // We don't want to start the transition if the organized TaskFragment is empty, unless // We don't want to start the transition if the organized TaskFragment is empty, unless // it is requested to be removed. // it is requested to be removed or the mAllowTransitionWhenEmpty flag is true. if (getTopNonFinishingActivity() != null || mIsRemovalRequested) { if (getTopNonFinishingActivity() != null || mIsRemovalRequested || mAllowTransitionWhenEmpty) { return true; return true; } } // Organizer shouldn't change embedded TaskFragment in PiP. // Organizer shouldn't change embedded TaskFragment in PiP. Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -2202,6 +2202,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } final TaskFragment taskFragment = new TaskFragment(mService, final TaskFragment taskFragment = new TaskFragment(mService, creationParams.getFragmentToken(), true /* createdByOrganizer */); creationParams.getFragmentToken(), true /* createdByOrganizer */); taskFragment.setAllowTransitionWhenEmpty(creationParams.getAllowTransitionWhenEmpty()); // Set task fragment organizer immediately, since it might have to be notified about further // Set task fragment organizer immediately, since it might have to be notified about further // actions. // actions. TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer(); TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer(); Loading
services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -444,6 +444,10 @@ public class TaskFragmentTest extends WindowTestsBase { // Not ready if the task is still visible when the TaskFragment becomes empty. // Not ready if the task is still visible when the TaskFragment becomes empty. doReturn(true).when(task).isVisibleRequested(); doReturn(true).when(task).isVisibleRequested(); assertFalse(taskFragment.isReadyToTransit()); assertFalse(taskFragment.isReadyToTransit()); // Ready if the mAllowTransitionWhenEmpty flag is true. taskFragment.setAllowTransitionWhenEmpty(true); assertTrue(taskFragment.isReadyToTransit()); } } @Test @Test Loading