Merge "Reducing number of configuration changes during PiP transition."

This commit is contained in:
Winson Chung
2017-02-16 16:39:57 +00:00
committed by Android (Google) Code Review
6 changed files with 149 additions and 122 deletions

View File

@@ -22,7 +22,6 @@ import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.AppOpsManager.MODE_ALLOWED;
@@ -47,7 +46,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
@@ -85,7 +83,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -290,8 +287,8 @@ final class ActivityRecord implements AppWindowContainerListener {
/**
* Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
*/
private final Configuration mTmpGlobalConfig = new Configuration();
private final Configuration mTmpTaskConfig = new Configuration();
private final Configuration mTmpConfig1 = new Configuration();
private final Configuration mTmpConfig2 = new Configuration();
private static String startingWindowStateToString(int state) {
switch (state) {
@@ -1975,13 +1972,13 @@ final class ActivityRecord implements AppWindowContainerListener {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Ensuring correct configuration: " + this);
// Short circuit: if the two configurations are equal (the common case), then there is
// nothing to do.
final Configuration newGlobalConfig = service.getGlobalConfiguration();
final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration();
if (mLastReportedConfiguration.equals(newGlobalConfig)
&& mLastReportedOverrideConfiguration.equals(newTaskMergedOverrideConfig)
&& !forceNewConfig) {
// Short circuit: if the two full configurations are equal (the common case), then there is
// nothing to do. We test the full configuration instead of the global and merged override
// configurations because there are cases (like moving a task to the pinned stack) where
// the combine configurations are equal, but would otherwise differ in the override config
mTmpConfig1.setTo(mLastReportedConfiguration);
mTmpConfig1.updateFrom(mLastReportedOverrideConfiguration);
if (task.getConfiguration().equals(mTmpConfig1) && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration unchanged in " + this);
return true;
@@ -1997,14 +1994,16 @@ final class ActivityRecord implements AppWindowContainerListener {
// Okay we now are going to make this activity have the new config.
// But then we need to figure out how it needs to deal with that.
mTmpGlobalConfig.setTo(mLastReportedConfiguration);
mTmpTaskConfig.setTo(mLastReportedOverrideConfiguration);
final Configuration newGlobalConfig = service.getGlobalConfiguration();
final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration();
mTmpConfig1.setTo(mLastReportedConfiguration);
mTmpConfig2.setTo(mLastReportedOverrideConfiguration);
mLastReportedConfiguration.setTo(newGlobalConfig);
mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig);
int taskChanges = getTaskConfigurationChanges(this, newTaskMergedOverrideConfig,
mTmpTaskConfig);
final int changes = mTmpGlobalConfig.diff(newGlobalConfig) | taskChanges;
mTmpConfig2);
final int changes = mTmpConfig1.diff(newGlobalConfig) | taskChanges;
if (changes == 0 && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration no differences in " + this);

View File

@@ -35,7 +35,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
@@ -52,6 +51,7 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
import com.android.server.wm.AppWindowContainerController;
import com.android.server.wm.StackWindowController;
import com.android.server.wm.TaskWindowContainerController;
import com.android.server.wm.TaskWindowContainerListener;
@@ -278,7 +278,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
private final Rect mTmpStableBounds = new Rect();
private final Rect mTmpNonDecorBounds = new Rect();
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
// Last non-fullscreen bounds the task was launched in or resized to.
// The information is persisted and used to determine the appropriate stack to launch the
@@ -1838,66 +1837,38 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
return !mTmpConfig.equals(newConfig);
}
private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds,
boolean overrideWidth, boolean overrideHeight) {
mTmpRect2.set(inInsetBounds);
mService.mWindowManager.subtractNonDecorInsets(mTmpRect2);
int leftInset = mTmpRect2.left - inInsetBounds.left;
int topInset = mTmpRect2.top - inInsetBounds.top;
int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds,
boolean overrideWidth, boolean overrideHeight) {
mTmpRect2.set(inInsetBounds);
mService.mWindowManager.subtractStableInsets(mTmpRect2);
int leftInset = mTmpRect2.left - inInsetBounds.left;
int topInset = mTmpRect2.top - inInsetBounds.top;
int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right;
int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom;
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
/** Clears passed config and fills it with new override values. */
private void calculateOverrideConfig(Configuration config, Rect bounds, Rect insetBounds,
boolean overrideWidth, boolean overrideHeight) {
mTmpNonDecorBounds.set(bounds);
mTmpStableBounds.set(bounds);
final Configuration parentConfig = getParent().getConfiguration();
config.unset();
final Configuration parentConfig = getParent().getConfiguration();
final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
final boolean isFloatingTask = mStack != null && StackId.tasksAreFloating(mStack.mStackId);
if (isFloatingTask) {
// Floating tasks should not be resized to the screen's bounds.
config.screenWidthDp = (int) (mTmpStableBounds.width() / density);
config.screenHeightDp = (int) (mTmpStableBounds.height() / density);
} else {
// For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
// i.e. the screen area without the system bars.
// Additionally task dimensions should not be bigger than its parents dimensions.
subtractNonDecorInsets(mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds,
overrideWidth, overrideHeight);
subtractStableInsets(mTmpStableBounds, insetBounds != null ? insetBounds : bounds,
overrideWidth, overrideHeight);
config.screenWidthDp = Math.min(
(int) (mTmpStableBounds.width() / density), parentConfig.screenWidthDp);
config.screenHeightDp = Math.min(
(int) (mTmpStableBounds.height() / density), parentConfig.screenHeightDp);
}
// TODO: Orientation?
config.orientation = (config.screenWidthDp <= config.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
if (mStack != null) {
final StackWindowController stackController = mStack.getWindowContainerController();
stackController.adjustConfigurationForBounds(bounds, insetBounds,
mTmpNonDecorBounds, mTmpStableBounds, overrideWidth, overrideHeight, density,
config, parentConfig);
} else {
// No stack, give some default values
config.smallestScreenWidthDp =
mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
config.screenWidthDp = config.screenHeightDp = config.smallestScreenWidthDp;
Slog.wtf(TAG, "Expected stack when caclulating override config");
}
// For calculating screen layout, we need to use the non-decor inset screen area for the
// calculation for compatibility reasons, i.e. screen area without system bars that could
// never go away in Honeycomb.
final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
// We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start override
// calculation with partial default.
final int sl = Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_XLARGE;
@@ -1905,8 +1876,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
config.smallestScreenWidthDp = mService.mWindowManager.getSmallestWidthForTaskBounds(
insetBounds != null ? insetBounds : bounds);
}
/**

View File

@@ -152,11 +152,6 @@ public class DockedStackDividerController implements DimLayerUser {
int getSmallestWidthDpForBounds(Rect bounds) {
final DisplayInfo di = mDisplayContent.getDisplayInfo();
// If the bounds are fullscreen, return the value of the fullscreen configuration
if (bounds == null || (bounds.left == 0 && bounds.top == 0
&& bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
return mDisplayContent.getConfiguration().smallestScreenWidthDp;
}
final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
int minWidth = Integer.MAX_VALUE;
@@ -185,7 +180,7 @@ public class DockedStackDividerController implements DimLayerUser {
mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
mTmpRect3);
mService.subtractInsets(mTmpRect2, mTmpRect3, mTmpRect);
mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
minWidth = Math.min(mTmpRect.width(), minWidth);
}
return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);

View File

@@ -16,6 +16,9 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import android.app.ActivityManager.StackId;
import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -24,6 +27,8 @@ import android.os.Looper;
import android.os.Message;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayInfo;
import com.android.server.UiThread;
import com.android.internal.annotations.VisibleForTesting;
@@ -48,6 +53,12 @@ public class StackWindowController
private final H mHandler;
// Temp bounds only used in adjustConfigurationForBounds()
private final Rect mTmpRect = new Rect();
private final Rect mTmpStableInsets = new Rect();
private final Rect mTmpNonDecorInsets = new Rect();
private final Rect mTmpDisplayBounds = new Rect();
public StackWindowController(int stackId, StackWindowListener listener,
int displayId, boolean onTop, Rect outBounds) {
this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
@@ -289,6 +300,107 @@ public class StackWindowController
}
}
/**
* Adjusts the screen size in dp's for the {@param config} for the given params.
*/
public void adjustConfigurationForBounds(Rect bounds, Rect insetBounds,
Rect nonDecorBounds, Rect stableBounds, boolean overrideWidth,
boolean overrideHeight, float density, Configuration config,
Configuration parentConfig) {
synchronized (mWindowMap) {
final TaskStack stack = mContainer;
final DisplayContent displayContent = stack.getDisplayContent();
final DisplayInfo di = displayContent.getDisplayInfo();
// Get the insets and display bounds
mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
mTmpStableInsets);
mService.mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
mTmpNonDecorInsets);
mTmpDisplayBounds.set(0, 0, di.logicalWidth, di.logicalHeight);
int width;
int height;
if (StackId.tasksAreFloating(mStackId)) {
// Floating tasks should not be resized to the screen's bounds.
if (bounds.width() == mTmpDisplayBounds.width() &&
bounds.height() == mTmpDisplayBounds.height()) {
// If the bounds we are animating is the same as the fullscreen stack
// dimensions, then apply the same inset calculations that we normally do for
// the fullscreen stack, without intersecting it with the display bounds
stableBounds.inset(mTmpStableInsets);
nonDecorBounds.inset(mTmpNonDecorInsets);
}
width = (int) (stableBounds.width() / density);
height = (int) (stableBounds.height() / density);
} else {
// For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
// area, i.e. the screen area without the system bars.
// Additionally task dimensions should not be bigger than its parents dimensions.
// The non decor inset are areas that could never be removed in Honeycomb. See
// {@link WindowManagerPolicy#getNonDecorInsetsLw}.
intersectDisplayBoundsExcludeInsets(nonDecorBounds,
insetBounds != null ? insetBounds : bounds, mTmpNonDecorInsets,
mTmpDisplayBounds, overrideWidth, overrideHeight);
intersectDisplayBoundsExcludeInsets(stableBounds,
insetBounds != null ? insetBounds : bounds, mTmpStableInsets,
mTmpDisplayBounds, overrideWidth, overrideHeight);
width = Math.min((int) (stableBounds.width() / density),
parentConfig.screenWidthDp);
height = Math.min((int) (stableBounds.height() / density),
parentConfig.screenHeightDp);
}
config.screenWidthDp = width;
config.screenHeightDp = height;
config.smallestScreenWidthDp = getSmallestWidthForTaskBounds(
insetBounds != null ? insetBounds : bounds, density);
}
}
/**
* Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
* inset areas.
*
* @param inOutBounds The inOutBounds to subtract the stable inset areas from.
*/
private void intersectDisplayBoundsExcludeInsets(Rect inOutBounds, Rect inInsetBounds,
Rect stableInsets, Rect displayBounds, boolean overrideWidth, boolean overrideHeight) {
mTmpRect.set(inInsetBounds);
mService.intersectDisplayInsetBounds(displayBounds, stableInsets, mTmpRect);
int leftInset = mTmpRect.left - inInsetBounds.left;
int topInset = mTmpRect.top - inInsetBounds.top;
int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect.right;
int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect.bottom;
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
/**
* Calculates the smallest width for a task given the {@param bounds}.
*
* @return the smallest width to be used in the Configuration, in dips
*/
private int getSmallestWidthForTaskBounds(Rect bounds, float density) {
final DisplayContent displayContent = mContainer.getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (bounds == null || (bounds.width() == displayInfo.logicalWidth &&
bounds.height() == displayInfo.logicalHeight)) {
// If the bounds are fullscreen, return the value of the fullscreen configuration
return displayContent.getConfiguration().smallestScreenWidthDp;
} else if (StackId.tasksAreFloating(mStackId)) {
// For floating tasks, calculate the smallest width from the bounds of the task
return (int) (Math.min(bounds.width(), bounds.height()) / density);
} else {
// Iterating across all screen orientations, and return the minimum of the task
// width taking into account that the bounds might change because the snap algorithm
// snaps to a different value
return displayContent.getDockedDividerController()
.getSmallestWidthDpForBounds(bounds);
}
}
void requestResize(Rect bounds) {
mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
}

View File

@@ -1476,7 +1476,10 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
@Override
public void getFullScreenBounds(Rect bounds) {
getDisplayContent().getContentRect(bounds);
// This is currently only used for the pinned stack animation when leaving PiP
// (see {@link BoundsAnimationController}), and in that case we need to animate this back
// to the full bounds to match the fullscreen stack
getDisplayContent().getLogicalDisplayRect(bounds);
}
public boolean hasMovementAnimations() {

View File

@@ -7544,63 +7544,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
private void getNonDecorInsetsLocked(Rect outInsets) {
final DisplayInfo di = getDefaultDisplayInfoLocked();
mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
}
/**
* Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
* inset areas.
*
* @param inOutBounds The inOutBounds to subtract the stable inset areas from.
*/
public void subtractStableInsets(Rect inOutBounds) {
synchronized (mWindowMap) {
getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect2);
final DisplayInfo di = getDefaultDisplayInfoLocked();
mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
subtractInsets(mTmpRect, mTmpRect2, inOutBounds);
}
}
/**
* Intersects the specified {@code inOutBounds} with the display frame that excludes
* areas that could never be removed in Honeycomb. See
* {@link WindowManagerPolicy#getNonDecorInsetsLw}.
*
* @param inOutBounds The inOutBounds to subtract the inset areas from.
*/
public void subtractNonDecorInsets(Rect inOutBounds) {
synchronized (mWindowMap) {
getNonDecorInsetsLocked(mTmpRect2);
final DisplayInfo di = getDefaultDisplayInfoLocked();
mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
subtractInsets(mTmpRect, mTmpRect2, inOutBounds);
}
}
void subtractInsets(Rect display, Rect insets, Rect inOutBounds) {
void intersectDisplayInsetBounds(Rect display, Rect insets, Rect inOutBounds) {
mTmpRect3.set(display);
mTmpRect3.inset(insets);
inOutBounds.intersect(mTmpRect3);
}
/**
* Calculates the smallest width for a task given the {@param bounds}. It does that by iterating
* across all screen orientations, and returns the minimum of the task width taking into account
* that the bounds might change because the snap algorithm snaps to a different value.
*
* @return the smallest width to be used in the Configuration, in dips
*/
public int getSmallestWidthForTaskBounds(Rect bounds) {
synchronized (mWindowMap) {
// TODO(multi-display): Use correct display content here
return getDefaultDisplayContentLocked().getDockedDividerController()
.getSmallestWidthDpForBounds(bounds);
}
}
MousePositionTracker mMousePositionTracker = new MousePositionTracker();
private static class MousePositionTracker implements PointerEventListener {