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 android.server.wm; 18 19 import static android.app.UiModeManager.MODE_NIGHT_AUTO; 20 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM; 21 import static android.app.UiModeManager.MODE_NIGHT_NO; 22 import static android.app.UiModeManager.MODE_NIGHT_YES; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.content.Intent.ACTION_MAIN; 26 import static android.content.Intent.CATEGORY_HOME; 27 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 28 import static android.server.wm.CliIntentExtra.extraBool; 29 import static android.server.wm.CliIntentExtra.extraString; 30 import static android.server.wm.WindowManagerState.STATE_RESUMED; 31 import static android.server.wm.app.Components.HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY; 32 import static android.server.wm.app.Components.HOME_ACTIVITY; 33 import static android.server.wm.app.Components.SPLASHSCREEN_ACTIVITY; 34 import static android.server.wm.app.Components.SPLASH_SCREEN_REPLACE_ICON_ACTIVITY; 35 import static android.server.wm.app.Components.SPLASH_SCREEN_REPLACE_THEME_ACTIVITY; 36 import static android.server.wm.app.Components.TestActivity.COMMAND_START_ACTIVITY; 37 import static android.server.wm.app.Components.TestActivity.EXTRA_INTENT; 38 import static android.server.wm.app.Components.TestStartingWindowKeys.CANCEL_HANDLE_EXIT; 39 import static android.server.wm.app.Components.TestStartingWindowKeys.CENTER_VIEW_IS_SURFACE_VIEW; 40 import static android.server.wm.app.Components.TestStartingWindowKeys.CONTAINS_BRANDING_VIEW; 41 import static android.server.wm.app.Components.TestStartingWindowKeys.CONTAINS_CENTER_VIEW; 42 import static android.server.wm.app.Components.TestStartingWindowKeys.DELAY_RESUME; 43 import static android.server.wm.app.Components.TestStartingWindowKeys.GET_NIGHT_MODE_ACTIVITY_CHANGED; 44 import static android.server.wm.app.Components.TestStartingWindowKeys.HANDLE_SPLASH_SCREEN_EXIT; 45 import static android.server.wm.app.Components.TestStartingWindowKeys.ICON_ANIMATION_DURATION; 46 import static android.server.wm.app.Components.TestStartingWindowKeys.ICON_ANIMATION_START; 47 import static android.server.wm.app.Components.TestStartingWindowKeys.ICON_BACKGROUND_COLOR; 48 import static android.server.wm.app.Components.TestStartingWindowKeys.OVERRIDE_THEME_COLOR; 49 import static android.server.wm.app.Components.TestStartingWindowKeys.OVERRIDE_THEME_COMPONENT; 50 import static android.server.wm.app.Components.TestStartingWindowKeys.OVERRIDE_THEME_ENABLED; 51 import static android.server.wm.app.Components.TestStartingWindowKeys.RECEIVE_SPLASH_SCREEN_EXIT; 52 import static android.server.wm.app.Components.TestStartingWindowKeys.REPLACE_ICON_EXIT; 53 import static android.server.wm.app.Components.TestStartingWindowKeys.REQUEST_HANDLE_EXIT_ON_CREATE; 54 import static android.server.wm.app.Components.TestStartingWindowKeys.REQUEST_HANDLE_EXIT_ON_RESUME; 55 import static android.server.wm.app.Components.TestStartingWindowKeys.REQUEST_SET_NIGHT_MODE_ON_CREATE; 56 import static android.view.Display.DEFAULT_DISPLAY; 57 import static android.view.WindowInsets.Type.captionBar; 58 import static android.view.WindowInsets.Type.systemBars; 59 60 import static org.hamcrest.MatcherAssert.assertThat; 61 import static org.hamcrest.Matchers.greaterThanOrEqualTo; 62 import static org.hamcrest.Matchers.lessThanOrEqualTo; 63 import static org.junit.Assert.assertEquals; 64 import static org.junit.Assert.assertFalse; 65 import static org.junit.Assert.assertTrue; 66 import static org.junit.Assert.fail; 67 import static org.junit.Assume.assumeFalse; 68 import static org.junit.Assume.assumeTrue; 69 70 import android.app.UiModeManager; 71 import android.content.ComponentName; 72 import android.content.Intent; 73 import android.content.pm.LauncherApps; 74 import android.content.pm.ShortcutInfo; 75 import android.content.pm.ShortcutManager; 76 import android.content.res.Configuration; 77 import android.graphics.Bitmap; 78 import android.graphics.Color; 79 import android.graphics.Insets; 80 import android.graphics.Rect; 81 import android.os.Bundle; 82 import android.platform.test.annotations.Presubmit; 83 import android.view.WindowManager; 84 import android.view.WindowMetrics; 85 86 import androidx.core.graphics.ColorUtils; 87 88 import com.android.compatibility.common.util.TestUtils; 89 90 import org.junit.After; 91 import org.junit.Before; 92 import org.junit.Rule; 93 import org.junit.Test; 94 95 import java.util.Collections; 96 import java.util.function.Consumer; 97 98 /** 99 * Build/Install/Run: 100 * atest CtsWindowManagerDeviceTestCases:SplashscreenTests 101 */ 102 @Presubmit 103 @android.server.wm.annotation.Group1 104 public class SplashscreenTests extends ActivityManagerTestBase { 105 106 private static final int CENTER_ICON_SIZE = 192; 107 108 @Rule 109 public final DumpOnFailure dumpOnFailure = new DumpOnFailure(); 110 111 @Before setUp()112 public void setUp() throws Exception { 113 super.setUp(); 114 mWmState.setSanityCheckWithFocusedWindow(false); 115 mWmState.waitForDisplayUnfrozen(); 116 } 117 118 @After tearDown()119 public void tearDown() { 120 mWmState.setSanityCheckWithFocusedWindow(true); 121 } 122 prepareTestLauncher()123 private CommandSession.ActivitySession prepareTestLauncher() { 124 createManagedHomeActivitySession(HOME_ACTIVITY); 125 return createManagedActivityClientSession() 126 .startActivity(new Intent(ACTION_MAIN) 127 .addCategory(CATEGORY_HOME) 128 .addFlags(FLAG_ACTIVITY_NEW_TASK) 129 .setComponent(HOME_ACTIVITY)); 130 } 131 startActivityFromTestLauncher(CommandSession.ActivitySession homeActivity, ComponentName componentName, Consumer<Intent> fillExtra)132 private void startActivityFromTestLauncher(CommandSession.ActivitySession homeActivity, 133 ComponentName componentName, Consumer<Intent> fillExtra) { 134 135 final Bundle data = new Bundle(); 136 final Intent startIntent = new Intent(); 137 startIntent.setComponent(componentName); 138 startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 139 fillExtra.accept(startIntent); 140 data.putParcelable(EXTRA_INTENT, startIntent); 141 homeActivity.sendCommand(COMMAND_START_ACTIVITY, data); 142 } 143 144 @Test testSplashscreenContent()145 public void testSplashscreenContent() { 146 // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly 147 // applied insets by system bars in AAOS. 148 assumeFalse(isCar()); 149 150 launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 151 // The windowSplashScreenContent attribute is set to RED. We check that it is ignored. 152 testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE); 153 } 154 155 @Test testSplashscreenContent_FreeformWindow()156 public void testSplashscreenContent_FreeformWindow() { 157 // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly 158 // applied insets by system bars in AAOS. 159 assumeFalse(isCar()); 160 assumeTrue(supportsFreeform()); 161 162 launchActivityNoWait(SPLASHSCREEN_ACTIVITY, WINDOWING_MODE_FREEFORM); 163 // The windowSplashScreenContent attribute is set to RED. We check that it is ignored. 164 testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLUE, Color.WHITE); 165 } 166 testSplashScreenColor(ComponentName name, int primaryColor, int secondaryColor)167 private void testSplashScreenColor(ComponentName name, int primaryColor, int secondaryColor) { 168 // Activity may not be launched yet even if app transition is in idle state. 169 mWmState.waitForActivityState(name, STATE_RESUMED); 170 mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY); 171 boolean isFullscreen = mWmState.getTaskByActivity(name).isWindowingModeCompatible( 172 WINDOWING_MODE_FULLSCREEN); 173 174 final Bitmap image = takeScreenshot(); 175 final WindowMetrics windowMetrics = mWm.getMaximumWindowMetrics(); 176 final Rect stableBounds = new Rect(windowMetrics.getBounds()); 177 Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility( 178 systemBars() & ~captionBar()); 179 stableBounds.inset(insets); 180 WindowManagerState.WindowState startingWindow = mWmState.findFirstWindowWithType( 181 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 182 183 Rect startingWindowBounds = startingWindow.getBounds(); 184 final Rect appBounds; 185 if (startingWindowBounds != null) { 186 appBounds = new Rect(startingWindowBounds); 187 } else { 188 appBounds = new Rect(startingWindow.getFrame()); 189 } 190 191 Rect topInsetsBounds = new Rect(insets.left, 0, appBounds.right - insets.right, insets.top); 192 Rect bottomInsetsBounds = new Rect(insets.left, appBounds.bottom - insets.bottom, 193 appBounds.right - insets.right, appBounds.bottom); 194 195 assertFalse("Couldn't find splash screen bounds. Impossible to assert the colors", 196 appBounds.isEmpty()); 197 198 // Use ratios to flexibly accommodate circular or not quite rectangular displays 199 // Note: Color.BLACK is the pixel color outside of the display region 200 201 int px = WindowManagerState.dpToPx(CENTER_ICON_SIZE, 202 mContext.getResources().getConfiguration().densityDpi); 203 Rect ignoreRect = new Rect(0, 0, px, px); 204 ignoreRect.offsetTo(appBounds.centerX() - ignoreRect.width() / 2, 205 appBounds.centerY() - ignoreRect.height() / 2); 206 207 appBounds.intersect(stableBounds); 208 assertColors(image, appBounds, primaryColor, 0.99f, secondaryColor, 0.02f, ignoreRect); 209 if (isFullscreen && !topInsetsBounds.isEmpty()) { 210 assertColors(image, topInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, null); 211 } 212 if (isFullscreen && !bottomInsetsBounds.isEmpty()) { 213 assertColors(image, bottomInsetsBounds, primaryColor, 0.80f, secondaryColor, 0.10f, 214 null); 215 } 216 } 217 218 // For real devices, gamma correction might be applied on hardware driver, so the colors may 219 // not exactly match. isSimilarColor(int a, int b)220 private static boolean isSimilarColor(int a, int b) { 221 if (a == b) { 222 return true; 223 } 224 return Math.abs(Color.alpha(a) - Color.alpha(b)) + 225 Math.abs(Color.red(a) - Color.red(b)) + 226 Math.abs(Color.green(a) - Color.green(b)) + 227 Math.abs(Color.blue(a) - Color.blue(b)) < 10; 228 } 229 assertColors(Bitmap img, Rect bounds, int primaryColor, float expectedPrimaryRatio, int secondaryColor, float acceptableWrongRatio, Rect ignoreRect)230 private void assertColors(Bitmap img, Rect bounds, int primaryColor, float expectedPrimaryRatio, 231 int secondaryColor, float acceptableWrongRatio, Rect ignoreRect) { 232 233 int primaryPixels = 0; 234 int secondaryPixels = 0; 235 int wrongPixels = 0; 236 237 assertThat(bounds.top, greaterThanOrEqualTo(0)); 238 assertThat(bounds.left, greaterThanOrEqualTo(0)); 239 assertThat(bounds.right, lessThanOrEqualTo(img.getWidth())); 240 assertThat(bounds.bottom, lessThanOrEqualTo(img.getHeight())); 241 242 for (int x = bounds.left; x < bounds.right; x++) { 243 for (int y = bounds.top; y < bounds.bottom; y++) { 244 if (ignoreRect != null && ignoreRect.contains(x, y)) { 245 continue; 246 } 247 final int color = img.getPixel(x, y); 248 if (isSimilarColor(primaryColor, color)) { 249 primaryPixels++; 250 } else if (isSimilarColor(secondaryColor, color)) { 251 secondaryPixels++; 252 } else { 253 wrongPixels++; 254 } 255 } 256 } 257 258 int totalPixels = bounds.width() * bounds.height(); 259 if (ignoreRect != null) { 260 totalPixels -= ignoreRect.width() * ignoreRect.height(); 261 } 262 263 final float primaryRatio = (float) primaryPixels / totalPixels; 264 if (primaryRatio < expectedPrimaryRatio) { 265 generateFailureImage(img, bounds, primaryColor, secondaryColor, ignoreRect); 266 fail("Less than " + (expectedPrimaryRatio * 100.0f) 267 + "% of pixels have non-primary color primaryPixels=" + primaryPixels 268 + " secondaryPixels=" + secondaryPixels + " wrongPixels=" + wrongPixels); 269 } 270 // Some pixels might be covered by screen shape decorations, like rounded corners. 271 // On circular displays, there is an antialiased edge. 272 final float wrongRatio = (float) wrongPixels / totalPixels; 273 if (wrongRatio > acceptableWrongRatio) { 274 generateFailureImage(img, bounds, primaryColor, secondaryColor, ignoreRect); 275 fail("More than " + (acceptableWrongRatio * 100.0f) 276 + "% of pixels have wrong color primaryPixels=" + primaryPixels 277 + " secondaryPixels=" + secondaryPixels + " wrongPixels=" 278 + wrongPixels); 279 } 280 } 281 generateFailureImage(Bitmap img, Rect bounds, int primaryColor, int secondaryColor, Rect ignoreRect)282 private void generateFailureImage(Bitmap img, Rect bounds, int primaryColor, 283 int secondaryColor, Rect ignoreRect) { 284 285 // Create a bitmap with on the left the original image and on the right the result of the 286 // test. The pixel marked in green have the right color, the transparent black one are 287 // ignored and the wrong pixels have the original color. 288 final int ignoredDebugColor = 0xEE000000; 289 final int validDebugColor = 0x6600FF00; 290 Bitmap result = Bitmap.createBitmap(img.getWidth() * 2, img.getHeight(), 291 Bitmap.Config.ARGB_8888); 292 293 // Execute the exact same logic applied in assertColor() to avoid bugs between the assertion 294 // method and the failure method 295 for (int x = bounds.left; x < bounds.right; x++) { 296 for (int y = bounds.top; y < bounds.bottom; y++) { 297 final int pixel = img.getPixel(x, y); 298 if (ignoreRect != null && ignoreRect.contains(x, y)) { 299 markDebugPixel(pixel, result, x, y, ignoredDebugColor, 0.95f); 300 continue; 301 } 302 if (isSimilarColor(primaryColor, pixel)) { 303 markDebugPixel(pixel, result, x, y, validDebugColor, 0.8f); 304 } else if (isSimilarColor(secondaryColor, pixel)) { 305 markDebugPixel(pixel, result, x, y, validDebugColor, 0.8f); 306 } else { 307 markDebugPixel(pixel, result, x, y, Color.TRANSPARENT, 0.0f); 308 } 309 } 310 } 311 312 // Mark the pixels outside the bounds as ignored 313 for (int x = 0; x < img.getWidth(); x++) { 314 for (int y = 0; y < img.getHeight(); y++) { 315 if (bounds.contains(x, y)) { 316 continue; 317 } 318 markDebugPixel(img.getPixel(x, y), result, x, y, ignoredDebugColor, 0.95f); 319 } 320 } 321 dumpOnFailure.dumpOnFailure("splashscreen-color-check", result); 322 } 323 markDebugPixel(int pixel, Bitmap result, int x, int y, int color, float ratio)324 private void markDebugPixel(int pixel, Bitmap result, int x, int y, int color, float ratio) { 325 int debugPixel = ColorUtils.blendARGB(pixel, color, ratio); 326 result.setPixel(x, y, pixel); 327 int debugOffsetX = result.getWidth() / 2; 328 result.setPixel(x + debugOffsetX, y, debugPixel); 329 } 330 331 @Test testHandleExitAnimationOnCreate()332 public void testHandleExitAnimationOnCreate() throws Exception { 333 assumeFalse(isLeanBack()); 334 launchRuntimeHandleExitAnimationActivity(true, false, false, true); 335 } 336 337 @Test testHandleExitAnimationOnResume()338 public void testHandleExitAnimationOnResume() throws Exception { 339 assumeFalse(isLeanBack()); 340 launchRuntimeHandleExitAnimationActivity(false, true, false, true); 341 } 342 343 @Test testHandleExitAnimationCancel()344 public void testHandleExitAnimationCancel() throws Exception { 345 assumeFalse(isLeanBack()); 346 launchRuntimeHandleExitAnimationActivity(true, false, true, false); 347 } 348 launchRuntimeHandleExitAnimationActivity(boolean extraOnCreate, boolean extraOnResume, boolean extraCancel, boolean expectResult)349 private void launchRuntimeHandleExitAnimationActivity(boolean extraOnCreate, 350 boolean extraOnResume, boolean extraCancel, boolean expectResult) throws Exception { 351 TestJournalProvider.TestJournalContainer.start(); 352 final CommandSession.ActivitySession homeActivity = prepareTestLauncher(); 353 startActivityFromTestLauncher(homeActivity, HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, intent -> { 354 intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, extraOnCreate); 355 intent.putExtra(REQUEST_HANDLE_EXIT_ON_RESUME, extraOnResume); 356 intent.putExtra(CANCEL_HANDLE_EXIT, extraCancel); 357 }); 358 359 mWmState.computeState(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY); 360 mWmState.assertVisibility(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, true); 361 final TestJournalProvider.TestJournal journal = 362 TestJournalProvider.TestJournalContainer.get(HANDLE_SPLASH_SCREEN_EXIT); 363 if (expectResult) { 364 TestUtils.waitUntil("Waiting for runtime onSplashScreenExit", 5 /* timeoutSecond */, 365 () -> journal.extras.getBoolean(RECEIVE_SPLASH_SCREEN_EXIT)); 366 assertTrue("No entry for CONTAINS_CENTER_VIEW", 367 journal.extras.containsKey(CONTAINS_CENTER_VIEW)); 368 assertTrue("No entry for CONTAINS_BRANDING_VIEW", 369 journal.extras.containsKey(CONTAINS_BRANDING_VIEW)); 370 assertTrue("Center View shouldn't be null", journal.extras.getBoolean(CONTAINS_CENTER_VIEW)); 371 assertTrue(journal.extras.getBoolean(CONTAINS_BRANDING_VIEW)); 372 assertEquals(Color.BLUE, journal.extras.getInt(ICON_BACKGROUND_COLOR, Color.YELLOW)); 373 } 374 } 375 376 @Test testSetApplicationNightMode()377 public void testSetApplicationNightMode() throws Exception { 378 final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class); 379 assumeTrue(uiModeManager != null); 380 final int systemNightMode = uiModeManager.getNightMode(); 381 final int testNightMode = (systemNightMode == MODE_NIGHT_AUTO 382 || systemNightMode == MODE_NIGHT_CUSTOM) ? MODE_NIGHT_YES 383 : systemNightMode == MODE_NIGHT_YES ? MODE_NIGHT_NO : MODE_NIGHT_YES; 384 final int testConfigNightMode = testNightMode == MODE_NIGHT_YES 385 ? Configuration.UI_MODE_NIGHT_YES 386 : Configuration.UI_MODE_NIGHT_NO; 387 final String nightModeNo = String.valueOf(testNightMode); 388 389 TestJournalProvider.TestJournalContainer.start(); 390 launchActivity(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, 391 extraString(REQUEST_SET_NIGHT_MODE_ON_CREATE, nightModeNo)); 392 mWmState.computeState(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY); 393 mWmState.assertVisibility(HANDLE_SPLASH_SCREEN_EXIT_ACTIVITY, true); 394 final TestJournalProvider.TestJournal journal = 395 TestJournalProvider.TestJournalContainer.get(HANDLE_SPLASH_SCREEN_EXIT); 396 TestUtils.waitUntil("Waiting for night mode changed", 5 /* timeoutSecond */, () -> 397 testConfigNightMode == journal.extras.getInt(GET_NIGHT_MODE_ACTIVITY_CHANGED)); 398 assertEquals(testConfigNightMode, 399 journal.extras.getInt(GET_NIGHT_MODE_ACTIVITY_CHANGED)); 400 } 401 402 @Test testSetBackgroundColorActivity()403 public void testSetBackgroundColorActivity() { 404 // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly 405 // applied insets by system bars in AAOS. 406 assumeFalse(isCar()); 407 408 launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FULLSCREEN, 409 extraBool(DELAY_RESUME, true)); 410 testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE); 411 } 412 413 @Test testSetBackgroundColorActivity_FreeformWindow()414 public void testSetBackgroundColorActivity_FreeformWindow() { 415 // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly 416 // applied insets by system bars in AAOS. 417 assumeFalse(isCar()); 418 assumeTrue(supportsFreeform()); 419 420 launchActivityNoWait(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, WINDOWING_MODE_FREEFORM, 421 extraBool(DELAY_RESUME, true)); 422 testSplashScreenColor(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, Color.BLUE, Color.WHITE); 423 } 424 425 @Test testHandleExitIconAnimatingActivity()426 public void testHandleExitIconAnimatingActivity() throws Exception { 427 assumeFalse(isLeanBack()); 428 final CommandSession.ActivitySession homeActivity = prepareTestLauncher(); 429 TestJournalProvider.TestJournalContainer.start(); 430 431 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent -> { 432 intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true); 433 }); 434 mWmState.computeState(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY); 435 mWmState.assertVisibility(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, true); 436 final TestJournalProvider.TestJournal journal = 437 TestJournalProvider.TestJournalContainer.get(REPLACE_ICON_EXIT); 438 TestUtils.waitUntil("Waiting for runtime onSplashScreenExit", 5 /* timeoutSecond */, 439 () -> journal.extras.getBoolean(RECEIVE_SPLASH_SCREEN_EXIT)); 440 assertTrue(journal.extras.getBoolean(CONTAINS_CENTER_VIEW)); 441 final long iconAnimationStart = journal.extras.getLong(ICON_ANIMATION_START); 442 final long iconAnimationDuration = journal.extras.getLong(ICON_ANIMATION_DURATION); 443 assertTrue(iconAnimationStart != 0); 444 assertEquals(iconAnimationDuration, 500); 445 assertFalse(journal.extras.getBoolean(CONTAINS_BRANDING_VIEW)); 446 assertTrue(journal.extras.getBoolean(CENTER_VIEW_IS_SURFACE_VIEW)); 447 } 448 449 @Test testCancelHandleExitIconAnimatingActivity()450 public void testCancelHandleExitIconAnimatingActivity() { 451 assumeFalse(isLeanBack()); 452 final CommandSession.ActivitySession homeActivity = prepareTestLauncher(); 453 TestJournalProvider.TestJournalContainer.start(); 454 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, intent -> { 455 intent.putExtra(REQUEST_HANDLE_EXIT_ON_CREATE, true); 456 intent.putExtra(CANCEL_HANDLE_EXIT, true); 457 }); 458 mWmState.waitForActivityState(SPLASH_SCREEN_REPLACE_ICON_ACTIVITY, STATE_RESUMED); 459 mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY); 460 461 final TestJournalProvider.TestJournal journal = 462 TestJournalProvider.TestJournalContainer.get(REPLACE_ICON_EXIT); 463 assertFalse(journal.extras.getBoolean(RECEIVE_SPLASH_SCREEN_EXIT)); 464 } 465 466 @Test testShortcutChangeTheme()467 public void testShortcutChangeTheme() { 468 // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly 469 // applied insets by system bars in AAOS. 470 assumeFalse(isCar()); 471 472 final LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); 473 final ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class); 474 assumeTrue(launcherApps != null && shortcutManager != null); 475 476 final String shortCutId = "shortcut1"; 477 final ShortcutInfo.Builder b = new ShortcutInfo.Builder( 478 mContext, shortCutId); 479 final Intent i = new Intent(ACTION_MAIN) 480 .setComponent(SPLASHSCREEN_ACTIVITY); 481 final ShortcutInfo shortcut = b.setShortLabel("label") 482 .setLongLabel("long label") 483 .setIntent(i) 484 .setStartingTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen) 485 .build(); 486 try { 487 shortcutManager.addDynamicShortcuts(Collections.singletonList(shortcut)); 488 runWithShellPermission(() -> launcherApps.startShortcut(shortcut, null, null)); 489 testSplashScreenColor(SPLASHSCREEN_ACTIVITY, Color.BLACK, Color.WHITE); 490 } finally { 491 shortcutManager.removeDynamicShortcuts(Collections.singletonList(shortCutId)); 492 } 493 } 494 waitAndAssertOverrideThemeColor(int expectedColor)495 private void waitAndAssertOverrideThemeColor(int expectedColor) { 496 final ComponentName activity = SPLASH_SCREEN_REPLACE_THEME_ACTIVITY; 497 final Bundle resultExtras = Condition.waitForResult( 498 new Condition<Bundle>("splash screen theme color of " + activity) 499 .setResultSupplier(() -> TestJournalProvider.TestJournalContainer.get( 500 OVERRIDE_THEME_COMPONENT).extras) 501 .setResultValidator(extras -> extras.containsKey(OVERRIDE_THEME_COLOR))); 502 if (resultExtras == null) { 503 fail("No reported override theme color from " + activity); 504 } 505 if (expectedColor > 0) { 506 assertEquals("Override theme color must match", 507 Integer.toHexString(expectedColor), 508 Integer.toHexString(resultExtras.getInt(OVERRIDE_THEME_COLOR))); 509 } 510 mWmState.waitForActivityRemoved(activity); 511 separateTestJournal(); 512 } 513 514 @Test testOverrideSplashscreenTheme()515 public void testOverrideSplashscreenTheme() { 516 assumeFalse(isLeanBack()); 517 final CommandSession.ActivitySession homeActivity = prepareTestLauncher(); 518 519 // Pre-launch the activity to ensure status is cleared on the device 520 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, 521 intent -> {}); 522 waitAndAssertOverrideThemeColor(0 /* ignore */); 523 524 // Launch the activity a first time, check that the splashscreen use the default theme, 525 // and override the theme for the next launch 526 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, 527 intent -> intent.putExtra(OVERRIDE_THEME_ENABLED, true)); 528 waitAndAssertOverrideThemeColor(Color.BLUE); 529 530 // Launch the activity a second time, check that the theme has been overridden and reset 531 // to the default theme 532 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, 533 intent -> {}); 534 waitAndAssertOverrideThemeColor(Color.RED); 535 536 // Launch the activity a third time just to check that the theme has indeed been reset. 537 startActivityFromTestLauncher(homeActivity, SPLASH_SCREEN_REPLACE_THEME_ACTIVITY, 538 intent -> {}); 539 waitAndAssertOverrideThemeColor(Color.BLUE); 540 } 541 } 542