blob: cc73c842bd93978f3d0e297deed2de659513df86 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.SplitActivityLifecycleTest.ActivityB.EXTRA_SHOW_WHEN_LOCKED;
import static android.server.wm.WindowManagerState.STATE_STARTED;
import static android.server.wm.WindowManagerState.STATE_STOPPED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.server.wm.WindowManagerState.Task;
import android.server.wm.WindowManagerState.TaskFragment;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import org.junit.Ignore;
import org.junit.Test;
/**
* Tests that verify the behavior of split Activity.
* <p>
* At the beginning of test, two Activities are launched side-by-side in two adjacent TaskFragments.
* Then another Activity will be launched with different scenarios. The purpose of this test is to
* verify the CUJ of split Activity.
* </p>
*
* Build/Install/Run:
* atest CtsWindowManagerDeviceTestCases:SplitActivityLifecycleTest
*/
@Presubmit
public class SplitActivityLifecycleTest extends TaskFragmentOrganizerTestBase {
private Activity mOwnerActivity;
private IBinder mOwnerToken;
private final Rect mPrimaryBounds = new Rect();
private final Rect mSideBounds = new Rect();
private TaskFragmentRecord mTaskFragA;
private TaskFragmentRecord mTaskFragB;
private final ComponentName mActivityA = new ComponentName(mContext, ActivityA.class);
private final ComponentName mActivityB = new ComponentName(mContext, ActivityB.class);
private final ComponentName mActivityC = new ComponentName(mContext, ActivityC.class);
private final Intent mIntent = new Intent().setComponent(mActivityC);
@Override
public void setUp() throws Exception {
super.setUp();
mOwnerActivity = startActivity(ActivityA.class);
mOwnerToken = getActivityToken(mOwnerActivity);
}
/** Launch two Activities in two adjacent TaskFragments side-by-side. */
private void initializeSplitActivities(boolean splitInEmbeddedTask) {
initializeSplitActivities(splitInEmbeddedTask, false /* showWhenLocked */);
}
/**
* Launch two Activities in two adjacent TaskFragments side-by-side and support to set the
* showWhenLocked attribute to Activity B.
*/
private void initializeSplitActivities(boolean splitInEmbeddedTask, boolean showWhenLocked) {
final Rect activityBounds = mOwnerActivity.getWindowManager().getCurrentWindowMetrics()
.getBounds();
activityBounds.splitVertically(mPrimaryBounds, mSideBounds);
final TaskFragmentCreationParams paramsA = generatePrimaryTaskFragParams();
final TaskFragmentCreationParams paramsB = generateSideTaskFragParams();
IBinder taskFragTokenA = paramsA.getFragmentToken();
IBinder taskFragTokenB = paramsB.getFragmentToken();
final WindowContainerTransaction wct = new WindowContainerTransaction()
.createTaskFragment(paramsA)
.reparentActivityToTaskFragment(taskFragTokenA, mOwnerToken)
.createTaskFragment(paramsB)
.setAdjacentTaskFragments(taskFragTokenA, taskFragTokenB, null /* params */);
final Intent intent = new Intent().setComponent(mActivityB);
if (splitInEmbeddedTask) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
}
if (showWhenLocked) {
intent.putExtra(EXTRA_SHOW_WHEN_LOCKED, true);
}
wct.startActivityInTaskFragment(taskFragTokenB, mOwnerToken, intent,
null /* activityOptions */);
mTaskFragmentOrganizer.setAppearedCount(2);
mTaskFragmentOrganizer.applyTransaction(wct);
mTaskFragmentOrganizer.waitForTaskFragmentCreated();
final TaskFragmentInfo infoA = mTaskFragmentOrganizer.getTaskFragmentInfo(
taskFragTokenA);
final TaskFragmentInfo infoB = mTaskFragmentOrganizer.getTaskFragmentInfo(
taskFragTokenB);
assertNotEmptyTaskFragment(infoA, taskFragTokenA, mOwnerToken);
assertNotEmptyTaskFragment(infoB, taskFragTokenB);
mTaskFragA = new TaskFragmentRecord(infoA);
mTaskFragB = new TaskFragmentRecord(infoB);
waitAndAssertResumedActivity(mActivityA, "Activity A must still be resumed.");
waitAndAssertResumedActivity(mActivityB, "Activity B must still be resumed.");
if (splitInEmbeddedTask) {
TaskFragment taskFragmentB = mWmState.getTaskFragmentByActivity(mActivityB);
Task embeddedTask = mWmState.getTaskByActivity(mActivityB);
assertWindowHierarchy(taskFragmentB, embeddedTask, mWmState.getActivity(mActivityB));
}
mTaskFragmentOrganizer.resetLatch();
}
/**
* Verifies the behavior to launch Activity in the same TaskFragment as the owner Activity.
* <p>
* For example, given that Activity A and B are showed side-by-side, this test verifies
* the behavior to launch Activity C in the same TaskFragment as Activity A:
* <pre class="prettyprint">
* |A|B| -> |C|B|
* </pre></p>
*/
@Test
public void testActivityLaunchInSameSplitTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */);
final IBinder taskFragTokenA = mTaskFragA.getTaskFragToken();
final WindowContainerTransaction wct = new WindowContainerTransaction()
.startActivityInTaskFragment(taskFragTokenA, mOwnerToken, mIntent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
final TaskFragmentInfo infoA = mTaskFragmentOrganizer.waitForAndGetTaskFragmentInfo(
taskFragTokenA, info -> info.getActivities().size() == 2,
"getActivities from TaskFragment A must contain 2 activities");
assertNotEmptyTaskFragment(infoA, taskFragTokenA, mOwnerToken);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STOPPED,
"Activity A is occluded by Activity C, so it must be stopped.");
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
final TaskFragment taskFragmentA = mWmState.getTaskFragmentByActivity(mActivityA);
assertWithMessage("TaskFragmentA must contain Activity A and C")
.that(taskFragmentA.mActivities).containsExactly(mWmState.getActivity(mActivityA),
mWmState.getActivity(mActivityC));
}
/**
* Verifies the behavior to launch Activity in the adjacent TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, this test verifies
* the behavior to launch Activity C in the same TaskFragment as Activity B:
* <pre class="prettyprint">
* |A|B| -> |A|C|
* </pre></p>
*/
@Test
public void testActivityLaunchInAdjacentSplitTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */);
final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
final WindowContainerTransaction wct = new WindowContainerTransaction()
.startActivityInTaskFragment(taskFragTokenB, mOwnerToken, mIntent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
final TaskFragmentInfo infoB = mTaskFragmentOrganizer.waitForAndGetTaskFragmentInfo(
taskFragTokenB, info -> info.getActivities().size() == 2,
"getActivities from TaskFragment A must contain 2 activities");
assertNotEmptyTaskFragment(infoB, taskFragTokenB);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,
"Activity B is occluded by Activity C, so it must be stopped.");
final TaskFragment taskFragmentB = mWmState.getTaskFragmentByActivity(mActivityB);
assertWithMessage("TaskFragmentB must contain Activity B and C")
.that(taskFragmentB.mActivities).containsExactly(mWmState.getActivity(mActivityB),
mWmState.getActivity(mActivityC));
}
/**
* Verifies the behavior that the Activity instance in bottom TaskFragment calls
* {@link Context#startActivity(Intent)} to launch another Activity.
* <p>
* For example, given that Activity A and B are showed side-by-side, Activity A calls
* {@link Context#startActivity(Intent)} to launch Activity C. The expected behavior is that
* Activity C will be launch on top of Activity B as below:
* <pre class="prettyprint">
* |A|B| -> |A|C|
* </pre>
* The reason is that TaskFragment B has higher z-order than TaskFragment A because we create
* TaskFragment B later than TaskFragment A.
* </p>
*/
@Test
public void testActivityLaunchFromBottomTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */);
mOwnerActivity.startActivity(mIntent);
final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
final TaskFragmentInfo infoB = mTaskFragmentOrganizer.waitForAndGetTaskFragmentInfo(
taskFragTokenB, info -> info.getActivities().size() == 2,
"getActivities from TaskFragment A must contain 2 activities");
assertNotEmptyTaskFragment(infoB, taskFragTokenB);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,
"Activity B is occluded by Activity C, so it must be stopped.");
final TaskFragment taskFragmentB = mWmState.getTaskFragmentByActivity(mActivityB);
assertWithMessage("TaskFragmentB must contain Activity B and C")
.that(taskFragmentB.mActivities).containsExactly(mWmState.getActivity(mActivityB),
mWmState.getActivity(mActivityC));
}
/**
* Verifies the behavior to launch adjacent Activity to the adjacent TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, this test verifies
* the behavior to launch the Activity C to the adjacent TaskFragment of the secondary
* TaskFragment, which Activity B is attached to. Then the secondary TaskFragment is shifted to
* occlude the primary TaskFragment, which Activity A is attached to, and the adjacent
* TaskFragment, which Activity C is attached to, is occupied the region where the secondary
* TaskFragment is located. This test is to verify the "shopping mode" scenario.
* <pre class="prettyprint">
* |A|B| -> |B|C|
* </pre></p>
*/
@Test
public void testAdjacentActivityLaunchFromSecondarySplitTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */);
final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
final TaskFragmentCreationParams paramsC = generateSideTaskFragParams();
final IBinder taskFragTokenC = paramsC.getFragmentToken();
final WindowContainerTransaction wct = new WindowContainerTransaction()
// Move TaskFragment B to the primaryBounds
.setBounds(mTaskFragB.getToken(), mPrimaryBounds)
// Create the side TaskFragment for C and launch
.createTaskFragment(paramsC)
.startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent,
null /* activityOptions */)
.setAdjacentTaskFragments(taskFragTokenB, taskFragTokenC, null /* options */);
mTaskFragmentOrganizer.applyTransaction(wct);
// Wait for the TaskFragment of Activity C to be created.
mTaskFragmentOrganizer.waitForTaskFragmentCreated();
// Wait for the TaskFragment of Activity B to be changed.
mTaskFragmentOrganizer.waitForTaskFragmentInfoChanged();
final TaskFragmentInfo infoB = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragTokenB);
final TaskFragmentInfo infoC = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragTokenC);
assertNotEmptyTaskFragment(infoB, taskFragTokenB);
assertNotEmptyTaskFragment(infoC, taskFragTokenC);
mTaskFragB = new TaskFragmentRecord(infoB);
final TaskFragmentRecord taskFragC = new TaskFragmentRecord(infoC);
assertThat(mTaskFragB.getBounds()).isEqualTo(mPrimaryBounds);
assertThat(taskFragC.getBounds()).isEqualTo(mSideBounds);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STOPPED,
"Activity A is occluded by Activity C, so it must be stopped.");
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
}
/**
* Verifies the behavior to launch Activity in expanded TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, this test verifies
* the behavior to launch Activity C in the TaskFragment which fills the Task bounds of owner
* Activity:
* <pre class="prettyprint">
* |A|B| -> |C|
* </pre></p>
*/
@Test
public void testActivityLaunchInExpandedTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */);
testActivityLaunchInExpandedTaskFragmentInternal();
}
/**
* Verifies the behavior to launch Activity in expanded TaskFragment and occludes the embedded
* Task.
* <p>
* For example, given that Activity A and B are showed side-by-side, which Activity B is in
* embedded Task, this test verifies the behavior to launch Activity C in the TaskFragment which
* fills the Task bounds of owner Activity:
* <pre class="prettyprint">
* - Fullscreen -
* TaskFragmentC
* - ActivityC <---- new started Activity
* - Left - - Right -
* TaskFragmentA TaskFragmentB
* - ActivityA - Embedded Task
* - ActivityB
* </pre></p>
*/
@Test
@Ignore("b/197364677")
public void testActivityLaunchInExpandedTaskFragment_AboveEmbeddedTask() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(true /* verifyEmbeddedTask */);
testActivityLaunchInExpandedTaskFragmentInternal();
}
private void testActivityLaunchInExpandedTaskFragmentInternal() {
final TaskFragmentCreationParams fullScreenParamsC = mTaskFragmentOrganizer
.generateTaskFragParams(mOwnerToken);
final IBinder taskFragTokenC = fullScreenParamsC.getFragmentToken();
final WindowContainerTransaction wct = new WindowContainerTransaction()
.createTaskFragment(fullScreenParamsC)
.startActivityInTaskFragment(taskFragTokenC, mOwnerToken, mIntent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
mTaskFragmentOrganizer.waitForTaskFragmentCreated();
assertNotEmptyTaskFragment(mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragTokenC),
taskFragTokenC);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STOPPED,
"Activity A is occluded by Activity C, so it must be stopped.");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,
"Activity B is occluded by Activity C, so it must be stopped.");
}
/**
* Verifies the behavior to launch Activity above the embedded Task in TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, which Activity B is in
* embedded Task, this test verifies the behavior to launch Activity C on top of the embedded
* Task in the same TaskFragment as Activity B:
* <pre class="prettyprint">
* - Left - - Right -
* TaskFragmentA TaskFragmentB
* - ActivityA - ActivityC <---- new started Activity
* - Embedded Task
* - ActivityB
* </pre></p>
*/
@Test
@Ignore("b/197364677")
public void testActivityLaunchAboveEmbeddedTaskInTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(true /* verifyEmbeddedTask */);
final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
WindowContainerTransaction wct = new WindowContainerTransaction()
.startActivityInTaskFragment(taskFragTokenB, mOwnerToken, mIntent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
mTaskFragmentOrganizer.waitForTaskFragmentInfoChanged();
final TaskFragmentInfo infoB = mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragTokenB);
assertNotEmptyTaskFragment(infoB, taskFragTokenB);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
waitAndAssertActivityState(mActivityB, WindowManagerState.STATE_STOPPED,
"Activity B is occluded by Activity C, so it must be stopped.");
final TaskFragment taskFragmentB = mWmState.getTaskFragmentByActivity(mActivityB);
assertWithMessage("TaskFragmentB must contain Activity C")
.that(taskFragmentB.mActivities).containsExactly(mWmState.getActivity(mActivityC));
}
/**
* Verifies the behavior to launch Activity to the embedded Task in TaskFragment.
* <p>
* For example, given that Activity A and B are showed side-by-side, which Activity B is in
* embedded Task, this test verifies the behavior to launch Activity C to the embedded Task
* and on top of Activity B:
* <pre class="prettyprint">
* - Left - - Right -
* TaskFragmentA TaskFragmentB
* - ActivityA - Embedded Task
* - ActivityC <---- new started Activity
* - ActivityB
* </pre></p>
*/
@Test
@Ignore("b/197364677")
public void testActivityLaunchToEmbeddedTaskInTaskFragment() {
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(true /* verifyEmbeddedTask */);
final IBinder taskFragTokenB = mTaskFragB.getTaskFragToken();
// Make Activity C launch to the embedded Task.
final Intent intent = new Intent(mIntent).addFlags(FLAG_ACTIVITY_NEW_TASK);
WindowContainerTransaction wct = new WindowContainerTransaction()
.startActivityInTaskFragment(taskFragTokenB, mOwnerToken, intent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
waitAndAssertResumedActivity(mActivityC, "Activity C must be resumed.");
waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,
"Activity B is occluded by Activity C, so it must be stopped.");
final Task embeddedTask = mWmState.getTaskByActivity(mActivityB);
assertWithMessage("Embedded Task must contain Activity B and Activity C")
.that(embeddedTask.mActivities).containsExactly(mWmState.getActivity(mActivityB),
mWmState.getActivity(mActivityC));
}
/**
* Verifies the show-when-locked behavior while launch embedded activities. Don't show the
* embedded activities even if one of Activity has showWhenLocked flag.
*/
@Test
public void testLaunchEmbeddedActivityWithShowWhenLocked() {
assumeTrue(supportsLockScreen());
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
// Initialize test environment by launching Activity A and B (with showWhenLocked)
// side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */);
lockScreenSession.sleepDevice();
lockScreenSession.wakeUpDevice();
waitAndAssertActivityState(mActivityA, STATE_STOPPED,"Activity A must be stopped");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,"Activity B must be stopped");
}
/**
* Verifies the show-when-locked behavior while launch embedded activities. Don't show the
* embedded activities if the activities don't have showWhenLocked flag.
*/
@Test
public void testLaunchEmbeddedActivitiesWithoutShowWhenLocked() {
assumeTrue(supportsLockScreen());
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
// Initialize test environment by launching Activity A and B side-by-side.
initializeSplitActivities(false /* verifyEmbeddedTask */, false /* showWhenLocked */);
lockScreenSession.sleepDevice();
lockScreenSession.wakeUpDevice();
waitAndAssertActivityState(mActivityA, STATE_STOPPED,"Activity A must be stopped");
waitAndAssertActivityState(mActivityB, STATE_STOPPED,"Activity B must be stopped");
}
/**
* Verifies the show-when-locked behavior while launch embedded activities. The embedded
* activities should be shown on top of the lock screen since they have the showWhenLocked flag.
* Don't show the embedded activities even if one of Activity has showWhenLocked flag.
*/
@Test
public void testLaunchEmbeddedActivitiesWithShowWhenLocked() {
assumeTrue(supportsLockScreen());
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
// Initialize test environment by launching Activity A and B side-by-side.
mOwnerActivity.setShowWhenLocked(true);
initializeSplitActivities(false /* verifyEmbeddedTask */, true /* showWhenLocked */);
lockScreenSession.sleepDevice();
lockScreenSession.wakeUpDevice();
waitAndAssertResumedActivity(mActivityA, "Activity A must be resumed.");
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
// Launch Activity C without show-when-lock and verifies that both activities are stopped.
mOwnerActivity.startActivity(mIntent);
waitAndAssertActivityState(mActivityA, STATE_STOPPED, "Activity A must be stopped");
waitAndAssertActivityState(mActivityC, STATE_STOPPED, "Activity C must be stopped");
}
/**
* Verifies an Activity below adjacent translucent TaskFragments is visible.
*/
@Test
public void testTranslucentAdjacentTaskFragment() {
// Create ActivityB on top of ActivityA
Activity activityB = startActivity(ActivityB.class);
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STOPPED,
"Activity A is occluded by Activity B, so it must be stopped.");
// Create two adjacent TaskFragments, making ActivityB and TranslucentActivity
// displayed side-by-side (ActivityB|TranslucentActivity).
mOwnerActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
.splitVertically(mPrimaryBounds, mSideBounds);
final TaskFragmentCreationParams primaryParams = generatePrimaryTaskFragParams();
final TaskFragmentCreationParams secondaryParams = generateSideTaskFragParams();
IBinder primaryToken = primaryParams.getFragmentToken();
IBinder secondaryToken = secondaryParams.getFragmentToken();
final ComponentName translucentActivity = new ComponentName(mContext,
TranslucentActivity.class);
final Intent intent = new Intent().setComponent(translucentActivity);
WindowContainerTransaction wct = new WindowContainerTransaction()
.createTaskFragment(primaryParams)
.reparentActivityToTaskFragment(primaryToken, getActivityToken(activityB))
.createTaskFragment(secondaryParams)
.setAdjacentTaskFragments(primaryToken, secondaryToken, null /* params */)
.startActivityInTaskFragment(secondaryToken, mOwnerToken, intent,
null /* activityOptions */);
mTaskFragmentOrganizer.applyTransaction(wct);
waitAndAssertResumedActivity(translucentActivity, "TranslucentActivity must be resumed.");
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STARTED,
"Activity A is not fully occluded and must be visible and started");
}
private TaskFragmentCreationParams generatePrimaryTaskFragParams() {
return mTaskFragmentOrganizer.generateTaskFragParams(mOwnerToken, mPrimaryBounds,
WINDOWING_MODE_MULTI_WINDOW);
}
private TaskFragmentCreationParams generateSideTaskFragParams() {
return mTaskFragmentOrganizer.generateTaskFragParams(mOwnerToken, mSideBounds,
WINDOWING_MODE_MULTI_WINDOW);
}
private static class TaskFragmentRecord {
private final IBinder mTaskFragToken;
private final Rect mBounds = new Rect();
private final WindowContainerToken mContainerToken;
private TaskFragmentRecord(TaskFragmentInfo info) {
mTaskFragToken = info.getFragmentToken();
mBounds.set(info.getConfiguration().windowConfiguration.getBounds());
mContainerToken = info.getToken();
}
private IBinder getTaskFragToken() {
return mTaskFragToken;
}
private Rect getBounds() {
return mBounds;
}
private WindowContainerToken getToken() {
return mContainerToken;
}
}
public static class ActivityA extends SplitTestActivity {}
public static class ActivityB extends SplitTestActivity {}
public static class ActivityC extends SplitTestActivity {}
public static class TranslucentActivity extends SplitTestActivity {}
public static class SplitTestActivity extends FocusableActivity {
public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (getIntent().getBooleanExtra(EXTRA_SHOW_WHEN_LOCKED, false)) {
setShowWhenLocked(true);
}
}
}
}