Merge "Fix snapshots for secure windows" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-05-03 17:29:16 +00:00
committed by Android (Google) Code Review
6 changed files with 147 additions and 66 deletions

View File

@@ -36,7 +36,6 @@ import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Trace;
import android.util.Slog;
import android.view.IApplicationToken;
@@ -319,7 +318,7 @@ public class AppWindowContainerController
+ " token: " + mToken);
return;
}
mContainer.setDisablePreviewSnapshots(disable);
mContainer.setDisablePreviewScreenshots(disable);
}
}

View File

@@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -48,6 +49,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE
import static com.android.server.wm.WindowManagerService.logWithStack;
import android.annotation.NonNull;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -1528,12 +1530,24 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return candidate;
}
void setDisablePreviewSnapshots(boolean disable) {
/**
* See {@link Activity#setDisablePreviewScreenshots}.
*/
void setDisablePreviewScreenshots(boolean disable) {
mDisbalePreviewScreenshots = disable;
}
boolean shouldDisablePreviewScreenshots() {
return mDisbalePreviewScreenshots;
/**
* Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
* the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
* we can't take a snapshot for other reasons, for example, if we have a secure window.
*
* @return True if we need to generate an app theme snapshot, false if we'd like to take a real
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
return mDisbalePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
true /* topToBottom */);
}
@Override

View File

@@ -31,11 +31,13 @@ import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Environment;
import android.util.ArraySet;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerPolicy.StartingSurface;
import com.google.android.collect.Sets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
import java.io.PrintWriter;
@@ -206,7 +208,7 @@ class TaskSnapshotController {
final AppWindowToken topChild = task.getTopChild();
if (StackId.isHomeOrRecentsStack(task.mStack.mStackId)) {
return SNAPSHOT_MODE_NONE;
} else if (topChild != null && topChild.shouldDisablePreviewScreenshots()) {
} else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
return SNAPSHOT_MODE_APP_THEME;
} else {
return SNAPSHOT_MODE_REAL;
@@ -227,6 +229,8 @@ class TaskSnapshotController {
return null;
}
final int color = task.getTaskDescription().getBackgroundColor();
final int statusBarColor = task.getTaskDescription().getStatusBarColor();
final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
final GraphicBuffer buffer = GraphicBuffer.create(mainWindow.getFrameLw().width(),
mainWindow.getFrameLw().height(),
RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_WRITE_RARELY | USAGE_SW_READ_NEVER);
@@ -235,6 +239,11 @@ class TaskSnapshotController {
}
final Canvas c = buffer.lockCanvas();
c.drawColor(color);
final LayoutParams attrs = mainWindow.getAttrs();
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
decorPainter.setInsets(mainWindow.mContentInsets, mainWindow.mStableInsets);
decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
mainWindow.mStableInsets, false /* reduced */, 1.0f /* scale */);

View File

@@ -42,8 +42,11 @@ 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.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityThread;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
@@ -118,13 +121,8 @@ class TaskSnapshotSurface implements StartingSurface {
private final Handler mHandler;
private 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;
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
TaskSnapshot snapshot) {
@@ -224,15 +222,9 @@ class TaskSnapshotSurface implements StartingSurface {
mTitle = title;
mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
mTaskBounds = taskBounds;
mSysUiVis = sysUiVis;
mWindowFlags = windowFlags;
mWindowPrivateFlags = windowPrivateFlags;
mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
service.mContext.getColor(R.color.system_bar_background_semi_transparent),
statusBarColor);
mNavigationBarColor = navigationBarColor;
mStatusBarPaint.setColor(mStatusBarColor);
mNavigationBarPaint.setColor(navigationBarColor);
mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
mStatusBarColor = statusBarColor;
}
@Override
@@ -258,6 +250,7 @@ class TaskSnapshotSurface implements StartingSurface {
mStableInsets.set(stableInsets);
mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
|| mFrame.height() != mSnapshot.getSnapshot().getHeight());
mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
}
private void drawSnapshot() {
@@ -346,7 +339,7 @@ class TaskSnapshotSurface implements StartingSurface {
@VisibleForTesting
void drawBackgroundAndBars(Canvas c, Rect frame) {
final int statusBarHeight = getStatusBarColorViewHeight();
final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
final boolean fillHorizontally = c.getWidth() > frame.right;
final boolean fillVertically = c.getHeight() > frame.bottom;
if (fillHorizontally) {
@@ -359,44 +352,7 @@ class TaskSnapshotSurface implements StartingSurface {
if (fillVertically) {
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);
}
mSystemBarBackgroundPainter.drawDecors(c, frame);
}
private void reportDrawn() {
@@ -450,4 +406,84 @@ class TaskSnapshotSurface implements StartingSurface {
}
}
}
/**
* Helper class to draw the background of the system bars in regions the task snapshot isn't
* filling the window.
*/
static class SystemBarBackgroundPainter {
private final Rect mContentInsets = new Rect();
private final Rect mStableInsets = new Rect();
private final Paint mStatusBarPaint = new Paint();
private final Paint mNavigationBarPaint = new Paint();
private final int mStatusBarColor;
private final int mNavigationBarColor;
private final int mWindowFlags;
private final int mWindowPrivateFlags;
private final int mSysUiVis;
SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
int statusBarColor, int navigationBarColor) {
mWindowFlags = windowFlags;
mWindowPrivateFlags = windowPrivateFlags;
mSysUiVis = sysUiVis;
final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
context.getColor(R.color.system_bar_background_semi_transparent),
statusBarColor);
mNavigationBarColor = navigationBarColor;
mStatusBarPaint.setColor(mStatusBarColor);
mNavigationBarPaint.setColor(navigationBarColor);
}
void setInsets(Rect contentInsets, Rect stableInsets) {
mContentInsets.set(contentInsets);
mStableInsets.set(stableInsets);
}
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 */);
}
void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
drawNavigationBarBackground(c);
}
@VisibleForTesting
void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
int statusBarHeight) {
if (statusBarHeight > 0
&& (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
mContentInsets.right);
final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
c.drawRect(left, 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);
}
}
}
}

View File

@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.TaskSnapshotController.*;
import static junit.framework.Assert.assertEquals;
@@ -76,12 +77,19 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
public void testGetSnapshotMode() throws Exception {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
disabledWindow.mAppToken.setDisablePreviewSnapshots(true);
disabledWindow.mAppToken.setDisablePreviewScreenshots(true);
assertEquals(SNAPSHOT_MODE_APP_THEME,
sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
final WindowState normalWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow");
assertEquals(SNAPSHOT_MODE_REAL,
sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
final WindowState secureWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow");
secureWindow.mAttrs.flags |= FLAG_SECURE;
assertEquals(SNAPSHOT_MODE_APP_THEME,
sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
}
}

View File

@@ -171,10 +171,24 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
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);
mSurface.mSystemBarBackgroundPainter.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_nullFrame() {
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.mSystemBarBackgroundPainter.drawStatusBarBackground(
mockCanvas, null, 10);
verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
}
@Test
public void testDrawStatusBarBackground_nope() {
setupSurface(100, 100);
@@ -183,7 +197,8 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
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);
mSurface.mSystemBarBackgroundPainter.drawStatusBarBackground(
mockCanvas, new Rect(0, 0, 100, 100), 10);
verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
}
@@ -196,7 +211,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
mSurface.drawNavigationBarBackground(mockCanvas);
mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
}
@@ -209,7 +224,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
mSurface.drawNavigationBarBackground(mockCanvas);
mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
}
@@ -222,7 +237,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
when(mockCanvas.getHeight()).thenReturn(100);
mSurface.drawNavigationBarBackground(mockCanvas);
mSurface.mSystemBarBackgroundPainter.drawNavigationBarBackground(mockCanvas);
verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
}
}