Loading core/java/android/window/WindowContainerTransaction.java +51 −1 Original line number Diff line number Diff line Loading @@ -516,11 +516,13 @@ public final class WindowContainerTransaction implements Parcelable { */ @NonNull public WindowContainerTransaction setAdjacentTaskFragments( @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) { @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2, @Nullable TaskFragmentAdjacentOptions options) { final HierarchyOp hierarchyOp = new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) .setContainer(fragmentToken1) .setReparentContainer(fragmentToken2) .setLaunchOptions(options != null ? options.toBundle() : null) .build(); mHierarchyOps.add(hierarchyOp); return this; Loading Loading @@ -1298,4 +1300,52 @@ public final class WindowContainerTransaction implements Parcelable { } } } /** * Helper class for building an options Bundle that can be used to set adjacent rules of * TaskFragments. * @hide */ public static class TaskFragmentAdjacentOptions { private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL = "android:transaction.adjacent.option.delay_primary_removal"; private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL = "android:transaction.adjacent.option.delay_secondary_removal"; private boolean mDelayPrimaryLastActivityRemoval; private boolean mDelaySecondaryLastActivityRemoval; public TaskFragmentAdjacentOptions() { } public TaskFragmentAdjacentOptions(@NonNull Bundle bundle) { mDelayPrimaryLastActivityRemoval = bundle.getBoolean( DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL); mDelaySecondaryLastActivityRemoval = bundle.getBoolean( DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL); } public void setDelayPrimaryLastActivityRemoval(boolean delay) { mDelayPrimaryLastActivityRemoval = delay; } public void setDelaySecondaryLastActivityRemoval(boolean delay) { mDelaySecondaryLastActivityRemoval = delay; } public boolean isDelayPrimaryLastActivityRemoval() { return mDelayPrimaryLastActivityRemoval; } public boolean isDelaySecondaryLastActivityRemoval() { return mDelaySecondaryLastActivityRemoval; } Bundle toBundle() { final Bundle b = new Bundle(); b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval); b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval); return b; } } } libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java +19 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.extensions.embedding.SplitRule; import java.util.Map; import java.util.concurrent.Executor; Loading Loading @@ -100,7 +101,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds, @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken, @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { @Nullable Bundle activityOptions, @NonNull SplitRule rule) { final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. Loading @@ -117,7 +118,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { activityOptions); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken); setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule); } /** Loading @@ -127,7 +128,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { */ void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); wct.setAdjacentTaskFragments(fragmentToken, null); setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */); } /** Loading Loading @@ -187,6 +188,21 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) { WindowContainerTransaction.TaskFragmentAdjacentOptions adjacentOptions = null; final boolean finishSecondaryWithPrimary = splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); final boolean finishPrimaryWithSecondary = splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { adjacentOptions = new WindowContainerTransaction.TaskFragmentAdjacentOptions(); adjacentOptions.setDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentOptions.setDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); } wct.setAdjacentTaskFragments(primary, secondary, adjacentOptions); } TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken, Rect bounds, @WindowingMode int windowingMode) { if (mFragmentInfos.containsKey(fragmentToken)) { Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java +16 −8 Original line number Diff line number Diff line Loading @@ -39,16 +39,10 @@ class SplitContainer { mSecondaryContainer = secondaryContainer; mSplitRule = splitRule; final boolean isPlaceholderContainer = isPlaceholderContainer(); final boolean shouldFinishPrimaryWithSecondary = (mSplitRule instanceof SplitPairRule) && ((SplitPairRule) mSplitRule).shouldFinishPrimaryWithSecondary(); final boolean shouldFinishSecondaryWithPrimary = (mSplitRule instanceof SplitPairRule) && ((SplitPairRule) mSplitRule).shouldFinishSecondaryWithPrimary(); if (shouldFinishPrimaryWithSecondary || isPlaceholderContainer) { if (shouldFinishPrimaryWithSecondary(splitRule)) { mSecondaryContainer.addActivityToFinishOnExit(primaryActivity); } if (shouldFinishSecondaryWithPrimary || isPlaceholderContainer) { if (shouldFinishSecondaryWithPrimary(splitRule)) { mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer); } } Loading @@ -71,4 +65,18 @@ class SplitContainer { boolean isPlaceholderContainer() { return (mSplitRule instanceof SplitPlaceholderRule); } static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) { final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule; final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule) && ((SplitPairRule) splitRule).shouldFinishPrimaryWithSecondary(); return shouldFinishPrimaryWithSecondary || isPlaceholderContainer; } static boolean shouldFinishSecondaryWithPrimary(@NonNull SplitRule splitRule) { final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule; final boolean shouldFinishSecondaryWithPrimary = (splitRule instanceof SplitPairRule) && ((SplitPairRule) splitRule).shouldFinishSecondaryWithPrimary(); return shouldFinishSecondaryWithPrimary || isPlaceholderContainer; } } libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java +5 −5 Original line number Diff line number Diff line Loading @@ -109,8 +109,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryContainer.setLastRequestedBounds(secondaryRectBounds); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments( primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken()); setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), rule); mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule); Loading Loading @@ -144,8 +144,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryActivity, secondaryRectBounds, primaryContainer); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments( primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken()); setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), rule); mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule); Loading Loading @@ -212,7 +212,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { rule); startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds, launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds, activityIntent, activityOptions); activityIntent, activityOptions, rule); applyTransaction(wct); primaryContainer.setLastRequestedBounds(primaryRectBounds); Loading services/core/java/com/android/server/wm/ActivityRecord.java +15 −1 Original line number Diff line number Diff line Loading @@ -3234,6 +3234,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere final ActivityRecord next = getDisplayArea().topRunningActivity( true /* considerKeyguardState */); // If the finishing activity is the last activity of a organized TaskFragment and has an // adjacent TaskFragment, check if the activity removal should be delayed. boolean delayRemoval = false; final TaskFragment taskFragment = getTaskFragment(); if (next != null && taskFragment != null && taskFragment.isEmbedded()) { final TaskFragment organized = taskFragment.getOrganizedTaskFragment(); final TaskFragment adjacent = organized != null ? organized.getAdjacentTaskFragment() : null; if (adjacent != null && organized.topRunningActivity() == null) { delayRemoval = organized.isDelayLastActivityRemoval(); } } // isNextNotYetVisible is to check if the next activity is invisible, or it has been // requested to be invisible but its windows haven't reported as invisible. If so, it // implied that the current finishing activity should be added into stopping list rather Loading @@ -3248,7 +3262,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (isCurrentVisible) { if (isNextNotYetVisible) { if (isNextNotYetVisible || delayRemoval) { // Add this activity to the list of stopping activities. It will be processed and // destroyed when the next activity reports idle. addToStopping(false /* scheduleIdle */, false /* idleDelayed */, Loading Loading
core/java/android/window/WindowContainerTransaction.java +51 −1 Original line number Diff line number Diff line Loading @@ -516,11 +516,13 @@ public final class WindowContainerTransaction implements Parcelable { */ @NonNull public WindowContainerTransaction setAdjacentTaskFragments( @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) { @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2, @Nullable TaskFragmentAdjacentOptions options) { final HierarchyOp hierarchyOp = new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) .setContainer(fragmentToken1) .setReparentContainer(fragmentToken2) .setLaunchOptions(options != null ? options.toBundle() : null) .build(); mHierarchyOps.add(hierarchyOp); return this; Loading Loading @@ -1298,4 +1300,52 @@ public final class WindowContainerTransaction implements Parcelable { } } } /** * Helper class for building an options Bundle that can be used to set adjacent rules of * TaskFragments. * @hide */ public static class TaskFragmentAdjacentOptions { private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL = "android:transaction.adjacent.option.delay_primary_removal"; private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL = "android:transaction.adjacent.option.delay_secondary_removal"; private boolean mDelayPrimaryLastActivityRemoval; private boolean mDelaySecondaryLastActivityRemoval; public TaskFragmentAdjacentOptions() { } public TaskFragmentAdjacentOptions(@NonNull Bundle bundle) { mDelayPrimaryLastActivityRemoval = bundle.getBoolean( DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL); mDelaySecondaryLastActivityRemoval = bundle.getBoolean( DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL); } public void setDelayPrimaryLastActivityRemoval(boolean delay) { mDelayPrimaryLastActivityRemoval = delay; } public void setDelaySecondaryLastActivityRemoval(boolean delay) { mDelaySecondaryLastActivityRemoval = delay; } public boolean isDelayPrimaryLastActivityRemoval() { return mDelayPrimaryLastActivityRemoval; } public boolean isDelaySecondaryLastActivityRemoval() { return mDelaySecondaryLastActivityRemoval; } Bundle toBundle() { final Bundle b = new Bundle(); b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval); b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval); return b; } } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java +19 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.extensions.embedding.SplitRule; import java.util.Map; import java.util.concurrent.Executor; Loading Loading @@ -100,7 +101,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { @NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds, @NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken, @NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { @Nullable Bundle activityOptions, @NonNull SplitRule rule) { final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. Loading @@ -117,7 +118,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { activityOptions); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken); setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule); } /** Loading @@ -127,7 +128,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { */ void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); wct.setAdjacentTaskFragments(fragmentToken, null); setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */); } /** Loading Loading @@ -187,6 +188,21 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) { WindowContainerTransaction.TaskFragmentAdjacentOptions adjacentOptions = null; final boolean finishSecondaryWithPrimary = splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); final boolean finishPrimaryWithSecondary = splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { adjacentOptions = new WindowContainerTransaction.TaskFragmentAdjacentOptions(); adjacentOptions.setDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentOptions.setDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); } wct.setAdjacentTaskFragments(primary, secondary, adjacentOptions); } TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken, Rect bounds, @WindowingMode int windowingMode) { if (mFragmentInfos.containsKey(fragmentToken)) { Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java +16 −8 Original line number Diff line number Diff line Loading @@ -39,16 +39,10 @@ class SplitContainer { mSecondaryContainer = secondaryContainer; mSplitRule = splitRule; final boolean isPlaceholderContainer = isPlaceholderContainer(); final boolean shouldFinishPrimaryWithSecondary = (mSplitRule instanceof SplitPairRule) && ((SplitPairRule) mSplitRule).shouldFinishPrimaryWithSecondary(); final boolean shouldFinishSecondaryWithPrimary = (mSplitRule instanceof SplitPairRule) && ((SplitPairRule) mSplitRule).shouldFinishSecondaryWithPrimary(); if (shouldFinishPrimaryWithSecondary || isPlaceholderContainer) { if (shouldFinishPrimaryWithSecondary(splitRule)) { mSecondaryContainer.addActivityToFinishOnExit(primaryActivity); } if (shouldFinishSecondaryWithPrimary || isPlaceholderContainer) { if (shouldFinishSecondaryWithPrimary(splitRule)) { mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer); } } Loading @@ -71,4 +65,18 @@ class SplitContainer { boolean isPlaceholderContainer() { return (mSplitRule instanceof SplitPlaceholderRule); } static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) { final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule; final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule) && ((SplitPairRule) splitRule).shouldFinishPrimaryWithSecondary(); return shouldFinishPrimaryWithSecondary || isPlaceholderContainer; } static boolean shouldFinishSecondaryWithPrimary(@NonNull SplitRule splitRule) { final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule; final boolean shouldFinishSecondaryWithPrimary = (splitRule instanceof SplitPairRule) && ((SplitPairRule) splitRule).shouldFinishSecondaryWithPrimary(); return shouldFinishSecondaryWithPrimary || isPlaceholderContainer; } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java +5 −5 Original line number Diff line number Diff line Loading @@ -109,8 +109,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryContainer.setLastRequestedBounds(secondaryRectBounds); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments( primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken()); setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), rule); mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule); Loading Loading @@ -144,8 +144,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { secondaryActivity, secondaryRectBounds, primaryContainer); // Set adjacent to each other so that the containers below will be invisible. wct.setAdjacentTaskFragments( primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken()); setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), rule); mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule); Loading Loading @@ -212,7 +212,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { rule); startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds, launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds, activityIntent, activityOptions); activityIntent, activityOptions, rule); applyTransaction(wct); primaryContainer.setLastRequestedBounds(primaryRectBounds); Loading
services/core/java/com/android/server/wm/ActivityRecord.java +15 −1 Original line number Diff line number Diff line Loading @@ -3234,6 +3234,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere final ActivityRecord next = getDisplayArea().topRunningActivity( true /* considerKeyguardState */); // If the finishing activity is the last activity of a organized TaskFragment and has an // adjacent TaskFragment, check if the activity removal should be delayed. boolean delayRemoval = false; final TaskFragment taskFragment = getTaskFragment(); if (next != null && taskFragment != null && taskFragment.isEmbedded()) { final TaskFragment organized = taskFragment.getOrganizedTaskFragment(); final TaskFragment adjacent = organized != null ? organized.getAdjacentTaskFragment() : null; if (adjacent != null && organized.topRunningActivity() == null) { delayRemoval = organized.isDelayLastActivityRemoval(); } } // isNextNotYetVisible is to check if the next activity is invisible, or it has been // requested to be invisible but its windows haven't reported as invisible. If so, it // implied that the current finishing activity should be added into stopping list rather Loading @@ -3248,7 +3262,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } if (isCurrentVisible) { if (isNextNotYetVisible) { if (isNextNotYetVisible || delayRemoval) { // Add this activity to the list of stopping activities. It will be processed and // destroyed when the next activity reports idle. addToStopping(false /* scheduleIdle */, false /* idleDelayed */, Loading