1 /* 2 * Copyright (C) 2020 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.theme; 18 19 import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; 20 21 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; 22 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR; 23 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyInt; 29 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.Mockito.clearInvocations; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.reset; 34 import static org.mockito.Mockito.times; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.verifyNoMoreInteractions; 37 import static org.mockito.Mockito.when; 38 39 import android.app.ActivityManager; 40 import android.app.UiModeManager; 41 import android.app.WallpaperColors; 42 import android.app.WallpaperManager; 43 import android.content.BroadcastReceiver; 44 import android.content.Intent; 45 import android.content.om.FabricatedOverlay; 46 import android.content.om.OverlayIdentifier; 47 import android.content.res.Resources; 48 import android.database.ContentObserver; 49 import android.graphics.Color; 50 import android.os.Handler; 51 import android.os.UserHandle; 52 import android.os.UserManager; 53 import android.provider.Settings; 54 import android.testing.AndroidTestingRunner; 55 56 import androidx.annotation.VisibleForTesting; 57 import androidx.test.filters.SmallTest; 58 59 import com.android.systemui.SysuiTestCase; 60 import com.android.systemui.broadcast.BroadcastDispatcher; 61 import com.android.systemui.dump.DumpManager; 62 import com.android.systemui.flags.FeatureFlags; 63 import com.android.systemui.flags.Flags; 64 import com.android.systemui.keyguard.WakefulnessLifecycle; 65 import com.android.systemui.monet.Style; 66 import com.android.systemui.settings.UserTracker; 67 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 68 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; 69 import com.android.systemui.util.settings.SecureSettings; 70 71 import com.google.common.util.concurrent.MoreExecutors; 72 73 import org.junit.Before; 74 import org.junit.Test; 75 import org.junit.runner.RunWith; 76 import org.mockito.ArgumentCaptor; 77 import org.mockito.Captor; 78 import org.mockito.Mock; 79 import org.mockito.MockitoAnnotations; 80 81 import java.util.Arrays; 82 import java.util.List; 83 import java.util.Map; 84 import java.util.concurrent.Executor; 85 86 @SmallTest 87 @RunWith(AndroidTestingRunner.class) 88 public class ThemeOverlayControllerTest extends SysuiTestCase { 89 90 private static final int USER_SYSTEM = UserHandle.USER_SYSTEM; 91 private static final int USER_SECONDARY = 10; 92 93 private ThemeOverlayController mThemeOverlayController; 94 @Mock 95 private Executor mBgExecutor; 96 @Mock 97 private Executor mMainExecutor; 98 @Mock 99 private BroadcastDispatcher mBroadcastDispatcher; 100 @Mock 101 private Handler mBgHandler; 102 @Mock 103 private ThemeOverlayApplier mThemeOverlayApplier; 104 @Mock 105 private SecureSettings mSecureSettings; 106 @Mock 107 private WallpaperManager mWallpaperManager; 108 @Mock 109 private UserManager mUserManager; 110 @Mock 111 private UserTracker mUserTracker; 112 @Mock 113 private DumpManager mDumpManager; 114 @Mock 115 private DeviceProvisionedController mDeviceProvisionedController; 116 @Mock 117 private FeatureFlags mFeatureFlags; 118 @Mock 119 private Resources mResources; 120 @Mock 121 private WakefulnessLifecycle mWakefulnessLifecycle; 122 @Mock 123 private UiModeManager mUiModeManager; 124 @Mock 125 private ActivityManager mActivityManager; 126 @Captor 127 private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver; 128 @Captor 129 private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener; 130 @Captor 131 private ArgumentCaptor<DeviceProvisionedListener> mDeviceProvisionedListener; 132 @Captor 133 private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessLifecycleObserver; 134 @Captor 135 private ArgumentCaptor<UserTracker.Callback> mUserTrackerCallback; 136 @Captor 137 private ArgumentCaptor<ContentObserver> mSettingsObserver; 138 139 @Before setup()140 public void setup() { 141 MockitoAnnotations.initMocks(this); 142 when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true); 143 when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE); 144 when(mUiModeManager.getContrast()).thenReturn(0.5f); 145 when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); 146 when(mResources.getColor(eq(android.R.color.system_accent1_500), any())) 147 .thenReturn(Color.RED); 148 when(mResources.getColor(eq(android.R.color.system_accent2_500), any())) 149 .thenReturn(Color.GREEN); 150 when(mResources.getColor(eq(android.R.color.system_accent3_500), any())) 151 .thenReturn(Color.BLUE); 152 when(mResources.getColor(eq(android.R.color.system_neutral1_500), any())) 153 .thenReturn(Color.YELLOW); 154 when(mResources.getColor(eq(android.R.color.system_neutral2_500), any())) 155 .thenReturn(Color.BLACK); 156 mThemeOverlayController = new ThemeOverlayController(mContext, 157 mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier, 158 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, 159 mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, 160 mUiModeManager, mActivityManager) { 161 @VisibleForTesting 162 protected boolean isNightMode() { 163 return false; 164 } 165 166 @VisibleForTesting 167 protected FabricatedOverlay newFabricatedOverlay(String name) { 168 FabricatedOverlay overlay = mock(FabricatedOverlay.class); 169 when(overlay.getIdentifier()) 170 .thenReturn(new OverlayIdentifier( 171 Integer.toHexString(mColorScheme.getSeed() | 0xff000000))); 172 return overlay; 173 } 174 }; 175 176 mWakefulnessLifecycle.dispatchFinishedWakingUp(); 177 mThemeOverlayController.start(); 178 verify(mUserTracker).addCallback(mUserTrackerCallback.capture(), eq(mMainExecutor)); 179 verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null), 180 eq(UserHandle.USER_ALL)); 181 verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(), 182 eq(mMainExecutor), any()); 183 verify(mWakefulnessLifecycle).addObserver(mWakefulnessLifecycleObserver.capture()); 184 verify(mDumpManager).registerDumpable(any(), any()); 185 verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); 186 verify(mSecureSettings).registerContentObserverForUser( 187 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), 188 eq(false), mSettingsObserver.capture(), eq(UserHandle.USER_ALL) 189 ); 190 } 191 192 @Test start_checksWallpaper()193 public void start_checksWallpaper() { 194 ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class); 195 verify(mBgExecutor).execute(registrationRunnable.capture()); 196 197 registrationRunnable.getValue().run(); 198 verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM)); 199 } 200 201 @Test onWallpaperColorsChanged_setsTheme_whenForeground()202 public void onWallpaperColorsChanged_setsTheme_whenForeground() { 203 // Should ask for a new theme when wallpaper colors change 204 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 205 Color.valueOf(Color.BLUE), null); 206 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 207 USER_SYSTEM); 208 ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays = 209 ArgumentCaptor.forClass(Map.class); 210 211 verify(mThemeOverlayApplier) 212 .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); 213 214 // Assert that we received the colors that we were expecting 215 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) 216 .isEqualTo(new OverlayIdentifier("ffff0000")); 217 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR)) 218 .isEqualTo(new OverlayIdentifier("ffff0000")); 219 220 // Should not ask again if changed to same value 221 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 222 USER_SYSTEM); 223 verifyNoMoreInteractions(mThemeOverlayApplier); 224 225 // Should not ask again even for new colors until we change wallpapers 226 mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), 227 null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); 228 verifyNoMoreInteractions(mThemeOverlayApplier); 229 230 // But should change theme after changing wallpapers 231 clearInvocations(mThemeOverlayApplier); 232 Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 233 intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true); 234 mBroadcastReceiver.getValue().onReceive(null, intent); 235 mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), 236 null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); 237 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 238 } 239 240 @Test onWallpaperColorsChanged_setsTheme_skipWhenBackground()241 public void onWallpaperColorsChanged_setsTheme_skipWhenBackground() { 242 // Should ask for a new theme when wallpaper colors change 243 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 244 Color.valueOf(Color.BLUE), null); 245 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 246 USER_SYSTEM); 247 ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays = 248 ArgumentCaptor.forClass(Map.class); 249 250 verify(mThemeOverlayApplier) 251 .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); 252 253 // Should not change theme after changing wallpapers, if intent doesn't have 254 // WallpaperManager.EXTRA_FROM_FOREGROUND_APP set to true. 255 clearInvocations(mThemeOverlayApplier); 256 mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED)); 257 mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), 258 null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); 259 verify(mThemeOverlayApplier, never()) 260 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 261 } 262 263 @Test onWallpaperColorsChanged_preservesWallpaperPickerTheme()264 public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() { 265 // Should ask for a new theme when wallpaper colors change 266 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 267 Color.valueOf(Color.BLUE), null); 268 269 String jsonString = 270 "{\"android.theme.customization.system_palette\":\"override.package.name\"," 271 + "\"android.theme.customization.color_source\":\"preset\"}"; 272 when(mSecureSettings.getStringForUser( 273 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 274 .thenReturn(jsonString); 275 276 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 277 USER_SYSTEM); 278 ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays = 279 ArgumentCaptor.forClass(Map.class); 280 281 verify(mThemeOverlayApplier) 282 .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); 283 284 // Assert that we received the colors that we were expecting 285 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) 286 .isEqualTo(new OverlayIdentifier("override.package.name")); 287 } 288 289 @Test onWallpaperColorsChanged_resetThemeIfNotPreset()290 public void onWallpaperColorsChanged_resetThemeIfNotPreset() { 291 // Should ask for a new theme when wallpaper colors change 292 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 293 Color.valueOf(Color.BLUE), null); 294 295 String jsonString = 296 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 297 + "\"android.theme.customization.system_palette\":\"A16B00\"," 298 + "\"android.theme.customization.accent_color\":\"A16B00\"," 299 + "\"android.theme.customization.color_index\":\"2\"}"; 300 301 when(mSecureSettings.getStringForUser( 302 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 303 .thenReturn(jsonString); 304 305 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 306 USER_SYSTEM); 307 308 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 309 verify(mSecureSettings).putStringForUser( 310 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 311 anyInt()); 312 313 assertThat(updatedSetting.getValue().contains("android.theme.customization.accent_color")) 314 .isFalse(); 315 assertThat(updatedSetting.getValue().contains("android.theme.customization.system_palette")) 316 .isFalse(); 317 assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) 318 .isFalse(); 319 320 verify(mThemeOverlayApplier) 321 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 322 } 323 324 @Test onWallpaperColorsChanged_resetThemeWithNewHomeWallpapers()325 public void onWallpaperColorsChanged_resetThemeWithNewHomeWallpapers() { 326 // Should ask for a new theme when wallpaper colors change 327 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 328 Color.valueOf(Color.BLUE), null); 329 330 String jsonString = 331 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 332 + "\"android.theme.customization.system_palette\":\"A16B00\"," 333 + "\"android.theme.customization.accent_color\":\"A16B00\"," 334 + "\"android.theme.customization.color_index\":\"2\"}"; 335 336 when(mSecureSettings.getStringForUser( 337 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 338 .thenReturn(jsonString); 339 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 340 .thenReturn(20); 341 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 342 .thenReturn(21); 343 344 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 345 USER_SYSTEM); 346 347 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 348 verify(mSecureSettings).putStringForUser( 349 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 350 anyInt()); 351 352 assertThat(updatedSetting.getValue().contains( 353 "android.theme.customization.color_both\":\"0")).isTrue(); 354 355 verify(mThemeOverlayApplier) 356 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 357 } 358 359 @Test onWallpaperColorsChanged_keepsThemeWhenSetFromLockScreen()360 public void onWallpaperColorsChanged_keepsThemeWhenSetFromLockScreen() { 361 // Should ask for a new theme when wallpaper colors change 362 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 363 Color.valueOf(Color.BLUE), null); 364 String jsonString = 365 "{\"android.theme.customization.color_source\":\"lock_wallpaper\"," 366 + "\"android.theme.customization.system_palette\":\"A16B00\"," 367 + "\"android.theme.customization.accent_color\":\"A16B00\"," 368 + "\"android.theme.customization.color_index\":\"2\"}"; 369 when(mSecureSettings.getStringForUser( 370 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 371 .thenReturn(jsonString); 372 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 373 .thenReturn(20); 374 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 375 .thenReturn(21); 376 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 377 USER_SYSTEM); 378 verify(mSecureSettings, never()).putStringForUser( 379 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any(), anyInt()); 380 } 381 382 @Test onWallpaperColorsChanged_resetLockScreenThemeWhenBothSet()383 public void onWallpaperColorsChanged_resetLockScreenThemeWhenBothSet() { 384 // Should ask for a new theme when wallpaper colors change 385 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 386 Color.valueOf(Color.BLUE), null); 387 String jsonString = 388 "{\"android.theme.customization.color_source\":\"lock_wallpaper\"," 389 + "\"android.theme.customization.system_palette\":\"A16B00\"," 390 + "\"android.theme.customization.accent_color\":\"A16B00\"," 391 + "\"android.theme.customization.color_index\":\"2\"}"; 392 when(mSecureSettings.getStringForUser( 393 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 394 .thenReturn(jsonString); 395 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 396 .thenReturn(20); 397 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 398 .thenReturn(21); 399 400 mColorsListener.getValue().onColorsChanged(mainColors, 401 WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK, 402 USER_SYSTEM); 403 404 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 405 verify(mSecureSettings).putStringForUser( 406 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 407 anyInt()); 408 assertThat(updatedSetting.getValue().contains( 409 "android.theme.customization.color_both\":\"1")).isTrue(); 410 verify(mThemeOverlayApplier) 411 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 412 } 413 414 @Test onSettingChanged_honorThemeStyle()415 public void onSettingChanged_honorThemeStyle() { 416 when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true); 417 List<Style> validStyles = Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT, 418 Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT); 419 for (Style style : validStyles) { 420 reset(mSecureSettings); 421 422 String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\"," 423 + "\"android.theme.customization.theme_style\":\"" + style.name() + "\"}"; 424 425 when(mSecureSettings.getStringForUser( 426 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 427 .thenReturn(jsonString); 428 429 mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId()); 430 431 assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(style); 432 } 433 } 434 435 @Test onSettingChanged_invalidStyle()436 public void onSettingChanged_invalidStyle() { 437 when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true); 438 String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\"," 439 + "\"android.theme.customization.theme_style\":\"some_invalid_name\"}"; 440 441 when(mSecureSettings.getStringForUser( 442 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 443 .thenReturn(jsonString); 444 445 mSettingsObserver.getValue().onChange(true, null, 0, mUserTracker.getUserId()); 446 447 assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.TONAL_SPOT); 448 } 449 450 @Test onWallpaperColorsChanged_resetThemeWithNewHomeAndLockWallpaper()451 public void onWallpaperColorsChanged_resetThemeWithNewHomeAndLockWallpaper() { 452 // Should ask for a new theme when wallpaper colors change 453 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 454 Color.valueOf(Color.BLUE), null); 455 456 String jsonString = 457 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 458 + "\"android.theme.customization.system_palette\":\"A16B00\"," 459 + "\"android.theme.customization.accent_color\":\"A16B00\"," 460 + "\"android.theme.customization.color_index\":\"2\"}"; 461 462 when(mSecureSettings.getStringForUser( 463 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 464 .thenReturn(jsonString); 465 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 466 .thenReturn(-1); 467 468 mColorsListener.getValue().onColorsChanged(mainColors, 469 WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK, USER_SYSTEM); 470 471 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 472 verify(mSecureSettings).putStringForUser( 473 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 474 anyInt()); 475 476 assertThat(updatedSetting.getValue().contains( 477 "android.theme.customization.color_both\":\"1")).isTrue(); 478 479 verify(mThemeOverlayApplier) 480 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 481 } 482 483 @Test onWallpaperColorsChanged_changeLockWallpaper()484 public void onWallpaperColorsChanged_changeLockWallpaper() { 485 // Should ask for a new theme when wallpaper colors change 486 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 487 Color.valueOf(Color.BLUE), null); 488 String jsonString = 489 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 490 + "\"android.theme.customization.system_palette\":\"A16B00\"," 491 + "\"android.theme.customization.accent_color\":\"A16B00\"," 492 + "\"android.theme.customization.color_index\":\"2\"}"; 493 when(mSecureSettings.getStringForUser( 494 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 495 .thenReturn(jsonString); 496 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 497 .thenReturn(1); 498 499 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK, 500 USER_SYSTEM); 501 502 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 503 verify(mSecureSettings).putStringForUser( 504 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 505 anyInt()); 506 assertThat(updatedSetting.getValue().contains( 507 "android.theme.customization.color_source\":\"lock_wallpaper")).isTrue(); 508 assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) 509 .isFalse(); 510 verify(mThemeOverlayApplier) 511 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 512 } 513 514 @Test onWallpaperColorsChanged_changeHomeWallpaper()515 public void onWallpaperColorsChanged_changeHomeWallpaper() { 516 // Should ask for a new theme when wallpaper colors change 517 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 518 Color.valueOf(Color.BLUE), null); 519 String jsonString = 520 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 521 + "\"android.theme.customization.system_palette\":\"A16B00\"," 522 + "\"android.theme.customization.accent_color\":\"A16B00\"," 523 + "\"android.theme.customization.color_index\":\"2\"}"; 524 when(mSecureSettings.getStringForUser( 525 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 526 .thenReturn(jsonString); 527 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 528 .thenReturn(-1); 529 530 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 531 USER_SYSTEM); 532 533 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 534 verify(mSecureSettings).putStringForUser( 535 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 536 anyInt()); 537 assertThat(updatedSetting.getValue().contains( 538 "android.theme.customization.color_source\":\"home_wallpaper")).isTrue(); 539 assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index")) 540 .isFalse(); 541 verify(mThemeOverlayApplier) 542 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 543 } 544 545 @Test onWallpaperColorsChanged_resetThemeWhenFromLatestWallpaper()546 public void onWallpaperColorsChanged_resetThemeWhenFromLatestWallpaper() { 547 // Should ask for a new theme when the colors of the last applied wallpaper change 548 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 549 Color.valueOf(Color.BLUE), null); 550 551 String jsonString = 552 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 553 + "\"android.theme.customization.system_palette\":\"A16B00\"," 554 + "\"android.theme.customization.accent_color\":\"A16B00\"," 555 + "\"android.theme.customization.color_index\":\"2\"}"; 556 557 when(mSecureSettings.getStringForUser( 558 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 559 .thenReturn(jsonString); 560 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 561 .thenReturn(1); 562 // SYSTEM wallpaper is the last applied one 563 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 564 .thenReturn(2); 565 566 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 567 USER_SYSTEM); 568 569 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 570 verify(mSecureSettings).putStringForUser( 571 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(), 572 anyInt()); 573 574 verify(mThemeOverlayApplier) 575 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 576 } 577 578 @Test onWallpaperColorsChanged_keepThemeWhenFromLatestWallpaperAndSpecifiedColor()579 public void onWallpaperColorsChanged_keepThemeWhenFromLatestWallpaperAndSpecifiedColor() { 580 // Shouldn't ask for a new theme when the colors of the last applied wallpaper change 581 // with the same specified system palette one. 582 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 583 Color.valueOf(0xffa16b00), null); 584 585 String jsonString = 586 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 587 + "\"android.theme.customization.system_palette\":\"A16B00\"," 588 + "\"android.theme.customization.accent_color\":\"A16B00\"," 589 + "\"android.theme.customization.color_index\":\"2\"}"; 590 591 when(mSecureSettings.getStringForUser( 592 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 593 .thenReturn(jsonString); 594 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 595 .thenReturn(1); 596 // SYSTEM wallpaper is the last applied one 597 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 598 .thenReturn(2); 599 600 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 601 USER_SYSTEM); 602 603 ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class); 604 verify(mSecureSettings, never()).putString( 605 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture()); 606 607 // Apply overlay by existing theme from secure setting 608 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 609 } 610 611 @Test onWallpaperColorsChanged_keepThemeIfNotLatestWallpaper()612 public void onWallpaperColorsChanged_keepThemeIfNotLatestWallpaper() { 613 // Shouldn't ask for a new theme when the colors of the wallpaper that is not the last 614 // applied one change 615 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 616 Color.valueOf(Color.BLUE), null); 617 618 String jsonString = 619 "{\"android.theme.customization.color_source\":\"home_wallpaper\"," 620 + "\"android.theme.customization.system_palette\":\"A16B00\"," 621 + "\"android.theme.customization.accent_color\":\"A16B00\"," 622 + "\"android.theme.customization.color_index\":\"2\"}"; 623 624 when(mSecureSettings.getStringForUser( 625 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 626 .thenReturn(jsonString); 627 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM)) 628 .thenReturn(1); 629 // SYSTEM wallpaper is the last applied one 630 when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM)) 631 .thenReturn(2); 632 633 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK, 634 USER_SYSTEM); 635 636 verify(mSecureSettings, never()).putString( 637 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any()); 638 639 640 verify(mThemeOverlayApplier, never()) 641 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 642 } 643 644 @Test onUserSwitching_setsTheme()645 public void onUserSwitching_setsTheme() { 646 // Setup users with different colors 647 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), null, null); 648 WallpaperColors secondaryColors = 649 new WallpaperColors(Color.valueOf(Color.BLUE), null, null); 650 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 651 USER_SYSTEM); 652 mColorsListener.getValue().onColorsChanged(secondaryColors, WallpaperManager.FLAG_SYSTEM, 653 USER_SECONDARY); 654 655 // When changing users 656 clearInvocations(mThemeOverlayApplier); 657 when(mUserTracker.getUserId()).thenReturn(USER_SECONDARY); 658 mUserTrackerCallback.getValue().onUserChanged(USER_SECONDARY, mContext); 659 660 ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays = 661 ArgumentCaptor.forClass(Map.class); 662 verify(mThemeOverlayApplier) 663 .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); 664 665 // Assert that we received secondary user colors 666 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) 667 .isEqualTo(new OverlayIdentifier("ff0000ff")); 668 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR)) 669 .isEqualTo(new OverlayIdentifier("ff0000ff")); 670 } 671 672 @Test onProfileAdded_setsTheme()673 public void onProfileAdded_setsTheme() { 674 mBroadcastReceiver.getValue().onReceive(null, 675 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); 676 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 677 } 678 679 @Test onUserAdded_appliesTheme_ifNotManagedProfile()680 public void onUserAdded_appliesTheme_ifNotManagedProfile() { 681 reset(mDeviceProvisionedController); 682 when(mUserManager.isManagedProfile(anyInt())).thenReturn(false); 683 mBroadcastReceiver.getValue().onReceive(null, 684 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); 685 verify(mThemeOverlayApplier) 686 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 687 } 688 689 @Test onProfileAdded_ignoresUntilSetupComplete()690 public void onProfileAdded_ignoresUntilSetupComplete() { 691 reset(mDeviceProvisionedController); 692 when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); 693 mBroadcastReceiver.getValue().onReceive(null, 694 new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)); 695 verify(mThemeOverlayApplier, never()) 696 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 697 } 698 699 @Test onWallpaperColorsChanged_firstEventBeforeUserSetup_shouldBeAccepted()700 public void onWallpaperColorsChanged_firstEventBeforeUserSetup_shouldBeAccepted() { 701 // By default, on setup() we make this controller return that the user finished setup 702 // wizard. This test on the other hand, is testing the setup flow. 703 reset(mDeviceProvisionedController); 704 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 705 Color.valueOf(Color.BLUE), null); 706 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 707 USER_SYSTEM); 708 709 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 710 711 // Regression test: null events should not reset the internal state and allow colors to be 712 // applied again. 713 clearInvocations(mThemeOverlayApplier); 714 Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 715 intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true); 716 mBroadcastReceiver.getValue().onReceive(null, intent); 717 mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); 718 verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), 719 any(), any()); 720 mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), 721 null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); 722 verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), 723 any(), any()); 724 } 725 726 @Test catchException_whenPackageNameIsOverlayName()727 public void catchException_whenPackageNameIsOverlayName() { 728 mDeviceProvisionedController = mock(DeviceProvisionedController.class); 729 mThemeOverlayApplier = mock(ThemeOverlayApplier.class); 730 mWallpaperManager = mock(WallpaperManager.class); 731 732 // Assume we have some wallpaper colors at boot. 733 when(mWallpaperManager.getWallpaperColors(anyInt())) 734 .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null)); 735 736 Executor executor = MoreExecutors.directExecutor(); 737 738 mThemeOverlayController = new ThemeOverlayController(mContext, 739 mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, 740 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, 741 mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, 742 mUiModeManager, mActivityManager) { 743 @VisibleForTesting 744 protected boolean isNightMode() { 745 return false; 746 } 747 748 @VisibleForTesting 749 protected FabricatedOverlay newFabricatedOverlay(String name) { 750 FabricatedOverlay overlay = mock(FabricatedOverlay.class); 751 when(overlay.getIdentifier()) 752 .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever")); 753 return overlay; 754 } 755 }; 756 mThemeOverlayController.start(); 757 758 verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null), 759 eq(UserHandle.USER_ALL)); 760 verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); 761 762 // Colors were applied during controller initialization. 763 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 764 clearInvocations(mThemeOverlayApplier); 765 } 766 767 @Test onWallpaperColorsChanged_defersUntilSetupIsCompleted_ifHasColors()768 public void onWallpaperColorsChanged_defersUntilSetupIsCompleted_ifHasColors() { 769 mDeviceProvisionedController = mock(DeviceProvisionedController.class); 770 mThemeOverlayApplier = mock(ThemeOverlayApplier.class); 771 mWallpaperManager = mock(WallpaperManager.class); 772 773 // Assume we have some wallpaper colors at boot. 774 when(mWallpaperManager.getWallpaperColors(anyInt())) 775 .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null)); 776 777 Executor executor = MoreExecutors.directExecutor(); 778 mThemeOverlayController = new ThemeOverlayController(mContext, 779 mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, 780 mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, 781 mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, 782 mUiModeManager, mActivityManager) { 783 @VisibleForTesting 784 protected boolean isNightMode() { 785 return false; 786 } 787 788 @VisibleForTesting 789 protected FabricatedOverlay newFabricatedOverlay(String name) { 790 FabricatedOverlay overlay = mock(FabricatedOverlay.class); 791 when(overlay.getIdentifier()) 792 .thenReturn(new OverlayIdentifier( 793 Integer.toHexString(mColorScheme.getSeed() | 0xff000000))); 794 return overlay; 795 } 796 }; 797 mThemeOverlayController.start(); 798 verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null), 799 eq(UserHandle.USER_ALL)); 800 verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture()); 801 802 // Colors were applied during controller initialization. 803 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 804 clearInvocations(mThemeOverlayApplier); 805 806 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 807 Color.valueOf(Color.BLUE), null); 808 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 809 USER_SYSTEM); 810 811 reset(mResources); 812 when(mResources.getColor(eq(android.R.color.system_accent1_500), any())) 813 .thenReturn(mThemeOverlayController.mColorScheme.getAccent1().getS500()); 814 when(mResources.getColor(eq(android.R.color.system_accent2_500), any())) 815 .thenReturn(mThemeOverlayController.mColorScheme.getAccent2().getS500()); 816 when(mResources.getColor(eq(android.R.color.system_accent3_500), any())) 817 .thenReturn(mThemeOverlayController.mColorScheme.getAccent3().getS500()); 818 when(mResources.getColor(eq(android.R.color.system_neutral1_500), any())) 819 .thenReturn(mThemeOverlayController.mColorScheme.getNeutral1().getS500()); 820 when(mResources.getColor(eq(android.R.color.system_neutral2_500), any())) 821 .thenReturn(mThemeOverlayController.mColorScheme.getNeutral2().getS500()); 822 823 // Defers event because we already have initial colors. 824 verify(mThemeOverlayApplier, never()) 825 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 826 827 // Then event happens after setup phase is over. 828 when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); 829 mDeviceProvisionedListener.getValue().onUserSetupChanged(); 830 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 831 } 832 833 @Test onWallpaperColorsChanged_screenOff_deviceSetupNotFinished_doesNotProcessQueued()834 public void onWallpaperColorsChanged_screenOff_deviceSetupNotFinished_doesNotProcessQueued() { 835 when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false); 836 mDeviceProvisionedListener.getValue().onUserSetupChanged(); 837 838 839 // Second color application is not applied. 840 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 841 Color.valueOf(Color.BLUE), null); 842 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 843 USER_SYSTEM); 844 845 clearInvocations(mThemeOverlayApplier); 846 847 // Device went to sleep and second set of colors was applied. 848 mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), 849 Color.valueOf(Color.RED), null); 850 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 851 USER_SYSTEM); 852 verify(mThemeOverlayApplier, never()) 853 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 854 855 mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); 856 verify(mThemeOverlayApplier, never()) 857 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 858 } 859 860 @Test onWallpaperColorsChanged_screenOff_processesQueued()861 public void onWallpaperColorsChanged_screenOff_processesQueued() { 862 when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); 863 mDeviceProvisionedListener.getValue().onUserSetupChanged(); 864 865 // Second color application is not applied. 866 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 867 Color.valueOf(Color.BLUE), null); 868 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 869 USER_SYSTEM); 870 871 clearInvocations(mThemeOverlayApplier); 872 873 // Device went to sleep and second set of colors was applied. 874 mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), 875 Color.valueOf(Color.RED), null); 876 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 877 USER_SYSTEM); 878 verify(mThemeOverlayApplier, never()) 879 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 880 881 mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep(); 882 verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 883 } 884 885 @Test onWallpaperColorsChanged_parsesColorsFromWallpaperPicker()886 public void onWallpaperColorsChanged_parsesColorsFromWallpaperPicker() { 887 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 888 Color.valueOf(Color.BLUE), null); 889 890 String jsonString = 891 "{\"android.theme.customization.system_palette\":\"00FF00\"}"; 892 when(mSecureSettings.getStringForUser( 893 eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) 894 .thenReturn(jsonString); 895 896 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 897 USER_SYSTEM); 898 ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays = 899 ArgumentCaptor.forClass(Map.class); 900 901 verify(mThemeOverlayApplier) 902 .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any()); 903 904 // Assert that we received the colors that we were expecting 905 assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) 906 .isEqualTo(new OverlayIdentifier("ff00ff00")); 907 } 908 909 // Regression test for b/234603929, where a reboot would generate a wallpaper colors changed 910 // event for the already-set colors that would then set the theme incorrectly on screen sleep. 911 @Test onWallpaperColorsSetToSame_keepsTheme()912 public void onWallpaperColorsSetToSame_keepsTheme() { 913 // Set initial colors and verify. 914 WallpaperColors startingColors = new WallpaperColors(Color.valueOf(Color.RED), 915 Color.valueOf(Color.BLUE), null); 916 WallpaperColors sameColors = new WallpaperColors(Color.valueOf(Color.RED), 917 Color.valueOf(Color.BLUE), null); 918 mColorsListener.getValue().onColorsChanged(startingColors, WallpaperManager.FLAG_SYSTEM, 919 USER_SYSTEM); 920 verify(mThemeOverlayApplier) 921 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 922 clearInvocations(mThemeOverlayApplier); 923 924 // Set to the same colors. 925 mColorsListener.getValue().onColorsChanged(sameColors, WallpaperManager.FLAG_SYSTEM, 926 USER_SYSTEM); 927 verify(mThemeOverlayApplier, never()) 928 .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any()); 929 930 // Verify that no change resulted. 931 mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep(); 932 verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(), 933 any(), any()); 934 } 935 936 @Test createDynamicOverlay_addsAllDynamicColors()937 public void createDynamicOverlay_addsAllDynamicColors() { 938 // Trigger new wallpaper colors to generate an overlay 939 WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), 940 Color.valueOf(Color.BLUE), null); 941 mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, 942 USER_SYSTEM); 943 ArgumentCaptor<FabricatedOverlay[]> themeOverlays = 944 ArgumentCaptor.forClass(FabricatedOverlay[].class); 945 946 verify(mThemeOverlayApplier) 947 .applyCurrentUserOverlays(any(), themeOverlays.capture(), anyInt(), any(), any()); 948 949 FabricatedOverlay[] overlays = themeOverlays.getValue(); 950 FabricatedOverlay accents = overlays[0]; 951 FabricatedOverlay neutrals = overlays[1]; 952 FabricatedOverlay dynamic = overlays[2]; 953 954 final int colorsPerPalette = 12; 955 956 // Color resources were added for all 3 accent palettes 957 verify(accents, times(colorsPerPalette * 3)) 958 .setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); 959 // Color resources were added for all 2 neutral palettes 960 verify(neutrals, times(colorsPerPalette * 2)) 961 .setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); 962 // All dynamic colors were added twice: light and dark them 963 // All fixed colors were added once 964 verify(dynamic, times( 965 DynamicColors.allDynamicColorsMapped(false).size() * 2 966 + DynamicColors.getFixedColorsMapped(false).size()) 967 ).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); 968 } 969 } 970