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