1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 21 import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; 22 import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; 23 24 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 25 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.when; 30 31 import android.content.ComponentName; 32 import android.content.ContextWrapper; 33 import android.content.res.Resources; 34 import android.graphics.Canvas; 35 import android.graphics.Color; 36 import android.graphics.ColorSpace; 37 import android.graphics.GraphicBuffer; 38 import android.graphics.PixelFormat; 39 import android.graphics.Point; 40 import android.graphics.Rect; 41 import android.hardware.HardwareBuffer; 42 import android.os.UserManager; 43 import android.view.Surface; 44 import android.window.TaskSnapshot; 45 46 import com.android.server.LocalServices; 47 import com.android.server.pm.UserManagerInternal; 48 import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; 49 50 import org.junit.After; 51 import org.junit.AfterClass; 52 import org.junit.Before; 53 import org.junit.BeforeClass; 54 55 import java.io.File; 56 import java.util.function.Predicate; 57 58 /** 59 * Base class for tests that use a {@link TaskSnapshotPersister}. 60 */ 61 class TaskSnapshotPersisterTestBase extends WindowTestsBase { 62 63 private static final Rect TEST_CONTENT_INSETS = new Rect(10, 20, 30, 40); 64 private static final Rect TEST_LETTERBOX_INSETS = new Rect(); 65 static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir(); 66 static final long MOCK_SNAPSHOT_ID = 12345678; 67 68 private ContextWrapper mContextSpy; 69 private Resources mResourcesSpy; 70 SnapshotPersistQueue mSnapshotPersistQueue; 71 TaskSnapshotPersister mPersister; 72 AppSnapshotLoader mLoader; 73 int mTestUserId; 74 float mHighResScale; 75 float mLowResScale; 76 TaskSnapshotPersisterTestBase(float highResScale, float lowResScale)77 TaskSnapshotPersisterTestBase(float highResScale, float lowResScale) { 78 super(); 79 mHighResScale = highResScale; 80 mLowResScale = lowResScale; 81 } 82 83 @BeforeClass setUpOnce()84 public static void setUpOnce() { 85 final UserManagerInternal userManager = mock(UserManagerInternal.class); 86 LocalServices.addService(UserManagerInternal.class, userManager); 87 } 88 89 @AfterClass tearDownOnce()90 public static void tearDownOnce() { 91 LocalServices.removeServiceForTest(UserManagerInternal.class); 92 } 93 94 @Before setUp()95 public void setUp() { 96 final UserManager um = UserManager.get(getInstrumentation().getTargetContext()); 97 mTestUserId = um.getProcessUserId(); 98 99 final UserManagerInternal userManagerInternal = 100 LocalServices.getService(UserManagerInternal.class); 101 when(userManagerInternal.isUserUnlocked(mTestUserId)).thenReturn(true); 102 103 mContextSpy = spy(new ContextWrapper(mWm.mContext)); 104 mResourcesSpy = spy(mContextSpy.getResources()); 105 when(mContextSpy.getResources()).thenReturn(mResourcesSpy); 106 when(mResourcesSpy.getFloat( 107 com.android.internal.R.dimen.config_highResTaskSnapshotScale)) 108 .thenReturn(mHighResScale); 109 when(mResourcesSpy.getFloat( 110 com.android.internal.R.dimen.config_lowResTaskSnapshotScale)) 111 .thenReturn(mLowResScale); 112 113 mSnapshotPersistQueue = new SnapshotPersistQueue(); 114 PersistInfoProvider provider = 115 TaskSnapshotController.createPersistInfoProvider(mWm, userId -> FILES_DIR); 116 mPersister = new TaskSnapshotPersister(mSnapshotPersistQueue, provider); 117 mLoader = new AppSnapshotLoader(provider); 118 mSnapshotPersistQueue.start(); 119 } 120 121 @After tearDown()122 public void tearDown() { 123 cleanDirectory(); 124 } 125 cleanDirectory()126 private void cleanDirectory() { 127 final File[] files = new File(FILES_DIR, "snapshots").listFiles(); 128 if (files == null) { 129 return; 130 } 131 for (File file : files) { 132 if (!file.isDirectory()) { 133 file.delete(); 134 } 135 } 136 } 137 createSnapshot()138 TaskSnapshot createSnapshot() { 139 return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build(); 140 } 141 assertTrueForFiles(File[] files, Predicate<File> predicate, String message)142 protected static void assertTrueForFiles(File[] files, Predicate<File> predicate, 143 String message) { 144 for (File file : files) { 145 assertTrue(file.getName() + message, predicate.test(file)); 146 } 147 } 148 149 /** 150 * Builds a TaskSnapshot. 151 */ 152 static class TaskSnapshotBuilder { 153 private static final int SNAPSHOT_WIDTH = 100; 154 private static final int SNAPSHOT_HEIGHT = 100; 155 156 private float mScaleFraction = 1f; 157 private boolean mIsRealSnapshot = true; 158 private boolean mIsTranslucent = false; 159 private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; 160 private int mSystemUiVisibility = 0; 161 private int mRotation = Surface.ROTATION_0; 162 private int mWidth = SNAPSHOT_WIDTH; 163 private int mHeight = SNAPSHOT_HEIGHT; 164 private ComponentName mTopActivityComponent = new ComponentName("", ""); 165 TaskSnapshotBuilder()166 TaskSnapshotBuilder() { 167 } 168 setTopActivityComponent(ComponentName topActivityComponent)169 TaskSnapshotBuilder setTopActivityComponent(ComponentName topActivityComponent) { 170 mTopActivityComponent = topActivityComponent; 171 return this; 172 } 173 setScaleFraction(float scale)174 TaskSnapshotBuilder setScaleFraction(float scale) { 175 mScaleFraction = scale; 176 return this; 177 } 178 setIsRealSnapshot(boolean isRealSnapshot)179 TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) { 180 mIsRealSnapshot = isRealSnapshot; 181 return this; 182 } 183 setIsTranslucent(boolean isTranslucent)184 TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) { 185 mIsTranslucent = isTranslucent; 186 return this; 187 } 188 setWindowingMode(int windowingMode)189 TaskSnapshotBuilder setWindowingMode(int windowingMode) { 190 mWindowingMode = windowingMode; 191 return this; 192 } 193 setSystemUiVisibility(int systemUiVisibility)194 TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) { 195 mSystemUiVisibility = systemUiVisibility; 196 return this; 197 } 198 setRotation(int rotation)199 TaskSnapshotBuilder setRotation(int rotation) { 200 mRotation = rotation; 201 return this; 202 } 203 setTaskSize(int width, int height)204 TaskSnapshotBuilder setTaskSize(int width, int height) { 205 mWidth = width; 206 mHeight = height; 207 return this; 208 } 209 build()210 TaskSnapshot build() { 211 // To satisfy existing tests, ensure the graphics buffer is always 100x100, and 212 // compute the ize of the task according to mScaleFraction. 213 Point taskSize = new Point((int) (mWidth / mScaleFraction), 214 (int) (mHeight / mScaleFraction)); 215 final GraphicBuffer buffer = GraphicBuffer.create(mWidth, mHeight, 216 PixelFormat.RGBA_8888, 217 USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); 218 Canvas c = buffer.lockCanvas(); 219 c.drawColor(Color.RED); 220 buffer.unlockCanvasAndPost(c); 221 return new TaskSnapshot(MOCK_SNAPSHOT_ID, 0 /* captureTime */, mTopActivityComponent, 222 HardwareBuffer.createFromGraphicBuffer(buffer), 223 ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, 224 mRotation, taskSize, TEST_CONTENT_INSETS, TEST_LETTERBOX_INSETS, 225 // When building a TaskSnapshot with the Builder class, isLowResolution 226 // is always false. Low-res snapshots are only created when loading from 227 // disk. 228 false /* isLowResolution */, 229 mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent, 230 false /* hasImeSurface */); 231 } 232 } 233 } 234