Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +28 −6 Original line number Diff line number Diff line Loading @@ -81,9 +81,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @NonNull private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; public SplitController() { mPresenter = new SplitPresenter(new MainThreadExecutor(), this); final MainThreadExecutor executor = new MainThreadExecutor(); mHandler = executor.mHandler; mPresenter = new SplitPresenter(executor, this); ActivityThread activityThread = ActivityThread.currentActivityThread(); // Register a callback to be notified about activities being created. activityThread.getApplication().registerActivityLifecycleCallbacks( Loading Loading @@ -167,11 +170,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // to fullscreen. cleanupForEnterPip(wct, container); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else { } else if (taskFragmentInfo.isTaskClearedForReuse()) { // Do not finish the dependents if this TaskFragment was cleared due to launching // activity in the Task. final boolean shouldFinishDependent = !taskFragmentInfo.isTaskClearedForReuse(); mPresenter.cleanupContainer(container, shouldFinishDependent, wct); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (!container.isWaitingActivityAppear()) { // Do not finish the container before the expected activity appear until timeout. mPresenter.cleanupContainer(container, true /* shouldFinishDependent */, wct); } } else if (wasInPip && isInPip) { // No update until exit PIP. Loading Loading @@ -417,6 +422,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen launchPlaceholderIfNecessary(activity); } /** * Called when we have been waiting too long for the TaskFragment to become non-empty after * creation. */ void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) { mPresenter.cleanupContainer(container, false /* shouldFinishDependent */); } /** * Returns a container that this activity is registered with. An activity can only belong to one * container, or no container at all. Loading Loading @@ -452,7 +465,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (activityInTask == null) { throw new IllegalArgumentException("activityInTask must not be null,"); } final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId); final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this); if (!mTaskContainers.contains(taskId)) { mTaskContainers.put(taskId, new TaskContainer(taskId)); } Loading Loading @@ -590,7 +603,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) { final TaskFragmentContainer container = taskContainer.mContainers.get(i); if (!container.isFinished() && container.getRunningActivityCount() > 0) { if (!container.isFinished() && (container.getRunningActivityCount() > 0 // We may be waiting for the top TaskFragment to become non-empty after // creation. In that case, we don't want to treat the TaskFragment below it as // top active, otherwise it may incorrectly launch placeholder on top of the // pending TaskFragment. || container.isWaitingActivityAppear())) { return container; } } Loading Loading @@ -920,6 +938,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return mTaskContainers.get(taskId); } Handler getHandler() { return mHandler; } /** * Returns {@code true} if an Activity with the provided component name should always be * expanded to occupy full task bounds. Such activity must not be put in a split. Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +42 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.os.IBinder; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Iterator; import java.util.List; Loading @@ -39,6 +41,11 @@ import java.util.List; * on the server side. */ class TaskFragmentContainer { private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000; @NonNull private final SplitController mController; /** * Client-created token that uniquely identifies the task fragment container instance. */ Loading @@ -51,7 +58,8 @@ class TaskFragmentContainer { /** * Server-provided task fragment information. */ private TaskFragmentInfo mInfo; @VisibleForTesting TaskFragmentInfo mInfo; /** * Activities that are being reparented or being started to this container, but haven't been Loading Loading @@ -80,11 +88,21 @@ class TaskFragmentContainer { @WindowingMode private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED; /** * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * if it is still empty after the timeout. */ @VisibleForTesting @Nullable Runnable mAppearEmptyTimeout; /** * 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, int taskId, @NonNull SplitController controller) { mController = controller; mToken = new Binder("TaskFragmentContainer"); if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); Loading Loading @@ -155,12 +173,30 @@ class TaskFragmentContainer { return count; } /** Whether we are waiting for the TaskFragment to appear and become non-empty. */ boolean isWaitingActivityAppear() { return !mIsFinished && (mInfo == null || mAppearEmptyTimeout != null); } @Nullable TaskFragmentInfo getInfo() { return mInfo; } void setInfo(@NonNull TaskFragmentInfo info) { if (!mIsFinished && mInfo == null && info.isEmpty()) { // onTaskFragmentAppeared with empty info. We will remove the TaskFragment if it is // still empty after timeout. mAppearEmptyTimeout = () -> { mAppearEmptyTimeout = null; mController.onTaskFragmentAppearEmptyTimeout(this); }; mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS); } else if (mAppearEmptyTimeout != null && !info.isEmpty()) { mController.getHandler().removeCallbacks(mAppearEmptyTimeout); mAppearEmptyTimeout = null; } mInfo = info; if (mInfo == null || mPendingAppearedActivities.isEmpty()) { return; Loading Loading @@ -234,6 +270,10 @@ class TaskFragmentContainer { @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) { if (!mIsFinished) { mIsFinished = true; if (mAppearEmptyTimeout != null) { mController.getHandler().removeCallbacks(mAppearEmptyTimeout); mAppearEmptyTimeout = null; } finishActivities(shouldFinishDependent, presenter, wct, controller); } Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading @@ -29,6 +30,7 @@ import static org.mockito.Mockito.never; import android.content.res.Configuration; import android.graphics.Point; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerToken; Loading Loading @@ -61,6 +63,10 @@ public class JetpackTaskFragmentOrganizerTest { private WindowContainerTransaction mTransaction; @Mock private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback; @Mock private SplitController mSplitController; @Mock private Handler mHandler; private JetpackTaskFragmentOrganizer mOrganizer; @Before Loading @@ -69,6 +75,7 @@ public class JetpackTaskFragmentOrganizerTest { mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback); mOrganizer.registerOrganizer(); spyOn(mOrganizer); doReturn(mHandler).when(mSplitController).getHandler(); } @Test Loading Loading @@ -106,7 +113,8 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { final TaskFragmentContainer container = new TaskFragmentContainer(null, TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); final TaskFragmentInfo info = createMockInfo(container); mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info); container.setInfo(info); Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +36 −5 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.app.Activity; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; Loading @@ -48,6 +49,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** Loading @@ -71,6 +73,9 @@ public class SplitControllerTest { private TaskFragmentInfo mInfo; @Mock private WindowContainerTransaction mTransaction; @Mock private Handler mHandler; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading @@ -86,6 +91,7 @@ public class SplitControllerTest { activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS); doReturn(mActivityResources).when(mActivity).getResources(); doReturn(activityConfig).when(mActivityResources).getConfiguration(); doReturn(mHandler).when(mSplitController).getHandler(); } @Test Loading @@ -94,28 +100,45 @@ public class SplitControllerTest { // tf3 is finished so is not active. TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class); doReturn(true).when(tf3).isFinished(); doReturn(false).when(tf3).isWaitingActivityAppear(); // tf2 has running activity so is active. TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class); doReturn(1).when(tf2).getRunningActivityCount(); // tf1 has no running activity so is not active. TaskFragmentContainer tf1 = new TaskFragmentContainer(null, TASK_ID); TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); taskContainer.mContainers.add(tf3); taskContainer.mContainers.add(tf2); taskContainer.mContainers.add(tf1); taskContainer.mContainers.add(tf2); taskContainer.mContainers.add(tf3); mSplitController.mTaskContainers.put(TASK_ID, taskContainer); assertWithMessage("Must return tf2 because tf3 is not active.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2); taskContainer.mContainers.remove(tf1); taskContainer.mContainers.remove(tf3); assertWithMessage("Must return tf2 because tf2 has running activity.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2); taskContainer.mContainers.remove(tf2); assertWithMessage("Must return null because tf1 has no running activity.") assertWithMessage("Must return tf because we are waiting for tf1 to appear.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1); final TaskFragmentInfo info = mock(TaskFragmentInfo.class); doReturn(new ArrayList<>()).when(info).getActivities(); doReturn(true).when(info).isEmpty(); tf1.setInfo(info); assertWithMessage("Must return tf because we are waiting for tf1 to become non-empty after" + " creation.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1); doReturn(false).when(info).isEmpty(); tf1.setInfo(info); assertWithMessage("Must return null because tf1 becomes empty.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isNull(); } Loading @@ -132,6 +155,14 @@ public class SplitControllerTest { verify(mActivity, never()).finish(); } @Test public void testOnTaskFragmentAppearEmptyTimeout() { final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); mSplitController.onTaskFragmentAppearEmptyTimeout(tf); verify(mSplitPresenter).cleanupContainer(tf, false /* shouldFinishDependent */); } @Test public void testNewContainer() { // Must pass in a valid activity. Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java +13 −1 Original line number Diff line number Diff line Loading @@ -32,8 +32,11 @@ import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Test class for {@link TaskContainer}. Loading @@ -48,6 +51,14 @@ public class TaskContainerTest { private static final int TASK_ID = 10; private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200); @Mock private SplitController mController; @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testIsTaskBoundsInitialized() { final TaskContainer taskContainer = new TaskContainer(TASK_ID); Loading Loading @@ -126,7 +137,8 @@ public class TaskContainerTest { assertTrue(taskContainer.isEmpty()); final TaskFragmentContainer tf = new TaskFragmentContainer(null, TASK_ID); final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, TASK_ID, mController); taskContainer.mContainers.add(tf); assertFalse(taskContainer.isEmpty()); Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +28 −6 Original line number Diff line number Diff line Loading @@ -81,9 +81,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @NonNull private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; public SplitController() { mPresenter = new SplitPresenter(new MainThreadExecutor(), this); final MainThreadExecutor executor = new MainThreadExecutor(); mHandler = executor.mHandler; mPresenter = new SplitPresenter(executor, this); ActivityThread activityThread = ActivityThread.currentActivityThread(); // Register a callback to be notified about activities being created. activityThread.getApplication().registerActivityLifecycleCallbacks( Loading Loading @@ -167,11 +170,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // to fullscreen. cleanupForEnterPip(wct, container); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else { } else if (taskFragmentInfo.isTaskClearedForReuse()) { // Do not finish the dependents if this TaskFragment was cleared due to launching // activity in the Task. final boolean shouldFinishDependent = !taskFragmentInfo.isTaskClearedForReuse(); mPresenter.cleanupContainer(container, shouldFinishDependent, wct); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (!container.isWaitingActivityAppear()) { // Do not finish the container before the expected activity appear until timeout. mPresenter.cleanupContainer(container, true /* shouldFinishDependent */, wct); } } else if (wasInPip && isInPip) { // No update until exit PIP. Loading Loading @@ -417,6 +422,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen launchPlaceholderIfNecessary(activity); } /** * Called when we have been waiting too long for the TaskFragment to become non-empty after * creation. */ void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) { mPresenter.cleanupContainer(container, false /* shouldFinishDependent */); } /** * Returns a container that this activity is registered with. An activity can only belong to one * container, or no container at all. Loading Loading @@ -452,7 +465,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (activityInTask == null) { throw new IllegalArgumentException("activityInTask must not be null,"); } final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId); final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this); if (!mTaskContainers.contains(taskId)) { mTaskContainers.put(taskId, new TaskContainer(taskId)); } Loading Loading @@ -590,7 +603,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) { final TaskFragmentContainer container = taskContainer.mContainers.get(i); if (!container.isFinished() && container.getRunningActivityCount() > 0) { if (!container.isFinished() && (container.getRunningActivityCount() > 0 // We may be waiting for the top TaskFragment to become non-empty after // creation. In that case, we don't want to treat the TaskFragment below it as // top active, otherwise it may incorrectly launch placeholder on top of the // pending TaskFragment. || container.isWaitingActivityAppear())) { return container; } } Loading Loading @@ -920,6 +938,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return mTaskContainers.get(taskId); } Handler getHandler() { return mHandler; } /** * Returns {@code true} if an Activity with the provided component name should always be * expanded to occupy full task bounds. Such activity must not be put in a split. Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +42 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.os.IBinder; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Iterator; import java.util.List; Loading @@ -39,6 +41,11 @@ import java.util.List; * on the server side. */ class TaskFragmentContainer { private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000; @NonNull private final SplitController mController; /** * Client-created token that uniquely identifies the task fragment container instance. */ Loading @@ -51,7 +58,8 @@ class TaskFragmentContainer { /** * Server-provided task fragment information. */ private TaskFragmentInfo mInfo; @VisibleForTesting TaskFragmentInfo mInfo; /** * Activities that are being reparented or being started to this container, but haven't been Loading Loading @@ -80,11 +88,21 @@ class TaskFragmentContainer { @WindowingMode private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED; /** * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * if it is still empty after the timeout. */ @VisibleForTesting @Nullable Runnable mAppearEmptyTimeout; /** * 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, int taskId, @NonNull SplitController controller) { mController = controller; mToken = new Binder("TaskFragmentContainer"); if (taskId == INVALID_TASK_ID) { throw new IllegalArgumentException("Invalid Task id"); Loading Loading @@ -155,12 +173,30 @@ class TaskFragmentContainer { return count; } /** Whether we are waiting for the TaskFragment to appear and become non-empty. */ boolean isWaitingActivityAppear() { return !mIsFinished && (mInfo == null || mAppearEmptyTimeout != null); } @Nullable TaskFragmentInfo getInfo() { return mInfo; } void setInfo(@NonNull TaskFragmentInfo info) { if (!mIsFinished && mInfo == null && info.isEmpty()) { // onTaskFragmentAppeared with empty info. We will remove the TaskFragment if it is // still empty after timeout. mAppearEmptyTimeout = () -> { mAppearEmptyTimeout = null; mController.onTaskFragmentAppearEmptyTimeout(this); }; mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS); } else if (mAppearEmptyTimeout != null && !info.isEmpty()) { mController.getHandler().removeCallbacks(mAppearEmptyTimeout); mAppearEmptyTimeout = null; } mInfo = info; if (mInfo == null || mPendingAppearedActivities.isEmpty()) { return; Loading Loading @@ -234,6 +270,10 @@ class TaskFragmentContainer { @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) { if (!mIsFinished) { mIsFinished = true; if (mAppearEmptyTimeout != null) { mController.getHandler().removeCallbacks(mAppearEmptyTimeout); mAppearEmptyTimeout = null; } finishActivities(shouldFinishDependent, presenter, wct, controller); } Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading @@ -29,6 +30,7 @@ import static org.mockito.Mockito.never; import android.content.res.Configuration; import android.graphics.Point; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerToken; Loading Loading @@ -61,6 +63,10 @@ public class JetpackTaskFragmentOrganizerTest { private WindowContainerTransaction mTransaction; @Mock private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback; @Mock private SplitController mSplitController; @Mock private Handler mHandler; private JetpackTaskFragmentOrganizer mOrganizer; @Before Loading @@ -69,6 +75,7 @@ public class JetpackTaskFragmentOrganizerTest { mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback); mOrganizer.registerOrganizer(); spyOn(mOrganizer); doReturn(mHandler).when(mSplitController).getHandler(); } @Test Loading Loading @@ -106,7 +113,8 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { final TaskFragmentContainer container = new TaskFragmentContainer(null, TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); final TaskFragmentInfo info = createMockInfo(container); mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info); container.setInfo(info); Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +36 −5 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.app.Activity; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; Loading @@ -48,6 +49,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** Loading @@ -71,6 +73,9 @@ public class SplitControllerTest { private TaskFragmentInfo mInfo; @Mock private WindowContainerTransaction mTransaction; @Mock private Handler mHandler; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading @@ -86,6 +91,7 @@ public class SplitControllerTest { activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS); doReturn(mActivityResources).when(mActivity).getResources(); doReturn(activityConfig).when(mActivityResources).getConfiguration(); doReturn(mHandler).when(mSplitController).getHandler(); } @Test Loading @@ -94,28 +100,45 @@ public class SplitControllerTest { // tf3 is finished so is not active. TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class); doReturn(true).when(tf3).isFinished(); doReturn(false).when(tf3).isWaitingActivityAppear(); // tf2 has running activity so is active. TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class); doReturn(1).when(tf2).getRunningActivityCount(); // tf1 has no running activity so is not active. TaskFragmentContainer tf1 = new TaskFragmentContainer(null, TASK_ID); TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */, TASK_ID, mSplitController); taskContainer.mContainers.add(tf3); taskContainer.mContainers.add(tf2); taskContainer.mContainers.add(tf1); taskContainer.mContainers.add(tf2); taskContainer.mContainers.add(tf3); mSplitController.mTaskContainers.put(TASK_ID, taskContainer); assertWithMessage("Must return tf2 because tf3 is not active.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2); taskContainer.mContainers.remove(tf1); taskContainer.mContainers.remove(tf3); assertWithMessage("Must return tf2 because tf2 has running activity.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2); taskContainer.mContainers.remove(tf2); assertWithMessage("Must return null because tf1 has no running activity.") assertWithMessage("Must return tf because we are waiting for tf1 to appear.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1); final TaskFragmentInfo info = mock(TaskFragmentInfo.class); doReturn(new ArrayList<>()).when(info).getActivities(); doReturn(true).when(info).isEmpty(); tf1.setInfo(info); assertWithMessage("Must return tf because we are waiting for tf1 to become non-empty after" + " creation.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1); doReturn(false).when(info).isEmpty(); tf1.setInfo(info); assertWithMessage("Must return null because tf1 becomes empty.") .that(mSplitController.getTopActiveContainer(TASK_ID)).isNull(); } Loading @@ -132,6 +155,14 @@ public class SplitControllerTest { verify(mActivity, never()).finish(); } @Test public void testOnTaskFragmentAppearEmptyTimeout() { final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); mSplitController.onTaskFragmentAppearEmptyTimeout(tf); verify(mSplitPresenter).cleanupContainer(tf, false /* shouldFinishDependent */); } @Test public void testNewContainer() { // Must pass in a valid activity. Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java +13 −1 Original line number Diff line number Diff line Loading @@ -32,8 +32,11 @@ import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Test class for {@link TaskContainer}. Loading @@ -48,6 +51,14 @@ public class TaskContainerTest { private static final int TASK_ID = 10; private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200); @Mock private SplitController mController; @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testIsTaskBoundsInitialized() { final TaskContainer taskContainer = new TaskContainer(TASK_ID); Loading Loading @@ -126,7 +137,8 @@ public class TaskContainerTest { assertTrue(taskContainer.isEmpty()); final TaskFragmentContainer tf = new TaskFragmentContainer(null, TASK_ID); final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, TASK_ID, mController); taskContainer.mContainers.add(tf); assertFalse(taskContainer.isEmpty()); Loading