Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +26 −20 Original line number Diff line number Diff line Loading @@ -422,6 +422,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen launchPlaceholderIfNecessary(activity); } @VisibleForTesting void onActivityDestroyed(@NonNull Activity activity) { // Remove any pending appeared activity, as the server won't send finished activity to the // organizer. for (int i = mTaskContainers.size() - 1; i >= 0; i--) { mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity); } // We didn't trigger the callback if there were any pending appeared activities, so check // again after the pending is removed. updateCallbackIfNecessary(); } /** * Called when we have been waiting too long for the TaskFragment to become non-empty after * creation. Loading Loading @@ -465,12 +477,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (activityInTask == null) { throw new IllegalArgumentException("activityInTask must not be null,"); } final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this); if (!mTaskContainers.contains(taskId)) { mTaskContainers.put(taskId, new TaskContainer(taskId)); } final TaskContainer taskContainer = mTaskContainers.get(taskId); taskContainer.mContainers.add(container); final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer, this); if (!taskContainer.isTaskBoundsInitialized()) { // Get the initial bounds before the TaskFragment has appeared. final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask); Loading Loading @@ -500,14 +512,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) { removeExistingSecondaryContainers(wct, primaryContainer); } mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer); primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer); } /** Cleanups all the dependencies when the TaskFragment is entering PIP. */ private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentContainer container) { final int taskId = container.getTaskId(); final TaskContainer taskContainer = mTaskContainers.get(taskId); final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } Loading Loading @@ -545,8 +556,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ void removeContainer(@NonNull TaskFragmentContainer container) { // Remove all split containers that included this one final int taskId = container.getTaskId(); final TaskContainer taskContainer = mTaskContainers.get(taskId); final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } Loading Loading @@ -637,8 +647,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitContainer == null) { return; } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainer != splitContainers.get(splitContainers.size() - 1)) { // Skip position update - it isn't the topmost split. return; Loading @@ -660,8 +669,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Nullable private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) { final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainers.isEmpty()) { return null; } Loading @@ -683,11 +691,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private SplitContainer getActiveSplitForContainers( @NonNull TaskFragmentContainer firstContainer, @NonNull TaskFragmentContainer secondContainer) { final List<SplitContainer> splitContainers = mTaskContainers.get(firstContainer.getTaskId()) final List<SplitContainer> splitContainers = firstContainer.getTaskContainer() .mSplitContainers; if (splitContainers == null) { return null; } for (int i = splitContainers.size() - 1; i >= 0; i--) { final SplitContainer splitContainer = splitContainers.get(i); final TaskFragmentContainer primary = splitContainer.getPrimaryContainer(); Loading Loading @@ -856,11 +861,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (container == null) { return false; } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null) { return true; } final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; for (SplitContainer splitContainer : splitContainers) { if (container.equals(splitContainer.getPrimaryContainer()) || container.equals(splitContainer.getSecondaryContainer())) { Loading Loading @@ -1046,6 +1047,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen public void onActivityConfigurationChanged(Activity activity) { SplitController.this.onActivityConfigurationChanged(activity); } @Override public void onActivityPostDestroyed(Activity activity) { SplitController.this.onActivityDestroyed(activity); } } /** Executor that posts on the main application thread. */ Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +2 −8 Original line number Diff line number Diff line Loading @@ -291,8 +291,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // When placeholder is shown in split, we should keep the focus on the primary. wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); } final TaskContainer taskContainer = mController.getTaskContainer( updatedContainer.getTaskId()); final TaskContainer taskContainer = updatedContainer.getTaskContainer(); final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment( primaryRectBounds); updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode); Loading Loading @@ -456,12 +455,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) { final int taskId = container.getTaskId(); final TaskContainer taskContainer = mController.getTaskContainer(taskId); if (taskContainer == null) { throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId); } return taskContainer.getTaskBounds(); return container.getTaskContainer().getTaskBounds(); } @NonNull Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +12 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package androidx.window.extensions.embedding; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.graphics.Rect; Loading Loading @@ -62,6 +64,9 @@ class TaskContainer { final Set<IBinder> mFinishedContainer = new ArraySet<>(); TaskContainer(int taskId) { if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); } mTaskId = taskId; } Loading Loading @@ -130,4 +135,11 @@ class TaskContainer { boolean isEmpty() { return mContainers.isEmpty() && mFinishedContainer.isEmpty(); } /** Removes the pending appeared activity from all TaskFragments in this Task. */ void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { for (TaskFragmentContainer container : mContainers) { container.removePendingAppearedActivity(pendingAppearedActivity); } } } libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +23 −9 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package androidx.window.extensions.embedding; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; Loading Loading @@ -52,8 +51,9 @@ class TaskFragmentContainer { @NonNull private final IBinder mToken; /** Parent leaf Task id. */ private final int mTaskId; /** Parent leaf Task. */ @NonNull private final TaskContainer mTaskContainer; /** * Server-provided task fragment information. Loading Loading @@ -100,14 +100,12 @@ class TaskFragmentContainer { * Creates a container with an existing activity that will be re-parented to it in a window * container transaction. */ TaskFragmentContainer(@Nullable Activity activity, int taskId, TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer, @NonNull SplitController controller) { mController = controller; mToken = new Binder("TaskFragmentContainer"); if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); } mTaskId = taskId; mTaskContainer = taskContainer; taskContainer.mContainers.add(this); if (activity != null) { addPendingAppearedActivity(activity); } Loading Loading @@ -162,9 +160,18 @@ class TaskFragmentContainer { } void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { if (hasActivity(pendingAppearedActivity.getActivityToken())) { return; } // Remove the pending activity from other TaskFragments. mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity); mPendingAppearedActivities.add(pendingAppearedActivity); } void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { mPendingAppearedActivities.remove(pendingAppearedActivity); } boolean hasActivity(@NonNull IBinder token) { if (mInfo != null && mInfo.getActivities().contains(token)) { return true; Loading Loading @@ -376,7 +383,13 @@ class TaskFragmentContainer { /** Gets the parent leaf Task id. */ int getTaskId() { return mTaskId; return mTaskContainer.getTaskId(); } /** Gets the parent Task. */ @NonNull TaskContainer getTaskContainer() { return mTaskContainer; } @Override Loading @@ -392,6 +405,7 @@ class TaskFragmentContainer { */ private String toString(boolean includeContainersToFinishOnExit) { return "TaskFragmentContainer{" + " parentTaskId=" + getTaskId() + " token=" + mToken + " topNonFinishingActivity=" + getTopNonFinishingActivity() + " runningActivityCount=" + getRunningActivityCount() Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -113,8 +113,9 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { final TaskContainer taskContainer = new TaskContainer(TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); taskContainer, mSplitController); final TaskFragmentInfo info = createMockInfo(container); mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info); container.setInfo(info); Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +26 −20 Original line number Diff line number Diff line Loading @@ -422,6 +422,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen launchPlaceholderIfNecessary(activity); } @VisibleForTesting void onActivityDestroyed(@NonNull Activity activity) { // Remove any pending appeared activity, as the server won't send finished activity to the // organizer. for (int i = mTaskContainers.size() - 1; i >= 0; i--) { mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity); } // We didn't trigger the callback if there were any pending appeared activities, so check // again after the pending is removed. updateCallbackIfNecessary(); } /** * Called when we have been waiting too long for the TaskFragment to become non-empty after * creation. Loading Loading @@ -465,12 +477,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (activityInTask == null) { throw new IllegalArgumentException("activityInTask must not be null,"); } final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this); if (!mTaskContainers.contains(taskId)) { mTaskContainers.put(taskId, new TaskContainer(taskId)); } final TaskContainer taskContainer = mTaskContainers.get(taskId); taskContainer.mContainers.add(container); final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer, this); if (!taskContainer.isTaskBoundsInitialized()) { // Get the initial bounds before the TaskFragment has appeared. final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask); Loading Loading @@ -500,14 +512,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) { removeExistingSecondaryContainers(wct, primaryContainer); } mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer); primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer); } /** Cleanups all the dependencies when the TaskFragment is entering PIP. */ private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentContainer container) { final int taskId = container.getTaskId(); final TaskContainer taskContainer = mTaskContainers.get(taskId); final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } Loading Loading @@ -545,8 +556,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ void removeContainer(@NonNull TaskFragmentContainer container) { // Remove all split containers that included this one final int taskId = container.getTaskId(); final TaskContainer taskContainer = mTaskContainers.get(taskId); final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } Loading Loading @@ -637,8 +647,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitContainer == null) { return; } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainer != splitContainers.get(splitContainers.size() - 1)) { // Skip position update - it isn't the topmost split. return; Loading @@ -660,8 +669,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Nullable private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) { final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainers.isEmpty()) { return null; } Loading @@ -683,11 +691,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private SplitContainer getActiveSplitForContainers( @NonNull TaskFragmentContainer firstContainer, @NonNull TaskFragmentContainer secondContainer) { final List<SplitContainer> splitContainers = mTaskContainers.get(firstContainer.getTaskId()) final List<SplitContainer> splitContainers = firstContainer.getTaskContainer() .mSplitContainers; if (splitContainers == null) { return null; } for (int i = splitContainers.size() - 1; i >= 0; i--) { final SplitContainer splitContainer = splitContainers.get(i); final TaskFragmentContainer primary = splitContainer.getPrimaryContainer(); Loading Loading @@ -856,11 +861,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (container == null) { return false; } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null) { return true; } final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; for (SplitContainer splitContainer : splitContainers) { if (container.equals(splitContainer.getPrimaryContainer()) || container.equals(splitContainer.getSecondaryContainer())) { Loading Loading @@ -1046,6 +1047,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen public void onActivityConfigurationChanged(Activity activity) { SplitController.this.onActivityConfigurationChanged(activity); } @Override public void onActivityPostDestroyed(Activity activity) { SplitController.this.onActivityDestroyed(activity); } } /** Executor that posts on the main application thread. */ Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +2 −8 Original line number Diff line number Diff line Loading @@ -291,8 +291,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // When placeholder is shown in split, we should keep the focus on the primary. wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); } final TaskContainer taskContainer = mController.getTaskContainer( updatedContainer.getTaskId()); final TaskContainer taskContainer = updatedContainer.getTaskContainer(); final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment( primaryRectBounds); updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode); Loading Loading @@ -456,12 +455,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) { final int taskId = container.getTaskId(); final TaskContainer taskContainer = mController.getTaskContainer(taskId); if (taskContainer == null) { throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId); } return taskContainer.getTaskBounds(); return container.getTaskContainer().getTaskBounds(); } @NonNull Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +12 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ package androidx.window.extensions.embedding; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.graphics.Rect; Loading Loading @@ -62,6 +64,9 @@ class TaskContainer { final Set<IBinder> mFinishedContainer = new ArraySet<>(); TaskContainer(int taskId) { if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); } mTaskId = taskId; } Loading Loading @@ -130,4 +135,11 @@ class TaskContainer { boolean isEmpty() { return mContainers.isEmpty() && mFinishedContainer.isEmpty(); } /** Removes the pending appeared activity from all TaskFragments in this Task. */ void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { for (TaskFragmentContainer container : mContainers) { container.removePendingAppearedActivity(pendingAppearedActivity); } } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +23 −9 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package androidx.window.extensions.embedding; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; Loading Loading @@ -52,8 +51,9 @@ class TaskFragmentContainer { @NonNull private final IBinder mToken; /** Parent leaf Task id. */ private final int mTaskId; /** Parent leaf Task. */ @NonNull private final TaskContainer mTaskContainer; /** * Server-provided task fragment information. Loading Loading @@ -100,14 +100,12 @@ class TaskFragmentContainer { * Creates a container with an existing activity that will be re-parented to it in a window * container transaction. */ TaskFragmentContainer(@Nullable Activity activity, int taskId, TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer, @NonNull SplitController controller) { mController = controller; mToken = new Binder("TaskFragmentContainer"); if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); } mTaskId = taskId; mTaskContainer = taskContainer; taskContainer.mContainers.add(this); if (activity != null) { addPendingAppearedActivity(activity); } Loading Loading @@ -162,9 +160,18 @@ class TaskFragmentContainer { } void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { if (hasActivity(pendingAppearedActivity.getActivityToken())) { return; } // Remove the pending activity from other TaskFragments. mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity); mPendingAppearedActivities.add(pendingAppearedActivity); } void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { mPendingAppearedActivities.remove(pendingAppearedActivity); } boolean hasActivity(@NonNull IBinder token) { if (mInfo != null && mInfo.getActivities().contains(token)) { return true; Loading Loading @@ -376,7 +383,13 @@ class TaskFragmentContainer { /** Gets the parent leaf Task id. */ int getTaskId() { return mTaskId; return mTaskContainer.getTaskId(); } /** Gets the parent Task. */ @NonNull TaskContainer getTaskContainer() { return mTaskContainer; } @Override Loading @@ -392,6 +405,7 @@ class TaskFragmentContainer { */ private String toString(boolean includeContainersToFinishOnExit) { return "TaskFragmentContainer{" + " parentTaskId=" + getTaskId() + " token=" + mToken + " topNonFinishingActivity=" + getTopNonFinishingActivity() + " runningActivityCount=" + getRunningActivityCount() Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -113,8 +113,9 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { final TaskContainer taskContainer = new TaskContainer(TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); taskContainer, mSplitController); final TaskFragmentInfo info = createMockInfo(container); mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info); container.setInfo(info); Loading