1 /* 2 * Copyright (C) 2019 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.wallpaper; 18 19 import static android.app.WallpaperManager.COMMAND_REAPPLY; 20 import static android.app.WallpaperManager.FLAG_LOCK; 21 import static android.app.WallpaperManager.FLAG_SYSTEM; 22 import static android.os.FileObserver.CLOSE_WRITE; 23 import static android.os.UserHandle.MIN_SECONDARY_USER_ID; 24 import static android.os.UserHandle.USER_SYSTEM; 25 import static android.view.Display.DEFAULT_DISPLAY; 26 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 33 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; 34 35 import static org.hamcrest.core.IsNot.not; 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertNotEquals; 38 import static org.junit.Assert.assertNotNull; 39 import static org.junit.Assert.assertNull; 40 import static org.junit.Assert.assertTrue; 41 import static org.junit.Assert.fail; 42 import static org.junit.Assume.assumeThat; 43 import static org.mockito.ArgumentMatchers.any; 44 import static org.mockito.ArgumentMatchers.anyBoolean; 45 import static org.mockito.ArgumentMatchers.anyInt; 46 import static org.mockito.ArgumentMatchers.anyLong; 47 import static org.mockito.ArgumentMatchers.eq; 48 import static org.mockito.Mockito.reset; 49 import static org.mockito.Mockito.verify; 50 51 import android.app.AppGlobals; 52 import android.app.AppOpsManager; 53 import android.app.WallpaperColors; 54 import android.app.WallpaperManager; 55 import android.content.ComponentName; 56 import android.content.Context; 57 import android.content.Intent; 58 import android.content.pm.IPackageManager; 59 import android.content.pm.PackageManager; 60 import android.content.pm.ParceledListSlice; 61 import android.content.pm.ServiceInfo; 62 import android.graphics.Color; 63 import android.hardware.display.DisplayManager; 64 import android.os.ParcelFileDescriptor; 65 import android.os.RemoteException; 66 import android.os.SystemClock; 67 import android.platform.test.annotations.Presubmit; 68 import android.service.wallpaper.IWallpaperConnection; 69 import android.service.wallpaper.IWallpaperEngine; 70 import android.service.wallpaper.WallpaperService; 71 import android.testing.TestableContext; 72 import android.util.Log; 73 import android.util.SparseArray; 74 import android.util.Xml; 75 import android.view.Display; 76 77 import androidx.test.platform.app.InstrumentationRegistry; 78 import androidx.test.runner.AndroidJUnit4; 79 80 import com.android.dx.mockito.inline.extended.ExtendedMockito; 81 import com.android.dx.mockito.inline.extended.StaticMockitoSession; 82 import com.android.internal.R; 83 import com.android.modules.utils.TypedXmlPullParser; 84 import com.android.modules.utils.TypedXmlSerializer; 85 import com.android.server.LocalServices; 86 import com.android.server.wm.WindowManagerInternal; 87 88 import org.hamcrest.CoreMatchers; 89 import org.junit.After; 90 import org.junit.AfterClass; 91 import org.junit.Before; 92 import org.junit.BeforeClass; 93 import org.junit.ClassRule; 94 import org.junit.Rule; 95 import org.junit.Test; 96 import org.junit.rules.TemporaryFolder; 97 import org.junit.runner.RunWith; 98 import org.mockito.Mock; 99 import org.mockito.MockitoAnnotations; 100 import org.mockito.quality.Strictness; 101 import org.xmlpull.v1.XmlPullParserException; 102 103 import java.io.ByteArrayOutputStream; 104 import java.io.File; 105 import java.io.FileInputStream; 106 import java.io.FileOutputStream; 107 import java.io.IOException; 108 import java.nio.charset.StandardCharsets; 109 import java.util.List; 110 111 /** 112 * Tests for the {@link WallpaperManagerService} class. 113 * 114 * Build/Install/Run: 115 * atest FrameworksMockingServicesTests:WallpaperManagerServiceTests 116 */ 117 @Presubmit 118 @RunWith(AndroidJUnit4.class) 119 public class WallpaperManagerServiceTests { 120 121 private static final String TAG = "WallpaperManagerServiceTests"; 122 private static final int DISPLAY_SIZE_DIMENSION = 100; 123 private static StaticMockitoSession sMockitoSession; 124 125 @ClassRule 126 public static final TestableContext sContext = new TestableContext( 127 InstrumentationRegistry.getInstrumentation().getTargetContext(), null); 128 private static ComponentName sImageWallpaperComponentName; 129 private static ComponentName sDefaultWallpaperComponent; 130 131 private IPackageManager mIpm = AppGlobals.getPackageManager(); 132 133 @Mock 134 private DisplayManager mDisplayManager; 135 136 @Rule 137 public final TemporaryFolder mFolder = new TemporaryFolder(); 138 private final SparseArray<File> mTempDirs = new SparseArray<>(); 139 private WallpaperManagerService mService; 140 private static IWallpaperConnection.Stub sWallpaperService; 141 142 @BeforeClass setUpClass()143 public static void setUpClass() { 144 sMockitoSession = mockitoSession() 145 .strictness(Strictness.LENIENT) 146 .spyStatic(WallpaperUtils.class) 147 .spyStatic(LocalServices.class) 148 .spyStatic(WallpaperManager.class) 149 .startMocking(); 150 151 final WindowManagerInternal dmi = mock(WindowManagerInternal.class); 152 LocalServices.addService(WindowManagerInternal.class, dmi); 153 154 sContext.addMockSystemService(Context.APP_OPS_SERVICE, mock(AppOpsManager.class)); 155 156 spyOn(sContext); 157 sContext.getTestablePermissions().setPermission( 158 android.Manifest.permission.SET_WALLPAPER_COMPONENT, 159 PackageManager.PERMISSION_GRANTED); 160 sContext.getTestablePermissions().setPermission( 161 android.Manifest.permission.SET_WALLPAPER, 162 PackageManager.PERMISSION_GRANTED); 163 sContext.getTestablePermissions().setPermission( 164 android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT, 165 PackageManager.PERMISSION_GRANTED); 166 sContext.getTestablePermissions().setPermission( 167 android.Manifest.permission.READ_WALLPAPER_INTERNAL, 168 PackageManager.PERMISSION_GRANTED); 169 doNothing().when(sContext).sendBroadcastAsUser(any(), any()); 170 171 //Wallpaper components 172 sWallpaperService = mock(IWallpaperConnection.Stub.class); 173 sImageWallpaperComponentName = ComponentName.unflattenFromString( 174 sContext.getResources().getString(R.string.image_wallpaper_component)); 175 // Mock default wallpaper as image wallpaper if there is no pre-defined default wallpaper. 176 sDefaultWallpaperComponent = WallpaperManager.getCmfDefaultWallpaperComponent(sContext); 177 178 if (sDefaultWallpaperComponent == null) { 179 sDefaultWallpaperComponent = sImageWallpaperComponentName; 180 doReturn(sImageWallpaperComponentName).when(() -> 181 WallpaperManager.getCmfDefaultWallpaperComponent(any())); 182 } else { 183 sContext.addMockService(sDefaultWallpaperComponent, sWallpaperService); 184 } 185 186 sContext.addMockService(sImageWallpaperComponentName, sWallpaperService); 187 } 188 189 @AfterClass tearDownClass()190 public static void tearDownClass() { 191 if (sMockitoSession != null) { 192 sMockitoSession.finishMocking(); 193 sMockitoSession = null; 194 } 195 LocalServices.removeServiceForTest(WindowManagerInternal.class); 196 sImageWallpaperComponentName = null; 197 sDefaultWallpaperComponent = null; 198 reset(sContext); 199 } 200 201 @Before setUp()202 public void setUp() { 203 MockitoAnnotations.initMocks(this); 204 ExtendedMockito.doAnswer(invocation -> { 205 int userId = (invocation.getArgument(0)); 206 return getWallpaperTestDir(userId); 207 }).when(() -> WallpaperUtils.getWallpaperDir(anyInt())); 208 209 sContext.addMockSystemService(DisplayManager.class, mDisplayManager); 210 211 final Display mockDisplay = mock(Display.class); 212 doReturn(DISPLAY_SIZE_DIMENSION).when(mockDisplay).getMaximumSizeDimension(); 213 doReturn(mockDisplay).when(mDisplayManager).getDisplay(anyInt()); 214 215 final Display[] displays = new Display[]{mockDisplay}; 216 doReturn(displays).when(mDisplayManager).getDisplays(); 217 218 spyOn(mIpm); 219 mService = new TestWallpaperManagerService(sContext); 220 spyOn(mService); 221 mService.systemReady(); 222 } 223 224 @After tearDown()225 public void tearDown() { 226 LocalServices.removeServiceForTest(WallpaperManagerInternal.class); 227 228 mTempDirs.clear(); 229 reset(mIpm); 230 mService = null; 231 } 232 getWallpaperTestDir(int userId)233 private File getWallpaperTestDir(int userId) { 234 File tempDir = mTempDirs.get(userId); 235 if (tempDir == null) { 236 try { 237 tempDir = mFolder.newFolder(String.valueOf(userId)); 238 mTempDirs.append(userId, tempDir); 239 } catch (IOException e) { 240 Log.e(TAG, "getWallpaperTestDir failed at userId= " + userId); 241 } 242 } 243 return tempDir; 244 } 245 246 protected class TestWallpaperManagerService extends WallpaperManagerService { 247 TestWallpaperManagerService(Context context)248 TestWallpaperManagerService(Context context) { 249 super(context); 250 } 251 252 // Always return true for test 253 @Override isWallpaperSupported(String callingPackage)254 public boolean isWallpaperSupported(String callingPackage) { 255 return true; 256 } 257 258 // Always return true for test 259 @Override isSetWallpaperAllowed(String callingPackage)260 public boolean isSetWallpaperAllowed(String callingPackage) { 261 return true; 262 } 263 } 264 265 /** 266 * Tests that the fundamental fields are set by the main WallpaperData constructor 267 */ 268 @Test testWallpaperDataConstructor()269 public void testWallpaperDataConstructor() { 270 final int testUserId = MIN_SECONDARY_USER_ID; 271 for (int which: List.of(FLAG_LOCK, FLAG_SYSTEM)) { 272 WallpaperData newWallpaperData = new WallpaperData(testUserId, which); 273 assertEquals(which, newWallpaperData.mWhich); 274 assertEquals(testUserId, newWallpaperData.userId); 275 276 WallpaperData wallpaperData = mService.getWallpaperSafeLocked(testUserId, which); 277 assertEquals(wallpaperData.getCropFile().getAbsolutePath(), 278 newWallpaperData.getCropFile().getAbsolutePath()); 279 assertEquals(wallpaperData.getWallpaperFile().getAbsolutePath(), 280 newWallpaperData.getWallpaperFile().getAbsolutePath()); 281 } 282 } 283 284 /** 285 * Tests that internal basic data should be correct after boot up. 286 */ 287 @Test testDataCorrectAfterBoot()288 public void testDataCorrectAfterBoot() { 289 mService.switchUser(USER_SYSTEM, null); 290 291 final WallpaperData fallbackData = mService.mFallbackWallpaper; 292 assertEquals("Fallback wallpaper component should be ImageWallpaper.", 293 sImageWallpaperComponentName, fallbackData.wallpaperComponent); 294 295 verifyLastWallpaperData(USER_SYSTEM, sDefaultWallpaperComponent); 296 verifyDisplayData(); 297 } 298 299 /** 300 * Tests setWallpaperComponent and clearWallpaper should work as expected. 301 */ 302 @Test testSetThenClearComponent()303 public void testSetThenClearComponent() { 304 // Skip if there is no pre-defined default wallpaper component. 305 assumeThat(sDefaultWallpaperComponent, 306 not(CoreMatchers.equalTo(sImageWallpaperComponentName))); 307 308 final int testUserId = USER_SYSTEM; 309 mService.switchUser(testUserId, null); 310 verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); 311 verifyCurrentSystemData(testUserId); 312 313 mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), 314 FLAG_SYSTEM, testUserId); 315 verifyLastWallpaperData(testUserId, sImageWallpaperComponentName); 316 verifyCurrentSystemData(testUserId); 317 318 mService.clearWallpaper(null, FLAG_SYSTEM, testUserId); 319 verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); 320 verifyCurrentSystemData(testUserId); 321 } 322 323 /** 324 * Tests that when setWallpaperComponent is called with the currently set component, a command 325 * is issued to the wallpaper. 326 */ 327 @Test testSetCurrentComponent()328 public void testSetCurrentComponent() throws Exception { 329 final int testUserId = USER_SYSTEM; 330 mService.switchUser(testUserId, null); 331 verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); 332 verifyCurrentSystemData(testUserId); 333 334 spyOn(mService.mWallpaperDisplayHelper); 335 doReturn(true).when(mService.mWallpaperDisplayHelper) 336 .isUsableDisplay(any(Display.class), 337 eq(mService.mLastWallpaper.connection.mClientUid)); 338 mService.mLastWallpaper.connection.attachEngine(mock(IWallpaperEngine.class), 339 DEFAULT_DISPLAY); 340 341 WallpaperManagerService.DisplayConnector connector = 342 mService.mLastWallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY); 343 mService.setWallpaperComponent(sDefaultWallpaperComponent, sContext.getOpPackageName(), 344 FLAG_SYSTEM, testUserId); 345 346 verify(connector.mEngine).dispatchWallpaperCommand( 347 eq(COMMAND_REAPPLY), anyInt(), anyInt(), anyInt(), any()); 348 } 349 350 /** 351 * Tests internal data should be correct and no crash after switch user continuously. 352 */ 353 @Test testSwitchMultipleUsers()354 public void testSwitchMultipleUsers() throws Exception { 355 final int lastUserId = 5; 356 final ServiceInfo pi = mIpm.getServiceInfo(sDefaultWallpaperComponent, 357 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, 0); 358 doReturn(pi).when(mIpm).getServiceInfo(any(), anyLong(), anyInt()); 359 360 final Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 361 final ParceledListSlice ris = 362 mIpm.queryIntentServices(intent, 363 intent.resolveTypeIfNeeded(sContext.getContentResolver()), 364 PackageManager.GET_META_DATA, 0); 365 doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyLong(), anyInt()); 366 doReturn(PackageManager.PERMISSION_GRANTED).when(mIpm).checkPermission( 367 eq(android.Manifest.permission.AMBIENT_WALLPAPER), any(), anyInt()); 368 369 for (int userId = 0; userId <= lastUserId; userId++) { 370 mService.switchUser(userId, null); 371 verifyLastWallpaperData(userId, sDefaultWallpaperComponent); 372 verifyCurrentSystemData(userId); 373 } 374 verifyNoConnectionBeforeLastUser(lastUserId); 375 } 376 377 /** 378 * Tests internal data should be correct and no crash after switch user + unlock user 379 * continuously. 380 * Simulating that the selected WallpaperService is not built-in. After switching users, the 381 * service should not be bound, but bound to the image wallpaper. After receiving the user 382 * unlock callback and can find the selected service for the user, the selected service should 383 * be bound. 384 */ 385 @Test testSwitchThenUnlockMultipleUsers()386 public void testSwitchThenUnlockMultipleUsers() throws Exception { 387 final int lastUserId = 5; 388 final ServiceInfo pi = mIpm.getServiceInfo(sDefaultWallpaperComponent, 389 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, 0); 390 doReturn(pi).when(mIpm).getServiceInfo(any(), anyLong(), anyInt()); 391 392 final Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 393 final ParceledListSlice ris = 394 mIpm.queryIntentServices(intent, 395 intent.resolveTypeIfNeeded(sContext.getContentResolver()), 396 PackageManager.GET_META_DATA, 0); 397 doReturn(PackageManager.PERMISSION_GRANTED).when(mIpm).checkPermission( 398 eq(android.Manifest.permission.AMBIENT_WALLPAPER), any(), anyInt()); 399 400 for (int userId = 1; userId <= lastUserId; userId++) { 401 mService.switchUser(userId, null); 402 verifyLastWallpaperData(userId, sImageWallpaperComponentName); 403 // Simulate user unlocked 404 doReturn(ris).when(mIpm).queryIntentServices(any(), any(), anyLong(), eq(userId)); 405 mService.onUnlockUser(userId); 406 verifyLastWallpaperData(userId, sDefaultWallpaperComponent); 407 verifyCurrentSystemData(userId); 408 } 409 verifyNoConnectionBeforeLastUser(lastUserId); 410 verifyDisplayData(); 411 } 412 413 @Test testXmlSerializationRoundtrip()414 public void testXmlSerializationRoundtrip() { 415 WallpaperData systemWallpaperData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0); 416 try { 417 TypedXmlSerializer serializer = Xml.newBinarySerializer(); 418 serializer.setOutput(new ByteArrayOutputStream(), StandardCharsets.UTF_8.name()); 419 serializer.startDocument(StandardCharsets.UTF_8.name(), true); 420 mService.mWallpaperDataParser.writeWallpaperAttributes( 421 serializer, "wp", systemWallpaperData); 422 } catch (IOException e) { 423 fail("exception occurred while writing system wallpaper attributes"); 424 } 425 426 WallpaperData shouldMatchSystem = new WallpaperData(0, FLAG_SYSTEM); 427 try { 428 TypedXmlPullParser parser = Xml.newBinaryPullParser(); 429 mService.mWallpaperDataParser.parseWallpaperAttributes(parser, shouldMatchSystem, true); 430 } catch (XmlPullParserException e) { 431 fail("exception occurred while parsing wallpaper"); 432 } 433 assertEquals(systemWallpaperData.primaryColors, shouldMatchSystem.primaryColors); 434 } 435 436 @Test testWallpaperManagerCallbackInRightOrder()437 public void testWallpaperManagerCallbackInRightOrder() throws RemoteException { 438 WallpaperData wallpaper = new WallpaperData(USER_SYSTEM, FLAG_SYSTEM); 439 wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.RED), 440 Color.valueOf(Color.BLUE), null); 441 442 spyOn(wallpaper); 443 doReturn(wallpaper).when(mService).getWallpaperSafeLocked(wallpaper.userId, FLAG_SYSTEM); 444 doNothing().when(mService).switchWallpaper(any(), any()); 445 doReturn(true).when(mService) 446 .bindWallpaperComponentLocked(any(), anyBoolean(), anyBoolean(), any(), any()); 447 doNothing().when(mService).saveSettingsLocked(wallpaper.userId); 448 spyOn(mService.mWallpaperCropper); 449 doNothing().when(mService.mWallpaperCropper).generateCrop(wallpaper); 450 451 // timestamps of {ACTION_WALLPAPER_CHANGED, onWallpaperColorsChanged} 452 final long[] timestamps = new long[2]; 453 doAnswer(invocation -> timestamps[0] = SystemClock.elapsedRealtime()) 454 .when(sContext).sendBroadcastAsUser(any(), any()); 455 doAnswer(invocation -> timestamps[1] = SystemClock.elapsedRealtime()) 456 .when(mService).notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM); 457 458 assertNull(wallpaper.wallpaperObserver); 459 mService.switchUser(wallpaper.userId, null); 460 assertNotNull(wallpaper.wallpaperObserver); 461 // We will call onEvent directly, so stop watching the file. 462 wallpaper.wallpaperObserver.stopWatching(); 463 464 spyOn(wallpaper.wallpaperObserver); 465 doReturn(wallpaper).when(wallpaper.wallpaperObserver).dataForEvent(true, false); 466 wallpaper.wallpaperObserver.onEvent(CLOSE_WRITE, WALLPAPER); 467 468 // ACTION_WALLPAPER_CHANGED should be invoked before onWallpaperColorsChanged. 469 assertTrue(timestamps[1] > timestamps[0]); 470 } 471 472 @Test testSetWallpaperDimAmount()473 public void testSetWallpaperDimAmount() throws RemoteException { 474 mService.switchUser(USER_SYSTEM, null); 475 float dimAmount = 0.7f; 476 mService.setWallpaperDimAmount(dimAmount); 477 assertEquals("Getting dim amount should match after setting the dim amount", 478 mService.getWallpaperDimAmount(), dimAmount, 0.0); 479 } 480 481 @Test testGetAdjustedWallpaperColorsOnDimming()482 public void testGetAdjustedWallpaperColorsOnDimming() throws RemoteException { 483 final int testUserId = USER_SYSTEM; 484 mService.switchUser(testUserId, null); 485 mService.setWallpaperComponent(sDefaultWallpaperComponent, sContext.getOpPackageName(), 486 FLAG_SYSTEM, testUserId); 487 WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId); 488 489 // Mock a wallpaper data with color hints that support dark text and dark theme 490 // but not HINT_FROM_BITMAP 491 wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.WHITE), null, null, 492 WallpaperColors.HINT_SUPPORTS_DARK_TEXT | WallpaperColors.HINT_SUPPORTS_DARK_THEME); 493 mService.setWallpaperDimAmount(0.6f); 494 int colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints(); 495 // Dimmed wallpaper not extracted from bitmap does not support dark text and dark theme 496 assertNotEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT, 497 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT); 498 assertNotEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME, 499 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME); 500 501 // Remove dimming 502 mService.setWallpaperDimAmount(0f); 503 colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints(); 504 // Undimmed wallpaper not extracted from bitmap does support dark text and dark theme 505 assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT, 506 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT); 507 assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME, 508 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME); 509 510 // Mock a wallpaper data with color hints that support dark text and dark theme 511 // and was extracted from bitmap 512 wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.WHITE), null, null, 513 WallpaperColors.HINT_SUPPORTS_DARK_TEXT | WallpaperColors.HINT_SUPPORTS_DARK_THEME 514 | WallpaperColors.HINT_FROM_BITMAP); 515 mService.setWallpaperDimAmount(0.6f); 516 colorHints = mService.getAdjustedWallpaperColorsOnDimming(wallpaper).getColorHints(); 517 // Dimmed wallpaper should still support dark text and dark theme 518 assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT, 519 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT); 520 assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_THEME, 521 colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME); 522 } 523 524 @Test getWallpaperWithFeature_getCropped_returnsCropFile()525 public void getWallpaperWithFeature_getCropped_returnsCropFile() throws Exception { 526 File cropSystemWallpaperFile = 527 new WallpaperData(USER_SYSTEM, FLAG_SYSTEM).getCropFile(); 528 cropSystemWallpaperFile.getParentFile().mkdirs(); 529 cropSystemWallpaperFile.createNewFile(); 530 try (FileOutputStream outputStream = new FileOutputStream(cropSystemWallpaperFile)) { 531 outputStream.write("Crop system wallpaper".getBytes()); 532 } 533 534 ParcelFileDescriptor pfd = 535 mService.getWallpaperWithFeature( 536 sContext.getPackageName(), 537 sContext.getAttributionTag(), 538 /* cb= */ null, 539 FLAG_SYSTEM, 540 /* outParams= */ null, 541 USER_SYSTEM, 542 /* getCropped= */ true); 543 544 assertPfdAndFileContentsEqual(pfd, cropSystemWallpaperFile); 545 } 546 547 @Test getWallpaperWithFeature_notGetCropped_returnsOriginalFile()548 public void getWallpaperWithFeature_notGetCropped_returnsOriginalFile() throws Exception { 549 File originalSystemWallpaperFile = 550 new WallpaperData(USER_SYSTEM, FLAG_SYSTEM).getWallpaperFile(); 551 originalSystemWallpaperFile.getParentFile().mkdirs(); 552 originalSystemWallpaperFile.createNewFile(); 553 try (FileOutputStream outputStream = new FileOutputStream(originalSystemWallpaperFile)) { 554 outputStream.write("Original system wallpaper".getBytes()); 555 } 556 557 ParcelFileDescriptor pfd = 558 mService.getWallpaperWithFeature( 559 sContext.getPackageName(), 560 sContext.getAttributionTag(), 561 /* cb= */ null, 562 FLAG_SYSTEM, 563 /* outParams= */ null, 564 USER_SYSTEM, 565 /* getCropped= */ false); 566 567 assertPfdAndFileContentsEqual(pfd, originalSystemWallpaperFile); 568 } 569 570 // Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for 571 // non-current user must not bind to wallpaper service. verifyNoConnectionBeforeLastUser(int lastUserId)572 private void verifyNoConnectionBeforeLastUser(int lastUserId) { 573 for (int i = 0; i < lastUserId; i++) { 574 final WallpaperData userData = mService.getCurrentWallpaperData(FLAG_SYSTEM, i); 575 assertNull("No user data connection left", userData.connection); 576 } 577 } 578 verifyLastWallpaperData(int lastUserId, ComponentName expectedComponent)579 private void verifyLastWallpaperData(int lastUserId, ComponentName expectedComponent) { 580 final WallpaperData lastData = mService.mLastWallpaper; 581 assertNotNull("Last wallpaper must not be null", lastData); 582 assertEquals("Last wallpaper component must be equals.", expectedComponent, 583 lastData.wallpaperComponent); 584 assertEquals("The user id in last wallpaper should be the last switched user", 585 lastUserId, lastData.userId); 586 assertNotNull("Must exist user data connection on last wallpaper data", 587 lastData.connection); 588 } 589 verifyCurrentSystemData(int userId)590 private void verifyCurrentSystemData(int userId) { 591 final WallpaperData lastData = mService.mLastWallpaper; 592 final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, userId); 593 assertEquals("Last wallpaper should be equals to current system wallpaper", 594 lastData, wallpaper); 595 } 596 verifyDisplayData()597 private void verifyDisplayData() { 598 mService.mWallpaperDisplayHelper.forEachDisplayData(data -> { 599 assertTrue("Display width must larger than maximum screen size", 600 data.mWidth >= DISPLAY_SIZE_DIMENSION); 601 assertTrue("Display height must larger than maximum screen size", 602 data.mHeight >= DISPLAY_SIZE_DIMENSION); 603 }); 604 } 605 606 /** 607 * Asserts that the contents of the given {@link ParcelFileDescriptor} and {@link File} contain 608 * exactly the same bytes. 609 * 610 * Both the PFD and File contents will be loaded to memory. The PFD will be closed at the end. 611 */ assertPfdAndFileContentsEqual(ParcelFileDescriptor pfd, File file)612 private static void assertPfdAndFileContentsEqual(ParcelFileDescriptor pfd, File file) 613 throws IOException { 614 try (ParcelFileDescriptor.AutoCloseInputStream pfdInputStream = 615 new ParcelFileDescriptor.AutoCloseInputStream(pfd); 616 FileInputStream fileInputStream = new FileInputStream(file) 617 ) { 618 String pfdContents = new String(pfdInputStream.readAllBytes()); 619 String fileContents = new String(fileInputStream.readAllBytes()); 620 assertEquals(pfdContents, fileContents); 621 } 622 } 623 } 624