Merge "Handle case when snapshot dimensions don't match" into oc-dev
This commit is contained in:
@@ -4159,14 +4159,25 @@ public class Activity extends ContextThemeWrapper
|
||||
mTaskDescription.setPrimaryColor(colorPrimary);
|
||||
}
|
||||
}
|
||||
// For dev-preview only.
|
||||
if (mTaskDescription.getBackgroundColor() == 0) {
|
||||
int colorBackground = a.getColor(
|
||||
com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
|
||||
if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
|
||||
mTaskDescription.setBackgroundColor(colorBackground);
|
||||
}
|
||||
|
||||
int colorBackground = a.getColor(
|
||||
com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
|
||||
if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
|
||||
mTaskDescription.setBackgroundColor(colorBackground);
|
||||
}
|
||||
|
||||
final int statusBarColor = a.getColor(
|
||||
com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0);
|
||||
if (statusBarColor != 0) {
|
||||
mTaskDescription.setStatusBarColor(statusBarColor);
|
||||
}
|
||||
|
||||
final int navigationBarColor = a.getColor(
|
||||
com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0);
|
||||
if (navigationBarColor != 0) {
|
||||
mTaskDescription.setNavigationBarColor(navigationBarColor);
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
setTaskDescription(mTaskDescription);
|
||||
}
|
||||
|
||||
@@ -1145,6 +1145,8 @@ public class ActivityManager {
|
||||
private String mIconFilename;
|
||||
private int mColorPrimary;
|
||||
private int mColorBackground;
|
||||
private int mStatusBarColor;
|
||||
private int mNavigationBarColor;
|
||||
|
||||
/**
|
||||
* Creates the TaskDescription to the specified values.
|
||||
@@ -1155,7 +1157,7 @@ public class ActivityManager {
|
||||
* opaque.
|
||||
*/
|
||||
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
|
||||
this(label, icon, null, colorPrimary, 0);
|
||||
this(label, icon, null, colorPrimary, 0, 0, 0);
|
||||
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
|
||||
throw new RuntimeException("A TaskDescription's primary color should be opaque");
|
||||
}
|
||||
@@ -1168,7 +1170,7 @@ public class ActivityManager {
|
||||
* @param icon An icon that represents the current state of this activity.
|
||||
*/
|
||||
public TaskDescription(String label, Bitmap icon) {
|
||||
this(label, icon, null, 0, 0);
|
||||
this(label, icon, null, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1177,24 +1179,26 @@ public class ActivityManager {
|
||||
* @param label A label and description of the current state of this activity.
|
||||
*/
|
||||
public TaskDescription(String label) {
|
||||
this(label, null, null, 0, 0);
|
||||
this(label, null, null, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty TaskDescription.
|
||||
*/
|
||||
public TaskDescription() {
|
||||
this(null, null, null, 0, 0);
|
||||
this(null, null, null, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
|
||||
int colorBackground) {
|
||||
int colorBackground, int statusBarColor, int navigationBarColor) {
|
||||
mLabel = label;
|
||||
mIcon = icon;
|
||||
mIconFilename = iconFilename;
|
||||
mColorPrimary = colorPrimary;
|
||||
mColorBackground = colorBackground;
|
||||
mStatusBarColor = statusBarColor;
|
||||
mNavigationBarColor = navigationBarColor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1214,6 +1218,8 @@ public class ActivityManager {
|
||||
mIconFilename = other.mIconFilename;
|
||||
mColorPrimary = other.mColorPrimary;
|
||||
mColorBackground = other.mColorBackground;
|
||||
mStatusBarColor = other.mStatusBarColor;
|
||||
mNavigationBarColor = other.mNavigationBarColor;
|
||||
}
|
||||
|
||||
private TaskDescription(Parcel source) {
|
||||
@@ -1252,6 +1258,20 @@ public class ActivityManager {
|
||||
mColorBackground = backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void setStatusBarColor(int statusBarColor) {
|
||||
mStatusBarColor = statusBarColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void setNavigationBarColor(int navigationBarColor) {
|
||||
mNavigationBarColor = navigationBarColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon for this task description.
|
||||
* @hide
|
||||
@@ -1325,6 +1345,20 @@ public class ActivityManager {
|
||||
return mColorBackground;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int getStatusBarColor() {
|
||||
return mStatusBarColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int getNavigationBarColor() {
|
||||
return mNavigationBarColor;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void saveToXml(XmlSerializer out) throws IOException {
|
||||
if (mLabel != null) {
|
||||
@@ -1377,6 +1411,8 @@ public class ActivityManager {
|
||||
}
|
||||
dest.writeInt(mColorPrimary);
|
||||
dest.writeInt(mColorBackground);
|
||||
dest.writeInt(mStatusBarColor);
|
||||
dest.writeInt(mNavigationBarColor);
|
||||
if (mIconFilename == null) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
@@ -1390,6 +1426,8 @@ public class ActivityManager {
|
||||
mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
|
||||
mColorPrimary = source.readInt();
|
||||
mColorBackground = source.readInt();
|
||||
mStatusBarColor = source.readInt();
|
||||
mNavigationBarColor = source.readInt();
|
||||
mIconFilename = source.readInt() > 0 ? source.readString() : null;
|
||||
}
|
||||
|
||||
@@ -1407,7 +1445,9 @@ public class ActivityManager {
|
||||
public String toString() {
|
||||
return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
|
||||
" IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
|
||||
" colorBackground: " + mColorBackground;
|
||||
" colorBackground: " + mColorBackground +
|
||||
" statusBarColor: " + mColorBackground +
|
||||
" navigationBarColor: " + mNavigationBarColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
|
||||
private final Rect mOldStableInsets = new Rect();
|
||||
private final Rect mSystemInsets = new Rect();
|
||||
private final Rect mStableInsets = new Rect();
|
||||
private final Rect mTmpRect = new Rect();
|
||||
|
||||
public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
|
||||
Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
|
||||
@@ -370,12 +371,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
|
||||
DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
|
||||
mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
|
||||
final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
|
||||
final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom,
|
||||
systemInsets.bottom);
|
||||
final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
|
||||
systemInsets.right);
|
||||
final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
|
||||
systemInsets.left);
|
||||
if (mStatusBarColor != null) {
|
||||
mStatusBarColor.setBounds(0, 0, left + width, topInset);
|
||||
mStatusBarColor.draw(canvas);
|
||||
@@ -385,14 +380,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
|
||||
// don't want the navigation bar background be moving around when resizing in docked mode.
|
||||
// However, we need it for the transitions into/out of docked mode.
|
||||
if (mNavigationBarColor != null && fullscreen) {
|
||||
final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
|
||||
if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
|
||||
mNavigationBarColor.setBounds(width - size, 0, width, height);
|
||||
} else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) {
|
||||
mNavigationBarColor.setBounds(0, 0, size, height);
|
||||
} else {
|
||||
mNavigationBarColor.setBounds(0, height - size, width, height);
|
||||
}
|
||||
DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect);
|
||||
mNavigationBarColor.setBounds(mTmpRect);
|
||||
mNavigationBarColor.draw(canvas);
|
||||
}
|
||||
mSystemBarBackgroundNode.end(canvas);
|
||||
|
||||
@@ -119,6 +119,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
// The height of a window which has not in DIP.
|
||||
private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
|
||||
|
||||
public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
|
||||
new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
|
||||
Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
|
||||
Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
|
||||
com.android.internal.R.id.statusBarBackground,
|
||||
FLAG_FULLSCREEN);
|
||||
|
||||
public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
|
||||
new ColorViewAttributes(
|
||||
SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
|
||||
Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
|
||||
Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
|
||||
com.android.internal.R.id.navigationBarBackground,
|
||||
0 /* hideWindowFlag */);
|
||||
|
||||
// Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
|
||||
// size calculation takes the shadow size into account. We set the elevation currently
|
||||
// to max until the first layout command has been executed.
|
||||
@@ -162,18 +177,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
// View added at runtime to draw under the navigation bar area
|
||||
private View mNavigationGuard;
|
||||
|
||||
private final ColorViewState mStatusColorViewState = new ColorViewState(
|
||||
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
|
||||
Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
|
||||
Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
|
||||
com.android.internal.R.id.statusBarBackground,
|
||||
FLAG_FULLSCREEN);
|
||||
private final ColorViewState mNavigationColorViewState = new ColorViewState(
|
||||
SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
|
||||
Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
|
||||
Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
|
||||
com.android.internal.R.id.navigationBarBackground,
|
||||
0 /* hideWindowFlag */);
|
||||
private final ColorViewState mStatusColorViewState =
|
||||
new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
|
||||
private final ColorViewState mNavigationColorViewState =
|
||||
new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);
|
||||
|
||||
private final Interpolator mShowInterpolator;
|
||||
private final Interpolator mHideInterpolator;
|
||||
@@ -983,35 +990,50 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
return false;
|
||||
}
|
||||
|
||||
static int getColorViewTopInset(int stableTop, int systemTop) {
|
||||
public static int getColorViewTopInset(int stableTop, int systemTop) {
|
||||
return Math.min(stableTop, systemTop);
|
||||
}
|
||||
|
||||
static int getColorViewBottomInset(int stableBottom, int systemBottom) {
|
||||
public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
|
||||
return Math.min(stableBottom, systemBottom);
|
||||
}
|
||||
|
||||
static int getColorViewRightInset(int stableRight, int systemRight) {
|
||||
public static int getColorViewRightInset(int stableRight, int systemRight) {
|
||||
return Math.min(stableRight, systemRight);
|
||||
}
|
||||
|
||||
static int getColorViewLeftInset(int stableLeft, int systemLeft) {
|
||||
public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
|
||||
return Math.min(stableLeft, systemLeft);
|
||||
}
|
||||
|
||||
static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
|
||||
public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
|
||||
return bottomInset == 0 && rightInset > 0;
|
||||
}
|
||||
|
||||
static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
|
||||
public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
|
||||
return bottomInset == 0 && leftInset > 0;
|
||||
}
|
||||
|
||||
static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
|
||||
public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
|
||||
return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
|
||||
: isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
|
||||
}
|
||||
|
||||
public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
|
||||
Rect contentInsets, Rect outRect) {
|
||||
final int bottomInset = getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom);
|
||||
final int leftInset = getColorViewLeftInset(stableInsets.left, contentInsets.left);
|
||||
final int rightInset = getColorViewLeftInset(stableInsets.right, contentInsets.right);
|
||||
final int size = getNavBarSize(bottomInset, rightInset, leftInset);
|
||||
if (isNavBarToRightEdge(bottomInset, rightInset)) {
|
||||
outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
|
||||
} else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
|
||||
outRect.set(0, 0, size, canvasHeight);
|
||||
} else {
|
||||
outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
|
||||
}
|
||||
}
|
||||
|
||||
WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
|
||||
WindowManager.LayoutParams attrs = mWindow.getAttributes();
|
||||
int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
|
||||
@@ -1131,9 +1153,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
}
|
||||
|
||||
private int calculateStatusBarColor() {
|
||||
int flags = mWindow.getAttributes().flags;
|
||||
return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? mSemiTransparentStatusBarColor
|
||||
: (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? mWindow.mStatusBarColor
|
||||
return calculateStatusBarColor(mWindow.getAttributes().flags,
|
||||
mSemiTransparentStatusBarColor, mWindow.mStatusBarColor);
|
||||
}
|
||||
|
||||
public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor,
|
||||
int statusBarColor) {
|
||||
return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor
|
||||
: (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor
|
||||
: Color.BLACK;
|
||||
}
|
||||
|
||||
@@ -1160,13 +1187,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
|
||||
int size, boolean verticalBar, boolean seascape, int sideMargin,
|
||||
boolean animate, boolean force) {
|
||||
state.present = (sysUiVis & state.systemUiHideFlag) == 0
|
||||
&& (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
|
||||
&& ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|
||||
|| force);
|
||||
boolean show = state.present
|
||||
&& (color & Color.BLACK) != 0
|
||||
&& ((mWindow.getAttributes().flags & state.translucentFlag) == 0 || force);
|
||||
state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
|
||||
boolean show = state.attributes.isVisible(state.present, color,
|
||||
mWindow.getAttributes().flags, force);
|
||||
boolean showView = show && !isResizing() && size > 0;
|
||||
|
||||
boolean visibilityChanged = false;
|
||||
@@ -1175,15 +1198,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
|
||||
int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
|
||||
int resolvedGravity = verticalBar
|
||||
? (seascape ? state.seascapeGravity : state.horizontalGravity)
|
||||
: state.verticalGravity;
|
||||
? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
|
||||
: state.attributes.verticalGravity;
|
||||
|
||||
if (view == null) {
|
||||
if (showView) {
|
||||
state.view = view = new View(mContext);
|
||||
view.setBackgroundColor(color);
|
||||
view.setTransitionName(state.transitionName);
|
||||
view.setId(state.id);
|
||||
view.setTransitionName(state.attributes.transitionName);
|
||||
view.setId(state.attributes.id);
|
||||
visibilityChanged = true;
|
||||
view.setVisibility(INVISIBLE);
|
||||
state.targetVisibility = VISIBLE;
|
||||
@@ -2269,6 +2292,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
boolean visible;
|
||||
int color;
|
||||
|
||||
final ColorViewAttributes attributes;
|
||||
|
||||
ColorViewState(ColorViewAttributes attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ColorViewAttributes {
|
||||
|
||||
final int id;
|
||||
final int systemUiHideFlag;
|
||||
final int translucentFlag;
|
||||
@@ -2278,9 +2310,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
final String transitionName;
|
||||
final int hideWindowFlag;
|
||||
|
||||
ColorViewState(int systemUiHideFlag,
|
||||
int translucentFlag, int verticalGravity, int horizontalGravity,
|
||||
int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
|
||||
private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
|
||||
int horizontalGravity, int seascapeGravity, String transitionName, int id,
|
||||
int hideWindowFlag) {
|
||||
this.id = id;
|
||||
this.systemUiHideFlag = systemUiHideFlag;
|
||||
this.translucentFlag = translucentFlag;
|
||||
@@ -2290,6 +2322,24 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
this.transitionName = transitionName;
|
||||
this.hideWindowFlag = hideWindowFlag;
|
||||
}
|
||||
|
||||
public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
|
||||
return (sysUiVis & systemUiHideFlag) == 0
|
||||
&& (windowFlags & hideWindowFlag) == 0
|
||||
&& ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|
||||
|| force);
|
||||
}
|
||||
|
||||
public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
|
||||
return present
|
||||
&& (color & Color.BLACK) != 0
|
||||
&& ((windowFlags & translucentFlag) == 0 || force);
|
||||
}
|
||||
|
||||
public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
|
||||
final boolean present = isPresent(sysUiVis, windowFlags, force);
|
||||
return isVisible(present, color, windowFlags, force);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8566,6 +8566,11 @@
|
||||
<!-- @hide From Theme.colorBackground, used for the TaskDescription background
|
||||
color. -->
|
||||
<attr name="colorBackground" />
|
||||
<!-- @hide From Theme.statusBarColor, used for the TaskDescription status bar color. -->
|
||||
<attr name="statusBarColor"/>
|
||||
<!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
|
||||
color. -->
|
||||
<attr name="navigationBarColor"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="Shortcut">
|
||||
|
||||
@@ -355,9 +355,10 @@ public class SystemServicesProxy {
|
||||
rti.firstActiveTime = rti.lastActiveTime = i;
|
||||
if (i % 2 == 0) {
|
||||
rti.taskDescription = new ActivityManager.TaskDescription(description,
|
||||
Bitmap.createBitmap(mDummyIcon), null,
|
||||
0xFF000000 | (0xFFFFFF & new Random().nextInt()),
|
||||
0xFF000000 | (0xFFFFFF & new Random().nextInt()));
|
||||
Bitmap.createBitmap(mDummyIcon), null,
|
||||
0xFF000000 | (0xFFFFFF & new Random().nextInt()),
|
||||
0xFF000000 | (0xFFFFFF & new Random().nextInt()),
|
||||
0, 0);
|
||||
} else {
|
||||
rti.taskDescription = new ActivityManager.TaskDescription();
|
||||
}
|
||||
|
||||
@@ -1613,6 +1613,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
|
||||
String iconFilename = null;
|
||||
int colorPrimary = 0;
|
||||
int colorBackground = 0;
|
||||
int statusBarColor = 0;
|
||||
int navigationBarColor = 0;
|
||||
boolean topActivity = true;
|
||||
for (--activityNdx; activityNdx >= 0; --activityNdx) {
|
||||
final ActivityRecord r = mActivities.get(activityNdx);
|
||||
if (r.taskDescription != null) {
|
||||
@@ -1625,13 +1628,16 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
|
||||
if (colorPrimary == 0) {
|
||||
colorPrimary = r.taskDescription.getPrimaryColor();
|
||||
}
|
||||
if (colorBackground == 0) {
|
||||
if (topActivity) {
|
||||
colorBackground = r.taskDescription.getBackgroundColor();
|
||||
statusBarColor = r.taskDescription.getStatusBarColor();
|
||||
navigationBarColor = r.taskDescription.getNavigationBarColor();
|
||||
}
|
||||
}
|
||||
topActivity = false;
|
||||
}
|
||||
lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
|
||||
colorBackground);
|
||||
colorBackground, statusBarColor, navigationBarColor);
|
||||
if (mWindowContainerController != null) {
|
||||
mWindowContainerController.setTaskDescription(lastTaskDescription);
|
||||
}
|
||||
|
||||
@@ -5254,11 +5254,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
// Don't allow snapshots to influence SystemUI visibility flags.
|
||||
// TODO: Revisit this once SystemUI flags for snapshots are handled correctly
|
||||
boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
|
||||
&& attrs.type < FIRST_SYSTEM_WINDOW
|
||||
&& (attrs.privateFlags & PRIVATE_FLAG_TASK_SNAPSHOT) == 0;
|
||||
&& attrs.type < FIRST_SYSTEM_WINDOW;
|
||||
final int stackId = win.getStackId();
|
||||
if (mTopFullscreenOpaqueWindowState == null && visible) {
|
||||
if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
|
||||
|
||||
@@ -566,7 +566,7 @@ public class AppWindowContainerController
|
||||
return false;
|
||||
}
|
||||
|
||||
mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
|
||||
mContainer.startingData = new SnapshotStartingData(mService, snapshot);
|
||||
scheduleAddStartingWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2920,7 +2920,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
if (stack != null) {
|
||||
stack.getBounds(frame);
|
||||
}
|
||||
} else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
|
||||
|
||||
// We want to screenshot with the exact bounds of the surface of the app. Thus,
|
||||
// intersect it with the frame.
|
||||
frame.intersect(w.mFrame);
|
||||
}else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
|
||||
final Rect wf = w.mFrame;
|
||||
final Rect cr = w.mContentInsets;
|
||||
int left = wf.left + cr.left;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.view.WindowManagerPolicy.StartingSurface;
|
||||
|
||||
@@ -25,9 +26,9 @@ import android.view.WindowManagerPolicy.StartingSurface;
|
||||
class SnapshotStartingData extends StartingData {
|
||||
|
||||
private final WindowManagerService mService;
|
||||
private final GraphicBuffer mSnapshot;
|
||||
private final TaskSnapshot mSnapshot;
|
||||
|
||||
SnapshotStartingData(WindowManagerService service, GraphicBuffer snapshot) {
|
||||
SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
|
||||
super(service);
|
||||
mService = service;
|
||||
mSnapshot = snapshot;
|
||||
|
||||
@@ -17,15 +17,14 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
|
||||
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
|
||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
|
||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
@@ -40,7 +39,6 @@ import android.view.DisplayInfo;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.EventLogTags;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.app.ActivityManager.StackId;
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Environment;
|
||||
import android.util.ArraySet;
|
||||
import android.view.WindowManagerPolicy.StartingSurface;
|
||||
@@ -152,7 +153,7 @@ class TaskSnapshotController {
|
||||
* MANAGER LOCK WHEN CALLING THIS METHOD!
|
||||
*/
|
||||
StartingSurface createStartingSurface(AppWindowToken token,
|
||||
GraphicBuffer snapshot) {
|
||||
TaskSnapshot snapshot) {
|
||||
return TaskSnapshotSurface.create(mService, token, snapshot);
|
||||
}
|
||||
|
||||
@@ -166,8 +167,17 @@ class TaskSnapshotController {
|
||||
if (buffer == null) {
|
||||
return null;
|
||||
}
|
||||
final WindowState mainWindow = top.findMainWindow();
|
||||
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
|
||||
top.findMainWindow().mStableInsets, false /* reduced */, 1f /* scale */);
|
||||
minRect(mainWindow.mContentInsets, mainWindow.mStableInsets), false /* reduced */,
|
||||
1f /* scale */);
|
||||
}
|
||||
|
||||
private Rect minRect(Rect rect1, Rect rect2) {
|
||||
return new Rect(Math.min(rect1.left, rect2.left),
|
||||
Math.min(rect1.top, rect2.top),
|
||||
Math.min(rect1.right, rect2.right),
|
||||
Math.min(rect1.bottom, rect2.bottom));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,20 +16,35 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
import static android.graphics.Color.WHITE;
|
||||
import static android.graphics.Color.alpha;
|
||||
import static android.view.SurfaceControl.HIDDEN;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
||||
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
|
||||
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
|
||||
import static com.android.internal.policy.DecorView.getColorViewLeftInset;
|
||||
import static com.android.internal.policy.DecorView.getColorViewTopInset;
|
||||
import static com.android.internal.policy.DecorView.getNavigationBarRect;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.graphics.Bitmap;
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
@@ -37,17 +52,22 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.MergedConfiguration;
|
||||
import android.util.Slog;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceSession;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.WindowManagerPolicy.StartingSurface;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.policy.DecorView;
|
||||
import com.android.internal.view.BaseIWindow;
|
||||
|
||||
/**
|
||||
@@ -57,19 +77,57 @@ import com.android.internal.view.BaseIWindow;
|
||||
*/
|
||||
class TaskSnapshotSurface implements StartingSurface {
|
||||
|
||||
private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
|
||||
|
||||
/**
|
||||
* When creating the starting window, we use the exact same layout flags such that we end up
|
||||
* with a window with the exact same dimensions etc. However, these flags are not used in layout
|
||||
* and might cause other side effects so we exclude them.
|
||||
*/
|
||||
private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
|
||||
| FLAG_NOT_TOUCHABLE
|
||||
| FLAG_NOT_TOUCH_MODAL
|
||||
| FLAG_ALT_FOCUSABLE_IM
|
||||
| FLAG_NOT_FOCUSABLE
|
||||
| FLAG_HARDWARE_ACCELERATED
|
||||
| FLAG_IGNORE_CHEEK_PRESSES
|
||||
| FLAG_LOCAL_FOCUS_MODE
|
||||
| FLAG_SLIPPERY
|
||||
| FLAG_WATCH_OUTSIDE_TOUCH
|
||||
| FLAG_SPLIT_TOUCH
|
||||
| FLAG_SCALED
|
||||
| FLAG_SECURE;
|
||||
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
|
||||
private static final int MSG_REPORT_DRAW = 0;
|
||||
private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
|
||||
private final Window mWindow;
|
||||
private final Surface mSurface;
|
||||
private SurfaceControl mChildSurfaceControl;
|
||||
private final IWindowSession mSession;
|
||||
private final WindowManagerService mService;
|
||||
private final Rect mTaskBounds;
|
||||
private final Rect mStableInsets = new Rect();
|
||||
private final Rect mContentInsets = new Rect();
|
||||
private final Rect mFrame = new Rect();
|
||||
private final TaskSnapshot mSnapshot;
|
||||
private final CharSequence mTitle;
|
||||
private boolean mHasDrawn;
|
||||
private boolean mReportNextDraw;
|
||||
private Paint mFillBackgroundPaint = new Paint();
|
||||
private long mShownTime;
|
||||
private final Handler mHandler;
|
||||
private final boolean mSizeMismatch;
|
||||
private final Paint mBackgroundPaint = new Paint();
|
||||
private final Paint mStatusBarPaint = new Paint();
|
||||
private final Paint mNavigationBarPaint = new Paint();
|
||||
private final int mStatusBarColor;
|
||||
private final int mNavigationBarColor;
|
||||
private final int mSysUiVis;
|
||||
private final int mWindowFlags;
|
||||
private final int mWindowPrivateFlags;
|
||||
|
||||
static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
|
||||
GraphicBuffer snapshot) {
|
||||
TaskSnapshot snapshot) {
|
||||
|
||||
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
|
||||
final Window window = new Window();
|
||||
@@ -78,32 +136,51 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
final Surface surface = new Surface();
|
||||
final Rect tmpRect = new Rect();
|
||||
final Rect tmpFrame = new Rect();
|
||||
final Rect taskBounds;
|
||||
final Rect tmpContentInsets = new Rect();
|
||||
final Rect tmpStableInsets = new Rect();
|
||||
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
|
||||
int fillBackgroundColor = Color.WHITE;
|
||||
int backgroundColor = WHITE;
|
||||
int statusBarColor = 0;
|
||||
int navigationBarColor = 0;
|
||||
final int sysUiVis;
|
||||
final int windowFlags;
|
||||
final int windowPrivateFlags;
|
||||
synchronized (service.mWindowMap) {
|
||||
final WindowState mainWindow = token.findMainWindow();
|
||||
if (mainWindow == null) {
|
||||
Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
|
||||
+ token);
|
||||
return null;
|
||||
}
|
||||
sysUiVis = mainWindow.getSystemUiVisibility();
|
||||
windowFlags = mainWindow.getAttrs().flags;
|
||||
windowPrivateFlags = mainWindow.getAttrs().privateFlags;
|
||||
|
||||
layoutParams.type = TYPE_APPLICATION_STARTING;
|
||||
layoutParams.format = snapshot.getFormat();
|
||||
layoutParams.flags = FLAG_LAYOUT_INSET_DECOR
|
||||
| FLAG_LAYOUT_IN_SCREEN
|
||||
layoutParams.format = snapshot.getSnapshot().getFormat();
|
||||
layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
|
||||
| FLAG_NOT_FOCUSABLE
|
||||
| FLAG_NOT_TOUCHABLE
|
||||
| FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
|
||||
| FLAG_NOT_TOUCHABLE;
|
||||
layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
|
||||
layoutParams.token = token.token;
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||
|
||||
// TODO: Inherit behavior whether to draw behind status bar/nav bar.
|
||||
layoutParams.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
|
||||
layoutParams.systemUiVisibility = sysUiVis;
|
||||
final Task task = token.getTask();
|
||||
if (task != null) {
|
||||
layoutParams.setTitle(String.format(TITLE_FORMAT,task.mTaskId));
|
||||
layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
|
||||
|
||||
final TaskDescription taskDescription = task.getTaskDescription();
|
||||
if (taskDescription != null) {
|
||||
fillBackgroundColor = taskDescription.getBackgroundColor();
|
||||
backgroundColor = taskDescription.getBackgroundColor();
|
||||
statusBarColor = taskDescription.getStatusBarColor();
|
||||
navigationBarColor = taskDescription.getNavigationBarColor();
|
||||
}
|
||||
taskBounds = new Rect();
|
||||
task.getBounds(taskBounds);
|
||||
} else {
|
||||
taskBounds = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -118,31 +195,57 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
// Local call.
|
||||
}
|
||||
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
|
||||
surface, fillBackgroundColor);
|
||||
surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
|
||||
navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds);
|
||||
window.setOuter(snapshotSurface);
|
||||
try {
|
||||
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
|
||||
tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration,
|
||||
surface);
|
||||
tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
|
||||
tmpMergedConfiguration, surface);
|
||||
} catch (RemoteException e) {
|
||||
// Local call.
|
||||
}
|
||||
snapshotSurface.drawSnapshot(snapshot);
|
||||
snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
|
||||
snapshotSurface.drawSnapshot();
|
||||
return snapshotSurface;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
|
||||
int fillBackgroundColor) {
|
||||
TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
|
||||
int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
|
||||
Rect taskBounds) {
|
||||
mService = service;
|
||||
mHandler = new Handler(mService.mH.getLooper());
|
||||
mSession = WindowManagerGlobal.getWindowSession();
|
||||
mWindow = window;
|
||||
mSurface = surface;
|
||||
mFillBackgroundPaint.setColor(fillBackgroundColor);
|
||||
mSnapshot = snapshot;
|
||||
mTitle = title;
|
||||
mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
|
||||
mTaskBounds = taskBounds;
|
||||
mSysUiVis = sysUiVis;
|
||||
mWindowFlags = windowFlags;
|
||||
mWindowPrivateFlags = windowPrivateFlags;
|
||||
mSizeMismatch = (mFrame.width() != snapshot.getSnapshot().getWidth()
|
||||
|| mFrame.height() != snapshot.getSnapshot().getHeight());
|
||||
mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
|
||||
service.mContext.getColor(R.color.system_bar_background_semi_transparent),
|
||||
statusBarColor);
|
||||
mNavigationBarColor = navigationBarColor;
|
||||
mStatusBarPaint.setColor(mStatusBarColor);
|
||||
mNavigationBarPaint.setColor(navigationBarColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
synchronized (mService.mWindowMap) {
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
|
||||
mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
mSession.remove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
@@ -150,31 +253,149 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
}
|
||||
}
|
||||
|
||||
private void drawSnapshot(GraphicBuffer snapshot) {
|
||||
mSurface.attachAndQueueBuffer(snapshot);
|
||||
@VisibleForTesting
|
||||
void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
|
||||
mFrame.set(frame);
|
||||
mContentInsets.set(contentInsets);
|
||||
mStableInsets.set(stableInsets);
|
||||
}
|
||||
|
||||
private void drawSnapshot() {
|
||||
final GraphicBuffer buffer = mSnapshot.getSnapshot();
|
||||
if (mSizeMismatch) {
|
||||
// The dimensions of the buffer and the window don't match, so attaching the buffer
|
||||
// will fail. Better create a child window with the exact dimensions and fill the parent
|
||||
// window with the background color!
|
||||
drawSizeMismatchSnapshot(buffer);
|
||||
} else {
|
||||
drawSizeMatchSnapshot(buffer);
|
||||
}
|
||||
final boolean reportNextDraw;
|
||||
synchronized (mService.mWindowMap) {
|
||||
mShownTime = SystemClock.uptimeMillis();
|
||||
mHasDrawn = true;
|
||||
reportNextDraw = mReportNextDraw;
|
||||
}
|
||||
if (reportNextDraw) {
|
||||
reportDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
|
||||
mSurface.attachAndQueueBuffer(buffer);
|
||||
mSurface.release();
|
||||
}
|
||||
|
||||
private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
|
||||
final SurfaceSession session = new SurfaceSession(mSurface);
|
||||
|
||||
// Keep a reference to it such that it doesn't get destroyed when finalized.
|
||||
mChildSurfaceControl = new SurfaceControl(session,
|
||||
mTitle + " - task-snapshot-surface",
|
||||
buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN);
|
||||
Surface surface = new Surface();
|
||||
surface.copyFrom(mChildSurfaceControl);
|
||||
|
||||
// Clip off ugly navigation bar.
|
||||
final Rect crop = calculateSnapshotCrop();
|
||||
final Rect frame = calculateSnapshotFrame(crop);
|
||||
SurfaceControl.openTransaction();
|
||||
try {
|
||||
// We can just show the surface here as it will still be hidden as the parent is
|
||||
// still hidden.
|
||||
mChildSurfaceControl.show();
|
||||
mChildSurfaceControl.setWindowCrop(crop);
|
||||
mChildSurfaceControl.setPosition(frame.left, frame.top);
|
||||
} finally {
|
||||
SurfaceControl.closeTransaction();
|
||||
}
|
||||
surface.attachAndQueueBuffer(buffer);
|
||||
surface.release();
|
||||
|
||||
final Canvas c = mSurface.lockCanvas(null);
|
||||
drawBackgroundAndBars(c, frame);
|
||||
mSurface.unlockCanvasAndPost(c);
|
||||
mSurface.release();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void fillEmptyBackground(Canvas c, Bitmap b) {
|
||||
final boolean fillHorizontally = c.getWidth() > b.getWidth();
|
||||
final boolean fillVertically = c.getHeight() > b.getHeight();
|
||||
Rect calculateSnapshotCrop() {
|
||||
final Rect rect = new Rect();
|
||||
rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
|
||||
final Rect insets = mSnapshot.getContentInsets();
|
||||
|
||||
// Let's remove all system decorations except the status bar, but only if the task is at the
|
||||
// very top of the screen.
|
||||
rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom);
|
||||
return rect;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Rect calculateSnapshotFrame(Rect crop) {
|
||||
final Rect frame = new Rect(crop);
|
||||
|
||||
// By default, offset it to to top/left corner
|
||||
frame.offsetTo(-crop.left, -crop.top);
|
||||
|
||||
// However, we also need to make space for the navigation bar on the left side.
|
||||
final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
|
||||
mContentInsets.left);
|
||||
frame.offset(colorViewLeftInset, 0);
|
||||
return frame;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void drawBackgroundAndBars(Canvas c, Rect frame) {
|
||||
final int statusBarHeight = getStatusBarColorViewHeight();
|
||||
final boolean fillHorizontally = c.getWidth() > frame.right;
|
||||
final boolean fillVertically = c.getHeight() > frame.bottom;
|
||||
if (fillHorizontally) {
|
||||
c.drawRect(b.getWidth(), 0, c.getWidth(), fillVertically
|
||||
? b.getHeight()
|
||||
: c.getHeight(),
|
||||
mFillBackgroundPaint);
|
||||
c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
|
||||
c.getWidth(), fillVertically
|
||||
? frame.bottom
|
||||
: c.getHeight(),
|
||||
mBackgroundPaint);
|
||||
}
|
||||
if (fillVertically) {
|
||||
c.drawRect(0, b.getHeight(), c.getWidth(), c.getHeight(), mFillBackgroundPaint);
|
||||
c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
|
||||
}
|
||||
drawStatusBarBackground(c, frame, statusBarHeight);
|
||||
drawNavigationBarBackground(c);
|
||||
}
|
||||
|
||||
private int getStatusBarColorViewHeight() {
|
||||
final boolean forceStatusBarBackground =
|
||||
(mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
|
||||
if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
|
||||
mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
|
||||
return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNavigationBarColorViewVisible() {
|
||||
return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
|
||||
mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void drawStatusBarBackground(Canvas c, Rect frame, int statusBarHeight) {
|
||||
if (statusBarHeight > 0 && c.getWidth() > frame.right) {
|
||||
final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
|
||||
mContentInsets.right);
|
||||
c.drawRect(frame.right, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void drawNavigationBarBackground(Canvas c) {
|
||||
final Rect navigationBarRect = new Rect();
|
||||
getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
|
||||
navigationBarRect);
|
||||
final boolean visible = isNavigationBarColorViewVisible();
|
||||
if (visible && !navigationBarRect.isEmpty()) {
|
||||
c.drawRect(navigationBarRect, mNavigationBarPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,10 +432,10 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
}
|
||||
};
|
||||
|
||||
private static class Window extends BaseIWindow {
|
||||
@VisibleForTesting
|
||||
static class Window extends BaseIWindow {
|
||||
|
||||
private TaskSnapshotSurface mOuter;
|
||||
|
||||
public void setOuter(TaskSnapshotSurface outer) {
|
||||
mOuter = outer;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
@@ -24,15 +27,19 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.server.wm.TaskSnapshotSurface.Window;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -48,59 +55,174 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
|
||||
|
||||
private TaskSnapshotSurface mSurface;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mSurface = new TaskSnapshotSurface(null, null, null, Color.WHITE);
|
||||
private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
|
||||
int windowFlags, Rect taskBounds) {
|
||||
final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
|
||||
GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
|
||||
final TaskSnapshot snapshot = new TaskSnapshot(buffer,
|
||||
ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
|
||||
mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
|
||||
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds);
|
||||
}
|
||||
|
||||
private void setupSurface(int width, int height) {
|
||||
setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
|
||||
new Rect(0, 0, width, height));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_fillHorizontally() throws Exception {
|
||||
setupSurface(200, 100);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(200);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
final Bitmap b = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
|
||||
mSurface.fillEmptyBackground(mockCanvas, b);
|
||||
mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
|
||||
verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_fillVertically() throws Exception {
|
||||
setupSurface(100, 200);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(200);
|
||||
final Bitmap b = Bitmap.createBitmap(200, 100, Config.ARGB_8888);
|
||||
mSurface.fillEmptyBackground(mockCanvas, b);
|
||||
mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
|
||||
verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_fillBoth() throws Exception {
|
||||
setupSurface(200, 200);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(200);
|
||||
when(mockCanvas.getHeight()).thenReturn(200);
|
||||
final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
|
||||
mSurface.fillEmptyBackground(mockCanvas, b);
|
||||
mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
|
||||
verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
|
||||
verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_dontFill_sameSize() throws Exception {
|
||||
setupSurface(100, 100);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
final Bitmap b = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
|
||||
mSurface.fillEmptyBackground(mockCanvas, b);
|
||||
mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
|
||||
verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception {
|
||||
setupSurface(100, 100);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
final Bitmap b = Bitmap.createBitmap(200, 200, Config.ARGB_8888);
|
||||
mSurface.fillEmptyBackground(mockCanvas, b);
|
||||
mSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
|
||||
verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotCrop() {
|
||||
setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
|
||||
assertEquals(new Rect(0, 0, 100, 90), mSurface.calculateSnapshotCrop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotCrop_taskNotOnTop() {
|
||||
setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100));
|
||||
assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotCrop_navBarLeft() {
|
||||
setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
|
||||
assertEquals(new Rect(10, 0, 100, 100), mSurface.calculateSnapshotCrop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotCrop_navBarRight() {
|
||||
setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
|
||||
assertEquals(new Rect(0, 0, 90, 100), mSurface.calculateSnapshotCrop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotFrame() {
|
||||
setupSurface(100, 100);
|
||||
final Rect insets = new Rect(0, 10, 0, 10);
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
assertEquals(new Rect(0, -10, 100, 70),
|
||||
mSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateSnapshotFrame_navBarLeft() {
|
||||
setupSurface(100, 100);
|
||||
final Rect insets = new Rect(10, 10, 0, 0);
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
assertEquals(new Rect(0, -10, 90, 80),
|
||||
mSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawStatusBarBackground() {
|
||||
setupSurface(100, 100);
|
||||
final Rect insets = new Rect(0, 10, 10, 0);
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100), 10);
|
||||
verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawStatusBarBackground_nope() {
|
||||
setupSurface(100, 100);
|
||||
final Rect insets = new Rect(0, 10, 10, 0);
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
mSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100), 10);
|
||||
verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawNavigationBarBackground() {
|
||||
final Rect insets = new Rect(0, 10, 0, 10);
|
||||
setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
|
||||
new Rect(0, 0, 100, 100));
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
mSurface.drawNavigationBarBackground(mockCanvas);
|
||||
verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawNavigationBarBackground_left() {
|
||||
final Rect insets = new Rect(10, 10, 0, 0);
|
||||
setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
|
||||
new Rect(0, 0, 100, 100));
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
mSurface.drawNavigationBarBackground(mockCanvas);
|
||||
verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrawNavigationBarBackground_right() {
|
||||
final Rect insets = new Rect(0, 10, 10, 0);
|
||||
setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
|
||||
new Rect(0, 0, 100, 100));
|
||||
mSurface.setFrames(new Rect(0, 0, 100, 100), insets, insets);
|
||||
final Canvas mockCanvas = mock(Canvas.class);
|
||||
when(mockCanvas.getWidth()).thenReturn(100);
|
||||
when(mockCanvas.getHeight()).thenReturn(100);
|
||||
mSurface.drawNavigationBarBackground(mockCanvas);
|
||||
verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user