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