Expose the system ui visibility flags and translucent state with snapshot

- Allow SystemUI/Launcher to determine whether the snapshot is of a
  translucent activity (to reduce overdraw by skipping drawing task
  background) and also the sysui visibility flags are (to determine how
  to update the nav bar while animating before the app is started.
- Fixing issue where the recents animation was reporting task fillsparent
  state instead of the app's fillsparent state (as we do in normal remote
  animations)

Bug: 79228291
Bug: 77984778
Bug: 78659249
Test: atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
Change-Id: I19bdf7f780e7d94014d6a115bf84fa614b1dffa0
This commit is contained in:
Winson Chung
2018-05-04 15:36:47 -07:00
parent 9743fae2d9
commit 173020c2ef
10 changed files with 173 additions and 25 deletions

View File

@@ -2110,9 +2110,12 @@ public class ActivityManager {
private final boolean mIsRealSnapshot;
private final int mWindowingMode;
private final float mScale;
private final int mSystemUiVisibility;
private final boolean mIsTranslucent;
public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets,
boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode) {
boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode,
int systemUiVisibility, boolean isTranslucent) {
mSnapshot = snapshot;
mOrientation = orientation;
mContentInsets = new Rect(contentInsets);
@@ -2120,6 +2123,8 @@ public class ActivityManager {
mScale = scale;
mIsRealSnapshot = isRealSnapshot;
mWindowingMode = windowingMode;
mSystemUiVisibility = systemUiVisibility;
mIsTranslucent = isTranslucent;
}
private TaskSnapshot(Parcel source) {
@@ -2130,6 +2135,8 @@ public class ActivityManager {
mScale = source.readFloat();
mIsRealSnapshot = source.readBoolean();
mWindowingMode = source.readInt();
mSystemUiVisibility = source.readInt();
mIsTranslucent = source.readBoolean();
}
/**
@@ -2169,6 +2176,13 @@ public class ActivityManager {
return mIsRealSnapshot;
}
/**
* @return Whether or not the snapshot is of a translucent app window.
*/
public boolean isTranslucent() {
return mIsTranslucent;
}
/**
* @return The windowing mode of the task when this snapshot was taken.
*/
@@ -2176,6 +2190,14 @@ public class ActivityManager {
return mWindowingMode;
}
/**
* @return The system ui visibility flags for the top most visible fullscreen window at the
* time that the snapshot was taken.
*/
public int getSystemUiVisibility() {
return mSystemUiVisibility;
}
/**
* @return The scale this snapshot was taken in.
*/
@@ -2197,6 +2219,8 @@ public class ActivityManager {
dest.writeFloat(mScale);
dest.writeBoolean(mIsRealSnapshot);
dest.writeInt(mWindowingMode);
dest.writeInt(mSystemUiVisibility);
dest.writeBoolean(mIsTranslucent);
}
@Override
@@ -2207,7 +2231,9 @@ public class ActivityManager {
+ " mOrientation=" + mOrientation
+ " mContentInsets=" + mContentInsets.toShortString()
+ " mReducedResolution=" + mReducedResolution + " mScale=" + mScale
+ " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode;
+ " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode
+ " mSystemUiVisibility=" + mSystemUiVisibility
+ " mIsTranslucent=" + mIsTranslucent;
}
public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {

View File

@@ -33,7 +33,9 @@ public class ThumbnailData {
public Rect insets;
public boolean reducedResolution;
public boolean isRealSnapshot;
public boolean isTranslucent;
public int windowingMode;
public int systemUiVisibility;
public float scale;
public ThumbnailData() {
@@ -43,7 +45,9 @@ public class ThumbnailData {
reducedResolution = false;
scale = 1f;
isRealSnapshot = true;
isTranslucent = false;
windowingMode = WINDOWING_MODE_UNDEFINED;
systemUiVisibility = 0;
}
public ThumbnailData(TaskSnapshot snapshot) {
@@ -53,6 +57,8 @@ public class ThumbnailData {
reducedResolution = snapshot.isReducedResolution();
scale = snapshot.getScale();
isRealSnapshot = snapshot.isRealSnapshot();
isTranslucent = snapshot.isTranslucent();
windowingMode = snapshot.getWindowingMode();
systemUiVisibility = snapshot.getSystemUiVisibility();
}
}

View File

@@ -29,4 +29,6 @@
int32 inset_bottom = 5;
bool is_real_snapshot = 6;
int32 windowing_mode = 7;
int32 system_ui_visibility = 8;
bool is_translucent = 9;
}

View File

@@ -558,14 +558,17 @@ public class RecentsAnimationController implements DeathRecipient {
}
RemoteAnimationTarget createRemoteAnimationApp() {
final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
final AppWindowToken topApp = mTask.getTopVisibleAppToken();
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
: null;
if (mainWindow == null) {
return null;
}
final Rect insets = new Rect(mainWindow.mContentInsets);
InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
!mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
!topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
return mTarget;

View File

@@ -37,6 +37,7 @@ import android.view.DisplayListCanvas;
import android.view.RenderNode;
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
@@ -274,7 +275,8 @@ class TaskSnapshotController {
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */,
true /* isRealSnapshot */, task.getWindowingMode());
true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
!top.fillsParent());
}
private boolean shouldDisableSnapshots() {
@@ -364,7 +366,8 @@ class TaskSnapshotController {
return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
topChild.getConfiguration().orientation, mainWindow.mStableInsets,
ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */,
false /* isRealSnapshot */, task.getWindowingMode());
false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
!topChild.fillsParent());
}
/**
@@ -429,6 +432,21 @@ class TaskSnapshotController {
});
}
/**
* @return The SystemUI visibility flags for the top fullscreen window in the given
* {@param task}.
*/
private int getSystemUiVisibility(Task task) {
final AppWindowToken topFullscreenToken = task.getTopFullscreenAppToken();
final WindowState topFullscreenWindow = topFullscreenToken != null
? topFullscreenToken.getTopFullscreenWindow()
: null;
if (topFullscreenWindow != null) {
return topFullscreenWindow.getSystemUiVisibility();
}
return 0;
}
void dump(PrintWriter pw, String prefix) {
mCache.dump(pw, prefix);
}

View File

@@ -90,7 +90,8 @@ class TaskSnapshotLoader {
return new TaskSnapshot(buffer, proto.orientation,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
reducedResolution, reducedResolution ? REDUCED_SCALE : 1f,
proto.isRealSnapshot, proto.windowingMode);
proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility,
proto.isTranslucent);
} catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
return null;

View File

@@ -317,6 +317,8 @@ class TaskSnapshotPersister {
proto.insetBottom = mSnapshot.getContentInsets().bottom;
proto.isRealSnapshot = mSnapshot.isRealSnapshot();
proto.windowingMode = mSnapshot.getWindowingMode();
proto.systemUiVisibility = mSnapshot.getSystemUiVisibility();
proto.isTranslucent = mSnapshot.isTranslucent();
final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
final File file = getProtoFile(mTaskId, mUserId);
final AtomicFile atomicFile = new AtomicFile(file);

View File

@@ -34,6 +34,7 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
import android.view.View;
import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
import org.junit.Test;
@@ -166,10 +167,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
@Test
public void testIsRealSnapshotPersistAndLoadSnapshot() {
TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN);
TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN);
TaskSnapshot a = new TaskSnapshotBuilder()
.setIsRealSnapshot(true)
.build();
TaskSnapshot b = new TaskSnapshotBuilder()
.setIsRealSnapshot(false)
.build();
assertTrue(a.isRealSnapshot());
assertFalse(b.isRealSnapshot());
mPersister.persistSnapshot(1, mTestUserId, a);
@@ -185,10 +188,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
@Test
public void testWindowingModePersistAndLoadSnapshot() {
TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN);
TaskSnapshot b = createSnapshot(1f /* scale */, true /* isRealSnapshot */,
WINDOWING_MODE_PINNED);
TaskSnapshot a = new TaskSnapshotBuilder()
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
.build();
TaskSnapshot b = new TaskSnapshotBuilder()
.setWindowingMode(WINDOWING_MODE_PINNED)
.build();
assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED);
mPersister.persistSnapshot(1, mTestUserId, a);
@@ -202,6 +207,50 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED);
}
@Test
public void testIsTranslucentPersistAndLoadSnapshot() {
TaskSnapshot a = new TaskSnapshotBuilder()
.setIsTranslucent(true)
.build();
TaskSnapshot b = new TaskSnapshotBuilder()
.setIsTranslucent(false)
.build();
assertTrue(a.isTranslucent());
assertFalse(b.isTranslucent());
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty();
final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
assertNotNull(snapshotA);
assertNotNull(snapshotB);
assertTrue(snapshotA.isTranslucent());
assertFalse(snapshotB.isTranslucent());
}
@Test
public void testSystemUiVisibilityPersistAndLoadSnapshot() {
final int lightBarFlags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
| View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
TaskSnapshot a = new TaskSnapshotBuilder()
.setSystemUiVisibility(0)
.build();
TaskSnapshot b = new TaskSnapshotBuilder()
.setSystemUiVisibility(lightBarFlags)
.build();
assertTrue(a.getSystemUiVisibility() == 0);
assertTrue(b.getSystemUiVisibility() == lightBarFlags);
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty();
final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
assertNotNull(snapshotA);
assertNotNull(snapshotB);
assertTrue(snapshotA.getSystemUiVisibility() == 0);
assertTrue(snapshotB.getSystemUiVisibility() == lightBarFlags);
}
@Test
public void testRemoveObsoleteFiles() {
mPersister.persistSnapshot(1, mTestUserId, createSnapshot());

View File

@@ -85,16 +85,57 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
}
TaskSnapshot createSnapshot(float scale) {
return createSnapshot(scale, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN);
return new TaskSnapshotBuilder()
.setScale(scale)
.build();
}
TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot, int windowingMode) {
final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS,
scale < 1f /* reducedResolution */, scale, isRealSnapshot, windowingMode);
/**
* Builds a TaskSnapshot.
*/
class TaskSnapshotBuilder {
private float mScale = 1f;
private boolean mIsRealSnapshot = true;
private boolean mIsTranslucent = false;
private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
private int mSystemUiVisibility = 0;
public TaskSnapshotBuilder setScale(float scale) {
mScale = scale;
return this;
}
public TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) {
mIsRealSnapshot = isRealSnapshot;
return this;
}
public TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) {
mIsTranslucent = isTranslucent;
return this;
}
public TaskSnapshotBuilder setWindowingMode(int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
public TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
return this;
}
public TaskSnapshot build() {
final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS,
mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, mWindowingMode,
mSystemUiVisibility, mIsTranslucent);
}
}
}

View File

@@ -62,7 +62,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
final TaskSnapshot snapshot = new TaskSnapshot(buffer,
ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN);
WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
ORIENTATION_PORTRAIT);