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 49 import org.junit.After; 50 import org.junit.AfterClass; 51 import org.junit.Before; 52 import org.junit.BeforeClass; 53 54 import java.io.File; 55 import java.util.function.Predicate; 56 57 /** 58 * Base class for tests that use a {@link TaskSnapshotPersister}. 59 */ 60 class TaskSnapshotPersisterTestBase extends WindowTestsBase { 61 62 private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); 63 static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir(); 64 static final long MOCK_SNAPSHOT_ID = 12345678; 65 66 private ContextWrapper mContextSpy; 67 private Resources mResourcesSpy; 68 TaskSnapshotPersister mPersister; 69 TaskSnapshotLoader mLoader; 70 int mTestUserId; 71 float mHighResScale; 72 float mLowResScale; 73 TaskSnapshotPersisterTestBase(float highResScale, float lowResScale)74 TaskSnapshotPersisterTestBase(float highResScale, float lowResScale) { 75 super(); 76 mHighResScale = highResScale; 77 mLowResScale = lowResScale; 78 } 79 80 @BeforeClass setUpOnce()81 public static void setUpOnce() { 82 final UserManagerInternal userManager = mock(UserManagerInternal.class); 83 LocalServices.addService(UserManagerInternal.class, userManager); 84 } 85 86 @AfterClass tearDownOnce()87 public static void tearDownOnce() { 88 LocalServices.removeServiceForTest(UserManagerInternal.class); 89 } 90 91 @Before setUp()92 public void setUp() { 93 final UserManager um = UserManager.get(getInstrumentation().getTargetContext()); 94 mTestUserId = um.getUserHandle(); 95 96 final UserManagerInternal userManagerInternal = 97 LocalServices.getService(UserManagerInternal.class); 98 when(userManagerInternal.isUserUnlocked(mTestUserId)).thenReturn(true); 99 100 mContextSpy = spy(new ContextWrapper(mWm.mContext)); 101 mResourcesSpy = spy(mContextSpy.getResources()); 102 when(mContextSpy.getResources()).thenReturn(mResourcesSpy); 103 when(mResourcesSpy.getFloat( 104 com.android.internal.R.dimen.config_highResTaskSnapshotScale)) 105 .thenReturn(mHighResScale); 106 when(mResourcesSpy.getFloat( 107 com.android.internal.R.dimen.config_lowResTaskSnapshotScale)) 108 .thenReturn(mLowResScale); 109 110 mPersister = new TaskSnapshotPersister(mWm, userId -> FILES_DIR); 111 mLoader = new TaskSnapshotLoader(mPersister); 112 mPersister.start(); 113 } 114 115 @After tearDown()116 public void tearDown() { 117 cleanDirectory(); 118 } 119 cleanDirectory()120 private void cleanDirectory() { 121 final File[] files = new File(FILES_DIR, "snapshots").listFiles(); 122 if (files == null) { 123 return; 124 } 125 for (File file : files) { 126 if (!file.isDirectory()) { 127 file.delete(); 128 } 129 } 130 } 131 createSnapshot()132 TaskSnapshot createSnapshot() { 133 return new TaskSnapshotBuilder() 134 .build(); 135 } 136 assertTrueForFiles(File[] files, Predicate<File> predicate, String message)137 protected static void assertTrueForFiles(File[] files, Predicate<File> predicate, 138 String message) { 139 for (File file : files) { 140 assertTrue(file.getName() + message, predicate.test(file)); 141 } 142 } 143 144 /** 145 * Builds a TaskSnapshot. 146 */ 147 static class TaskSnapshotBuilder { 148 private static final int SNAPSHOT_WIDTH = 100; 149 private static final int SNAPSHOT_HEIGHT = 100; 150 151 private float mScaleFraction = 1f; 152 private boolean mIsRealSnapshot = true; 153 private boolean mIsTranslucent = false; 154 private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; 155 private int mSystemUiVisibility = 0; 156 private int mRotation = Surface.ROTATION_0; 157 private ComponentName mTopActivityComponent = new ComponentName("", ""); 158 TaskSnapshotBuilder()159 TaskSnapshotBuilder() { 160 } 161 setTopActivityComponent(ComponentName topActivityComponent)162 TaskSnapshotBuilder setTopActivityComponent(ComponentName topActivityComponent) { 163 mTopActivityComponent = topActivityComponent; 164 return this; 165 } 166 setScaleFraction(float scale)167 TaskSnapshotBuilder setScaleFraction(float scale) { 168 mScaleFraction = scale; 169 return this; 170 } 171 setIsRealSnapshot(boolean isRealSnapshot)172 TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) { 173 mIsRealSnapshot = isRealSnapshot; 174 return this; 175 } 176 setIsTranslucent(boolean isTranslucent)177 TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) { 178 mIsTranslucent = isTranslucent; 179 return this; 180 } 181 setWindowingMode(int windowingMode)182 TaskSnapshotBuilder setWindowingMode(int windowingMode) { 183 mWindowingMode = windowingMode; 184 return this; 185 } 186 setSystemUiVisibility(int systemUiVisibility)187 TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) { 188 mSystemUiVisibility = systemUiVisibility; 189 return this; 190 } 191 setRotation(int rotation)192 TaskSnapshotBuilder setRotation(int rotation) { 193 mRotation = rotation; 194 return this; 195 } 196 build()197 TaskSnapshot build() { 198 // To satisfy existing tests, ensure the graphics buffer is always 100x100, and 199 // compute the ize of the task according to mScaleFraction. 200 Point taskSize = new Point((int) (SNAPSHOT_WIDTH / mScaleFraction), 201 (int) (SNAPSHOT_HEIGHT / mScaleFraction)); 202 final GraphicBuffer buffer = GraphicBuffer.create(SNAPSHOT_WIDTH, SNAPSHOT_HEIGHT, 203 PixelFormat.RGBA_8888, 204 USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); 205 Canvas c = buffer.lockCanvas(); 206 c.drawColor(Color.RED); 207 buffer.unlockCanvasAndPost(c); 208 return new TaskSnapshot(MOCK_SNAPSHOT_ID, mTopActivityComponent, 209 HardwareBuffer.createFromGraphicBuffer(buffer), 210 ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, 211 mRotation, taskSize, TEST_INSETS, 212 // When building a TaskSnapshot with the Builder class, isLowResolution 213 // is always false. Low-res snapshots are only created when loading from 214 // disk. 215 false /* isLowResolution */, 216 mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent, 217 false /* hasImeSurface */); 218 } 219 } 220 } 221