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