Merge "Revert "Allow activity in ActivityEmbedding split to get Task windowing mode"" into tm-dev

This commit is contained in:
Sam Dubey
2022-04-29 02:44:43 +00:00
committed by Android (Google) Code Review
6 changed files with 29 additions and 196 deletions

View File

@@ -16,6 +16,7 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.app.Activity;
@@ -48,8 +49,7 @@ import java.util.concurrent.Executor;
class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
/** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */
@VisibleForTesting
final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
/**
* Mapping from the client assigned unique token to the TaskFragment parent
@@ -120,29 +120,25 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
* @param secondaryFragmentBounds the initial bounds for the secondary TaskFragment
* @param activityIntent Intent to start the secondary Activity with.
* @param activityOptions ActivityOptions to start the secondary Activity with.
* @param windowingMode the windowing mode to set for the TaskFragments.
*/
void startActivityToSide(@NonNull WindowContainerTransaction wct,
@NonNull IBinder launchingFragmentToken, @NonNull Rect launchingFragmentBounds,
@NonNull Activity launchingActivity, @NonNull IBinder secondaryFragmentToken,
@NonNull Rect secondaryFragmentBounds, @NonNull Intent activityIntent,
@Nullable Bundle activityOptions, @NonNull SplitRule rule,
@WindowingMode int windowingMode) {
@Nullable Bundle activityOptions, @NonNull SplitRule rule) {
final IBinder ownerToken = launchingActivity.getActivityToken();
// Create or resize the launching TaskFragment.
if (mFragmentInfos.containsKey(launchingFragmentToken)) {
resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds);
wct.setWindowingMode(mFragmentInfos.get(launchingFragmentToken).getToken(),
windowingMode);
} else {
createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken,
launchingFragmentBounds, windowingMode, launchingActivity);
launchingFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, launchingActivity);
}
// Create a TaskFragment for the secondary activity.
createTaskFragmentAndStartActivity(wct, secondaryFragmentToken, ownerToken,
secondaryFragmentBounds, windowingMode, activityIntent,
secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent,
activityOptions);
// Set adjacent to each other so that the containers below will be invisible.
@@ -157,7 +153,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
resizeTaskFragment(wct, fragmentToken, new Rect());
setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */);
setWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED);
}
/**
@@ -260,15 +255,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds);
}
private void setWindowingMode(WindowContainerTransaction wct, IBinder fragmentToken,
@WindowingMode int windowingMode) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
}
wct.setWindowingMode(mFragmentInfos.get(fragmentToken).getToken(), windowingMode);
}
void deleteTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(

View File

@@ -257,9 +257,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (taskContainer == null) {
return;
}
final boolean wasInPip = taskContainer.isInPictureInPicture();
final boolean wasInPip = isInPictureInPicture(taskContainer.getConfiguration());
final boolean isInPIp = isInPictureInPicture(config);
taskContainer.setWindowingMode(config.windowConfiguration.getWindowingMode());
taskContainer.setConfiguration(config);
// We need to check the animation override when enter/exit PIP or has bounds changed.
boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
@@ -278,9 +278,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* bounds is large enough for at least one split rule.
*/
private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
if (!taskContainer.isTaskBoundsInitialized()
|| !taskContainer.isWindowingModeInitialized()) {
// We don't know about the Task bounds/windowingMode yet.
if (!taskContainer.isTaskBoundsInitialized()) {
// We don't know about the Task bounds yet.
return;
}
@@ -294,7 +293,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
private boolean supportSplit(@NonNull TaskContainer taskContainer) {
// No split inside PIP.
if (taskContainer.isInPictureInPicture()) {
if (isInPictureInPicture(taskContainer.getConfiguration())) {
return false;
}
// Check if the parent container bounds can support any split rule.
@@ -462,12 +461,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (!taskContainer.setTaskBounds(taskBounds)) {
Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
}
updateAnimationOverride(taskContainer);
}
if (!taskContainer.isWindowingModeInitialized()) {
taskContainer.setWindowingMode(activityInTask.getResources().getConfiguration()
.windowConfiguration.getWindowingMode());
}
updateAnimationOverride(taskContainer);
return container;
}

View File

@@ -16,11 +16,10 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import android.app.Activity;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
@@ -112,16 +111,13 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
primaryActivity, primaryRectBounds, null);
// Create new empty task fragment
final int taskId = primaryContainer.getTaskId();
final TaskFragmentContainer secondaryContainer = mController.newContainer(
null /* activity */, primaryActivity, taskId);
null /* activity */, primaryActivity, primaryContainer.getTaskId());
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
rule, isLtr(primaryActivity, rule));
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(secondaryRectBounds);
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
primaryActivity.getActivityToken(), secondaryRectBounds,
windowingMode);
WINDOWING_MODE_MULTI_WINDOW);
secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
// Set adjacent to each other so that the containers below will be invisible.
@@ -177,7 +173,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final WindowContainerTransaction wct = new WindowContainerTransaction();
createTaskFragment(wct, newContainer.getTaskFragmentToken(),
launchingActivity.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
launchingActivity.getActivityToken(), new Rect(), WINDOWING_MODE_MULTI_WINDOW);
applyTransaction(wct);
return newContainer;
@@ -193,17 +189,15 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
@NonNull Rect bounds, @Nullable TaskFragmentContainer containerToAvoid) {
TaskFragmentContainer container = mController.getContainerWithActivity(
activity.getActivityToken());
final int taskId = container != null ? container.getTaskId() : activity.getTaskId();
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(bounds);
if (container == null || container == containerToAvoid) {
container = mController.newContainer(activity, taskId);
container = mController.newContainer(activity, activity.getTaskId());
final TaskFragmentCreationParams fragmentOptions =
createFragmentOptions(
container.getTaskFragmentToken(),
activity.getActivityToken(),
bounds,
windowingMode);
WINDOWING_MODE_MULTI_WINDOW);
wct.createTaskFragment(fragmentOptions);
wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
@@ -212,7 +206,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
container.setLastRequestedBounds(bounds);
} else {
resizeTaskFragmentIfRegistered(wct, container, bounds);
updateTaskFragmentWindowingModeIfRegistered(wct, container, windowingMode);
}
return container;
@@ -244,17 +237,14 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
launchingActivity.getTaskId());
}
final int taskId = primaryContainer.getTaskId();
TaskFragmentContainer secondaryContainer = mController.newContainer(null /* activity */,
launchingActivity, taskId);
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(primaryRectBounds);
launchingActivity, primaryContainer.getTaskId());
final WindowContainerTransaction wct = new WindowContainerTransaction();
mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
rule);
startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
activityIntent, activityOptions, rule, windowingMode);
activityIntent, activityOptions, rule);
if (isPlaceholder) {
// When placeholder is launched in split, we should keep the focus on the primary.
wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
@@ -302,12 +292,6 @@ 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 int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment(
primaryRectBounds);
updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode);
updateTaskFragmentWindowingModeIfRegistered(wct, secondaryContainer, windowingMode);
}
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@@ -339,15 +323,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
resizeTaskFragment(wct, container.getTaskFragmentToken(), bounds);
}
private void updateTaskFragmentWindowingModeIfRegistered(
@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container,
@WindowingMode int windowingMode) {
if (container.getInfo() != null) {
wct.setWindowingMode(container.getInfo().getToken(), windowingMode);
}
}
@Override
void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
@Nullable Rect bounds) {

View File

@@ -16,14 +16,9 @@
package androidx.window.extensions.embedding;
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.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArraySet;
@@ -42,9 +37,9 @@ class TaskContainer {
/** Available window bounds of this Task. */
private final Rect mTaskBounds = new Rect();
/** Windowing mode of this Task. */
@WindowingMode
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
/** Configuration of the Task. */
@Nullable
private Configuration mConfiguration;
/** Active TaskFragments in this Task. */
final List<TaskFragmentContainer> mContainers = new ArrayList<>();
@@ -86,42 +81,13 @@ class TaskContainer {
return !mTaskBounds.isEmpty();
}
void setWindowingMode(int windowingMode) {
mWindowingMode = windowingMode;
@Nullable
Configuration getConfiguration() {
return mConfiguration;
}
/** Whether the Task windowing mode has been initialized. */
boolean isWindowingModeInitialized() {
return mWindowingMode != WINDOWING_MODE_UNDEFINED;
}
/**
* Returns the windowing mode for the TaskFragments below this Task, which should be split with
* other TaskFragments.
*
* @param taskFragmentBounds Requested bounds for the TaskFragment. It will be empty when
* the pair of TaskFragments are stacked due to the limited space.
*/
@WindowingMode
int getWindowingModeForSplitTaskFragment(@Nullable Rect taskFragmentBounds) {
// Only set to multi-windowing mode if the pair are showing side-by-side. Otherwise, it
// will be set to UNDEFINED which will then inherit the Task windowing mode.
if (taskFragmentBounds == null || taskFragmentBounds.isEmpty()) {
return WINDOWING_MODE_UNDEFINED;
}
// We use WINDOWING_MODE_MULTI_WINDOW when the Task is fullscreen.
// However, when the Task is in other multi windowing mode, such as Freeform, we need to
// have the activity windowing mode to match the Task, otherwise things like
// DecorCaptionView won't work correctly. As a result, have the TaskFragment to be in the
// Task windowing mode if the Task is in multi window.
// TODO we won't need this anymore after we migrate Freeform caption to WM Shell.
return WindowConfiguration.inMultiWindowMode(mWindowingMode)
? mWindowingMode
: WINDOWING_MODE_MULTI_WINDOW;
}
boolean isInPictureInPicture() {
return mWindowingMode == WINDOWING_MODE_PINNED;
void setConfiguration(@Nullable Configuration configuration) {
mConfiguration = configuration;
}
/** Whether there is any {@link TaskFragmentContainer} below this Task. */

View File

@@ -16,23 +16,15 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.content.res.Configuration;
import android.graphics.Point;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -43,8 +35,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
/**
* Test class for {@link JetpackTaskFragmentOrganizer}.
*
@@ -57,8 +47,6 @@ import java.util.ArrayList;
public class JetpackTaskFragmentOrganizerTest {
private static final int TASK_ID = 10;
@Mock
private WindowContainerTransaction mTransaction;
@Mock
private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
private JetpackTaskFragmentOrganizer mOrganizer;
@@ -103,24 +91,4 @@ public class JetpackTaskFragmentOrganizerTest {
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
}
@Test
public void testExpandTaskFragment() {
final TaskFragmentContainer container = new TaskFragmentContainer(null, TASK_ID);
final TaskFragmentInfo info = createMockInfo(container);
mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
container.setInfo(info);
mOrganizer.expandTaskFragment(mTransaction, container.getTaskFragmentToken());
verify(mTransaction).setWindowingMode(container.getInfo().getToken(),
WINDOWING_MODE_UNDEFINED);
}
private TaskFragmentInfo createMockInfo(TaskFragmentContainer container) {
return new TaskFragmentInfo(container.getTaskFragmentToken(),
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
false /* isVisible */, new ArrayList<>(), new Point(),
false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */);
}
}

View File

@@ -16,13 +16,6 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -70,56 +63,6 @@ public class TaskContainerTest {
assertFalse(taskContainer.setTaskBounds(TASK_BOUNDS));
}
@Test
public void testIsWindowingModeInitialized() {
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
assertFalse(taskContainer.isWindowingModeInitialized());
taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertTrue(taskContainer.isWindowingModeInitialized());
}
@Test
public void testGetWindowingModeForSplitTaskFragment() {
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
final Rect splitBounds = new Rect(0, 0, 500, 1000);
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
taskContainer.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(WINDOWING_MODE_FREEFORM,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
// Empty bounds means the split pair are stacked, so it should be UNDEFINED which will then
// inherit the Task windowing mode
assertEquals(WINDOWING_MODE_UNDEFINED,
taskContainer.getWindowingModeForSplitTaskFragment(new Rect()));
}
@Test
public void testIsInPictureInPicture() {
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
assertFalse(taskContainer.isInPictureInPicture());
taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertFalse(taskContainer.isInPictureInPicture());
taskContainer.setWindowingMode(WINDOWING_MODE_PINNED);
assertTrue(taskContainer.isInPictureInPicture());
}
@Test
public void testIsEmpty() {
final TaskContainer taskContainer = new TaskContainer(TASK_ID);