Merge "Introducing split-screen windowing modes."

This commit is contained in:
TreeHugger Robot
2017-09-08 14:07:43 +00:00
committed by Android (Google) Code Review
11 changed files with 143 additions and 92 deletions

View File

@@ -20,10 +20,11 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_DOCKED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.Manifest;
@@ -738,28 +739,6 @@ public class ActivityManager {
|| stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
}
/**
* Returns true if Stack size is affected by the docked stack changing size.
* @hide
*/
// TODO: Figure-out a way to remove.
public static boolean isResizeableByDockedStack(int stackId) {
return isStaticStack(stackId) && stackId != DOCKED_STACK_ID
&& stackId != PINNED_STACK_ID && stackId != ASSISTANT_STACK_ID;
}
/**
* Returns true if the size of tasks in the input stack are affected by the docked stack
* changing size.
* @hide
*/
// TODO: What is the difference between this method and the one above??
public static boolean isTaskResizeableByDockedStack(int stackId) {
return isStaticStack(stackId) && stackId != FREEFORM_WORKSPACE_STACK_ID
&& stackId != DOCKED_STACK_ID && stackId != PINNED_STACK_ID
&& stackId != ASSISTANT_STACK_ID;
}
/**
* Returns true if the input stack is affected by drag resizing.
* @hide
@@ -879,12 +858,15 @@ public class ActivityManager {
/** Returns the windowing mode that should be used for this input stack id.
* @hide */
// TODO: To be removed once we are not using stack id for stuff...
public static int getWindowingModeForStackId(int stackId) {
public static int getWindowingModeForStackId(int stackId, boolean inSplitScreenMode) {
final int windowingMode;
switch (stackId) {
case FULLSCREEN_WORKSPACE_STACK_ID:
case HOME_STACK_ID:
case RECENTS_STACK_ID:
windowingMode = inSplitScreenMode
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_FULLSCREEN;
break;
case ASSISTANT_STACK_ID:
windowingMode = WINDOWING_MODE_FULLSCREEN;
break;
@@ -892,7 +874,7 @@ public class ActivityManager {
windowingMode = WINDOWING_MODE_PINNED;
break;
case DOCKED_STACK_ID:
windowingMode = WINDOWING_MODE_DOCKED;
windowingMode = WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
break;
case FREEFORM_WORKSPACE_STACK_ID:
windowingMode = WINDOWING_MODE_FREEFORM;

View File

@@ -57,19 +57,26 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** Always on-top (always visible). of other siblings in its parent container.
* @hide */
public static final int WINDOWING_MODE_PINNED = 2;
/** Occupies a dedicated region of the screen or its parent container.
/** The primary container driving the screen to be in split-screen mode.
* @hide */
public static final int WINDOWING_MODE_DOCKED = 3;
public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
/**
* The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
* split-screen mode.
* @hide
*/
public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
/** Can be freely resized within its parent container.
* @hide */
public static final int WINDOWING_MODE_FREEFORM = 4;
public static final int WINDOWING_MODE_FREEFORM = 5;
/** @hide */
@IntDef({
WINDOWING_MODE_UNDEFINED,
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_PINNED,
WINDOWING_MODE_DOCKED,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
WINDOWING_MODE_FREEFORM,
})
public @interface WindowingMode {}
@@ -469,12 +476,26 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return mWindowingMode == WINDOWING_MODE_PINNED;
}
/**
* Returns true if this container can be put in either
* {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
* {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
if (mActivityType == ACTIVITY_TYPE_ASSISTANT) {
return false;
}
return mWindowingMode != WINDOWING_MODE_FREEFORM && mWindowingMode != WINDOWING_MODE_PINNED;
}
private static String windowingModeToString(@WindowingMode int windowingMode) {
switch (windowingMode) {
case WINDOWING_MODE_UNDEFINED: return "undefined";
case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
case WINDOWING_MODE_PINNED: return "pinned";
case WINDOWING_MODE_DOCKED: return "docked";
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
case WINDOWING_MODE_FREEFORM: return "freeform";
}
return String.valueOf(windowingMode);

View File

@@ -6,10 +6,12 @@ import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static android.app.WindowConfiguration.WINDOWING_MODE_DOCKED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
@@ -111,31 +113,34 @@ class ActivityMetricsLogger {
}
mLastLogTimeSecs = now;
ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
if (stack != null && stack.shouldBeVisible(null) != STACK_INVISIBLE) {
mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
mWindowState = WINDOW_STATE_INVALID;
ActivityStack stack = mSupervisor.getFocusedStack();
if (stack.isActivityTypeAssistant()) {
mWindowState = WINDOW_STATE_ASSISTANT;
return;
}
mWindowState = WINDOW_STATE_INVALID;
stack = mSupervisor.getFocusedStack();
int windowingMode = stack.getWindowingMode();
if (windowingMode == WINDOWING_MODE_PINNED) {
stack = mSupervisor.findStackBehind(stack);
windowingMode = stack.getWindowingMode();
}
if (StackId.isHomeOrRecentsStack(stack.mStackId)
|| windowingMode == WINDOWING_MODE_FULLSCREEN) {
mWindowState = WINDOW_STATE_STANDARD;
} else if (windowingMode == WINDOWING_MODE_DOCKED) {
Slog.wtf(TAG, "Docked stack shouldn't be the focused stack, because it reported not"
+ " being visible.");
mWindowState = WINDOW_STATE_INVALID;
} else if (windowingMode == WINDOWING_MODE_FREEFORM) {
mWindowState = WINDOW_STATE_FREEFORM;
} else if (stack.mStackId == ASSISTANT_STACK_ID) {
mWindowState = WINDOW_STATE_ASSISTANT;
} else if (StackId.isStaticStack(stack.mStackId)) {
throw new IllegalStateException("Unknown stack=" + stack);
switch (windowingMode) {
case WINDOWING_MODE_FULLSCREEN:
mWindowState = WINDOW_STATE_STANDARD;
break;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
break;
case WINDOW_STATE_FREEFORM:
mWindowState = WINDOW_STATE_FREEFORM;
break;
default:
if (windowingMode != WINDOWING_MODE_UNDEFINED) {
throw new IllegalStateException("Unknown windowing mode for stack=" + stack
+ " windowingMode=" + windowingMode);
}
}
}

View File

@@ -482,7 +482,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// TODO: Not needed once we are no longer using stack ids as the override config. can be passed
// in.
private void updateOverrideConfiguration() {
final int windowingMode = getWindowingModeForStackId(mStackId);
final int windowingMode = getWindowingModeForStackId(
mStackId, mStackSupervisor.getStack(DOCKED_STACK_ID) != null);
if (windowingMode != WINDOWING_MODE_UNDEFINED) {
setWindowingMode(windowingMode);
}

View File

@@ -36,6 +36,8 @@ import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCRE
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
@@ -2279,15 +2281,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return null;
}
/**
* Returns if a stack should be treated as if it's docked. Returns true if the stack is
* the docked stack itself, or if it's side-by-side to the docked stack.
*/
boolean isStackDockedInEffect(int stackId) {
return stackId == DOCKED_STACK_ID ||
(StackId.isResizeableByDockedStack(stackId) && getStack(DOCKED_STACK_ID) != null);
}
void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) {
if (stackId == DOCKED_STACK_ID) {
@@ -2301,9 +2294,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return;
}
final boolean splitScreenActive = getStack(DOCKED_STACK_ID) != null;
if (!allowResizeInDockedMode
&& !stack.getWindowConfiguration().tasksAreFloating()
&& getStack(DOCKED_STACK_ID) != null) {
&& !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) {
// If the docked stack exists, don't resize non-floating stacks independently of the
// size computed from the docked stack size (otherwise they will be out of sync)
return;
@@ -2312,6 +2305,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
mWindowManager.deferSurfaceLayout();
try {
if (stack.supportSplitScreenWindowingMode()) {
if (bounds == null && stack.inSplitScreenWindowingMode()) {
// null bounds = fullscreen windowing mode...at least for now.
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
} else if (splitScreenActive) {
// If we are in split-screen mode and this stack support split-screen, then
// it should be split-screen secondary mode. i.e. adjacent to the docked stack.
stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
}
}
stack.resize(bounds, tempTaskBounds, tempTaskInsetBounds);
if (!deferResume) {
stack.ensureVisibleActivitiesConfigurationLocked(
@@ -2323,14 +2326,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
void deferUpdateBounds(int stackId) {
private void deferUpdateBounds(int stackId) {
final ActivityStack stack = getStack(stackId);
if (stack != null) {
stack.deferUpdateBounds();
}
}
void continueUpdateBounds(int stackId) {
private void continueUpdateBounds(int stackId) {
final ActivityStack stack = getStack(stackId);
if (stack != null) {
stack.continueUpdateBounds();
@@ -2365,13 +2368,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// which is dismissing the docked stack, so resize all other stacks to
// fullscreen here already so we don't end up with resize trashing.
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
if (StackId.isResizeableByDockedStack(i)) {
ActivityStack otherStack = getStack(i);
if (otherStack != null) {
resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS,
true /* allowResizeInDockedMode */, DEFER_RESUME);
}
final ActivityStack otherStack = getStack(i);
if (otherStack == null) {
continue;
}
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS,
true /* allowResizeInDockedMode */, DEFER_RESUME);
}
// Also disable docked stack resizing since we have manually adjusted the
@@ -2485,18 +2490,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// screen controls and is also the same for all stacks.
final Rect otherTaskRect = new Rect();
for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
final ActivityStack current = getStack(i);
if (current != null && StackId.isResizeableByDockedStack(i)) {
current.getStackDockedModeBounds(
tempOtherTaskBounds /* currentTempTaskBounds */,
tempRect /* outStackBounds */,
otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */);
resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null,
!otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */, deferResume);
if (i == DOCKED_STACK_ID) {
continue;
}
final ActivityStack current = getStack(i);
if (current == null || !current.supportSplitScreenWindowingMode()) {
continue;
}
// Need to set windowing mode here before we try to get the dock bounds.
current.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
current.getStackDockedModeBounds(
tempOtherTaskBounds /* currentTempTaskBounds */,
tempRect /* outStackBounds */,
otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */);
resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null,
!otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds,
tempOtherTaskInsetBounds, preserveWindows,
true /* allowResizeInDockedMode */, deferResume);
}
}
if (!deferResume) {
@@ -4023,7 +4034,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final boolean isSecondaryDisplayPreferred =
(preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
|| StackId.isDynamicStack(preferredStackId);
if (((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
final ActivityStack actualStack = getStack(actualStackId);
final boolean inSplitScreenMode = actualStack != null
&& actualStack.inSplitScreenWindowingMode();
if (((!inSplitScreenMode && preferredStackId != DOCKED_STACK_ID)
&& !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
return;
}

View File

@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.activityTypeToString;
import android.app.WindowConfiguration;
@@ -145,6 +147,33 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
onOverrideConfigurationChanged(mTmpConfig);
}
/** Returns true if this container is currently in split-screen windowing mode. */
public boolean inSplitScreenWindowingMode() {
@WindowConfiguration.WindowingMode int windowingMode =
mFullConfiguration.windowConfiguration.getWindowingMode();
return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
/** Returns true if this container is currently in split-screen secondary windowing mode. */
public boolean inSplitScreenSecondaryWindowingMode() {
@WindowConfiguration.WindowingMode int windowingMode =
mFullConfiguration.windowConfiguration.getWindowingMode();
return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
/**
* Returns true if this container can be put in either
* {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
* {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
* its current state.
*/
public boolean supportSplitScreenWindowingMode() {
return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
}
/** Returns the activity type associated with the the configuration container. */
/*@WindowConfiguration.ActivityType*/
public int getActivityType() {

View File

@@ -421,9 +421,9 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
/** Return true if the current bound can get outputted to the rest of the system as-is. */
private boolean useCurrentBounds() {
final DisplayContent displayContent = mStack.getDisplayContent();
final DisplayContent displayContent = getDisplayContent();
return mFillsParent
|| !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
|| !inSplitScreenSecondaryWindowingMode()
|| displayContent == null
|| displayContent.getDockedStackIgnoringVisibility() != null;
}

View File

@@ -289,7 +289,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
/** Return true if the current bound can get outputted to the rest of the system as-is. */
private boolean useCurrentBounds() {
if (mFillsParent
|| !StackId.isResizeableByDockedStack(mStackId)
|| !inSplitScreenSecondaryWindowingMode()
|| mDisplayContent == null
|| mDisplayContent.getDockedStackLocked() != null) {
return true;
@@ -684,7 +684,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
Rect bounds = null;
final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
if (mStackId == DOCKED_STACK_ID
|| (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
|| (dockedStack != null && inSplitScreenSecondaryWindowingMode()
&& !dockedStack.fillsParent())) {
// The existence of a docked stack affects the size of other static stack created since
// the docked stack occupies a dedicated region on screen, but only if the dock stack is
@@ -756,8 +756,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return;
}
if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
|| mDisplayContent == null) {
if (!inSplitScreenWindowingMode() || mDisplayContent == null) {
outStackBounds.set(mBounds);
return;
}
@@ -1324,8 +1323,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return getDockSide(mBounds);
}
int getDockSide(Rect bounds) {
if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
private int getDockSide(Rect bounds) {
if (!inSplitScreenWindowingMode()) {
return DOCKED_INVALID;
}
if (mDisplayContent == null) {

View File

@@ -101,7 +101,7 @@ class WindowLayersController {
mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
w.mWinAnimator.mAnimLayer);
}
if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
if (w.getAppToken() != null && w.inSplitScreenSecondaryWindowingMode()) {
mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
w.mWinAnimator.mAnimLayer);
}

View File

@@ -54,7 +54,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
super.setUp();
final Configuration overrideConfig = new Configuration();
overrideConfig.windowConfiguration.setWindowingMode(
getWindowingModeForStackId(PINNED_STACK_ID));
getWindowingModeForStackId(PINNED_STACK_ID, false /* inSplitScreenMode */));
mPinnedStack = new StackWindowController(PINNED_STACK_ID, null,
mDisplayContent.getDisplayId(), true /* onTop */, new Rect(), sWm).mContainer;
mPinnedStack.onOverrideConfigurationChanged(overrideConfig);

View File

@@ -240,7 +240,7 @@ class WindowTestsBase {
StackWindowController createStackControllerOnStackOnDisplay(int stackId, DisplayContent dc) {
final Configuration overrideConfig = new Configuration();
overrideConfig.windowConfiguration.setWindowingMode(
getWindowingModeForStackId(stackId));
getWindowingModeForStackId(stackId, false /* inSplitScreenMode */));
final StackWindowController controller = new StackWindowController(stackId, null,
dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
controller.onOverrideConfigurationChanged(overrideConfig);