1 /*
2  * Copyright (C) 2018 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.systemui.wallpapers;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.hamcrest.Matchers.equalTo;
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyBoolean;
25 import static org.mockito.Mockito.clearInvocations;
26 import static org.mockito.Mockito.doAnswer;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.eq;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 import static org.mockito.hamcrest.MockitoHamcrest.intThat;
34 
35 import android.app.ActivityManager;
36 import android.app.WallpaperManager;
37 import android.content.Context;
38 import android.graphics.Bitmap;
39 import android.graphics.ColorSpace;
40 import android.graphics.Rect;
41 import android.hardware.display.DisplayManager;
42 import android.testing.AndroidTestingRunner;
43 import android.testing.TestableLooper;
44 import android.view.Surface;
45 import android.view.SurfaceHolder;
46 import android.view.WindowManager;
47 import android.view.WindowMetrics;
48 
49 import androidx.test.filters.SmallTest;
50 
51 import com.android.systemui.SysuiTestCase;
52 import com.android.systemui.settings.UserTracker;
53 import com.android.systemui.util.concurrency.FakeExecutor;
54 import com.android.systemui.util.time.FakeSystemClock;
55 
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 
62 @SmallTest
63 @RunWith(AndroidTestingRunner.class)
64 @TestableLooper.RunWithLooper
65 public class ImageWallpaperTest extends SysuiTestCase {
66     private static final int LOW_BMP_WIDTH = 128;
67     private static final int LOW_BMP_HEIGHT = 128;
68     private static final int DISPLAY_WIDTH = 1920;
69     private static final int DISPLAY_HEIGHT = 1080;
70 
71     @Mock
72     private WindowManager mWindowManager;
73     @Mock
74     private WindowMetrics mWindowMetrics;
75     @Mock
76     private DisplayManager mDisplayManager;
77     @Mock
78     private WallpaperManager mWallpaperManager;
79     @Mock
80     private SurfaceHolder mSurfaceHolder;
81     @Mock
82     private Surface mSurface;
83     @Mock
84     private Context mMockContext;
85     @Mock
86     private UserTracker mUserTracker;
87 
88     @Mock
89     private Bitmap mWallpaperBitmap;
90     FakeSystemClock mFakeSystemClock = new FakeSystemClock();
91     FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
92 
93     @Before
setUp()94     public void setUp() throws Exception {
95         allowTestableLooperAsMainThread();
96         MockitoAnnotations.initMocks(this);
97         //mEventCountdown = new CountDownLatch(1);
98 
99         // set up window manager
100         when(mWindowMetrics.getBounds()).thenReturn(
101                 new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
102         when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
103         when(mMockContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
104 
105         // set up display manager
106         doNothing().when(mDisplayManager).registerDisplayListener(any(), any());
107         when(mMockContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
108 
109         // set up bitmap
110         when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB));
111         when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
112 
113         // set up wallpaper manager
114         when(mWallpaperManager.getBitmapAsUser(eq(ActivityManager.getCurrentUser()), anyBoolean()))
115                 .thenReturn(mWallpaperBitmap);
116         when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
117 
118         // set up surface
119         when(mSurfaceHolder.getSurface()).thenReturn(mSurface);
120         doNothing().when(mSurface).hwuiDestroy();
121 
122         // set up UserTracker
123         when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
124     }
125 
126     @Test
testBitmapWallpaper_normal()127     public void testBitmapWallpaper_normal() {
128         // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
129         // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
130         int bitmapSide = DISPLAY_WIDTH;
131         testSurfaceHelper(
132                 bitmapSide /* bitmapWidth */,
133                 bitmapSide /* bitmapHeight */,
134                 bitmapSide /* expectedSurfaceWidth */,
135                 bitmapSide /* expectedSurfaceHeight */);
136     }
137 
138     @Test
testBitmapWallpaper_low_resolution()139     public void testBitmapWallpaper_low_resolution() {
140         // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
141         // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
142         testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */,
143                 LOW_BMP_HEIGHT /* bitmapHeight */,
144                 LOW_BMP_WIDTH /* expectedSurfaceWidth */,
145                 LOW_BMP_HEIGHT /* expectedSurfaceHeight */);
146     }
147 
148     @Test
testBitmapWallpaper_too_small()149     public void testBitmapWallpaper_too_small() {
150 
151         // test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
152         testMinSurfaceHelper(8, 8);
153         testMinSurfaceHelper(100, 2000);
154         testMinSurfaceHelper(200, 1);
155     }
156 
157     @Test
testLoadDrawAndUnloadBitmap()158     public void testLoadDrawAndUnloadBitmap() {
159         setBitmapDimensions(LOW_BMP_WIDTH, LOW_BMP_HEIGHT);
160 
161         ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
162         spyEngine.onCreate(mSurfaceHolder);
163         spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
164         assertThat(mFakeExecutor.numPending()).isAtLeast(1);
165 
166         int n = 0;
167         while (mFakeExecutor.numPending() >= 1) {
168             n++;
169             assertThat(n).isAtMost(10);
170             mFakeExecutor.runNextReady();
171             mFakeSystemClock.advanceTime(1000);
172         }
173 
174         verify(spyEngine, times(1)).drawFrameOnCanvas(mWallpaperBitmap);
175         assertThat(spyEngine.isBitmapLoaded()).isFalse();
176     }
177 
createImageWallpaper()178     private ImageWallpaper createImageWallpaper() {
179         return new ImageWallpaper(mFakeExecutor, mUserTracker) {
180             @Override
181             public Engine onCreateEngine() {
182                 return new CanvasEngine() {
183                     @Override
184                     public Context getDisplayContext() {
185                         return mMockContext;
186                     }
187 
188                     @Override
189                     public SurfaceHolder getSurfaceHolder() {
190                         return mSurfaceHolder;
191                     }
192 
193                     @Override
194                     public void setFixedSizeAllowed(boolean allowed) {
195                         super.setFixedSizeAllowed(allowed);
196                         assertWithMessage("mFixedSizeAllowed should be true").that(
197                                 allowed).isTrue();
198                     }
199                 };
200             }
201         };
202     }
203 
204     private ImageWallpaper.CanvasEngine getSpyEngine() {
205         ImageWallpaper imageWallpaper = createImageWallpaper();
206         ImageWallpaper.CanvasEngine engine =
207                 (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
208         ImageWallpaper.CanvasEngine spyEngine = spy(engine);
209         doNothing().when(spyEngine).drawFrameOnCanvas(any(Bitmap.class));
210         doNothing().when(spyEngine).reportEngineShown(anyBoolean());
211         doAnswer(invocation -> {
212             ((ImageWallpaper.CanvasEngine) invocation.getMock()).onMiniBitmapUpdated();
213             return null;
214         }).when(spyEngine).recomputeColorExtractorMiniBitmap();
215         return spyEngine;
216     }
217 
218     private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
219         when(mWallpaperManager.peekBitmapDimensions())
220                 .thenReturn(new Rect(0, 0, bitmapWidth, bitmapHeight));
221         when(mWallpaperBitmap.getWidth()).thenReturn(bitmapWidth);
222         when(mWallpaperBitmap.getHeight()).thenReturn(bitmapHeight);
223     }
224 
225     private void testMinSurfaceHelper(int bitmapWidth, int bitmapHeight) {
226         testSurfaceHelper(bitmapWidth, bitmapHeight,
227                 Math.max(ImageWallpaper.CanvasEngine.MIN_SURFACE_WIDTH, bitmapWidth),
228                 Math.max(ImageWallpaper.CanvasEngine.MIN_SURFACE_HEIGHT, bitmapHeight));
229     }
230 
231     private void testSurfaceHelper(int bitmapWidth, int bitmapHeight,
232             int expectedSurfaceWidth, int expectedSurfaceHeight) {
233 
234         clearInvocations(mSurfaceHolder);
235         setBitmapDimensions(bitmapWidth, bitmapHeight);
236 
237         ImageWallpaper imageWallpaper = createImageWallpaper();
238         ImageWallpaper.CanvasEngine engine =
239                 (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
240         engine.onCreate(mSurfaceHolder);
241 
242         verify(mSurfaceHolder, times(1)).setFixedSize(
243                 intThat(equalTo(expectedSurfaceWidth)),
244                 intThat(equalTo(expectedSurfaceHeight)));
245     }
246 }
247