1 /* 2 * Copyright (C) 2023 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.wm.shell.windowdecor; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 23 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING; 24 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; 25 import static android.view.WindowInsets.Type.captionBar; 26 import static android.view.WindowInsets.Type.statusBars; 27 import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND; 28 29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 30 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction; 31 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; 32 import static com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.CLOSE_MAXIMIZE_MENU_DELAY_MS; 33 import static com.android.wm.shell.windowdecor.WindowDecoration.INVALID_CORNER_RADIUS; 34 35 import static com.google.common.truth.Truth.assertThat; 36 37 import static junit.framework.Assert.assertFalse; 38 import static junit.framework.Assert.assertTrue; 39 40 import static org.mockito.ArgumentMatchers.anyBoolean; 41 import static org.mockito.ArgumentMatchers.argThat; 42 import static org.mockito.ArgumentMatchers.eq; 43 import static org.mockito.Mockito.any; 44 import static org.mockito.Mockito.anyInt; 45 import static org.mockito.Mockito.atLeastOnce; 46 import static org.mockito.Mockito.doReturn; 47 import static org.mockito.Mockito.mock; 48 import static org.mockito.Mockito.never; 49 import static org.mockito.Mockito.spy; 50 import static org.mockito.Mockito.verify; 51 import static org.mockito.Mockito.when; 52 53 import android.app.ActivityManager; 54 import android.app.assist.AssistContent; 55 import android.content.ComponentName; 56 import android.content.Context; 57 import android.content.Intent; 58 import android.content.pm.ActivityInfo; 59 import android.content.pm.ApplicationInfo; 60 import android.content.pm.PackageManager; 61 import android.content.pm.ResolveInfo; 62 import android.content.res.Resources; 63 import android.content.res.TypedArray; 64 import android.graphics.Point; 65 import android.graphics.Rect; 66 import android.graphics.Region; 67 import android.net.Uri; 68 import android.os.Handler; 69 import android.os.SystemProperties; 70 import android.platform.test.annotations.DisableFlags; 71 import android.platform.test.annotations.EnableFlags; 72 import android.testing.AndroidTestingRunner; 73 import android.testing.TestableContext; 74 import android.testing.TestableLooper; 75 import android.view.AttachedSurfaceControl; 76 import android.view.Choreographer; 77 import android.view.Display; 78 import android.view.GestureDetector; 79 import android.view.InsetsSource; 80 import android.view.InsetsState; 81 import android.view.MotionEvent; 82 import android.view.SurfaceControl; 83 import android.view.SurfaceControlViewHost; 84 import android.view.View; 85 import android.view.WindowInsets; 86 import android.view.WindowManager; 87 import android.window.WindowContainerTransaction; 88 89 import androidx.annotation.NonNull; 90 import androidx.annotation.Nullable; 91 import androidx.test.filters.SmallTest; 92 93 import com.android.dx.mockito.inline.extended.StaticMockitoSession; 94 import com.android.internal.R; 95 import com.android.window.flags.Flags; 96 import com.android.wm.shell.RootTaskDisplayAreaOrganizer; 97 import com.android.wm.shell.ShellTaskOrganizer; 98 import com.android.wm.shell.ShellTestCase; 99 import com.android.wm.shell.TestRunningTaskInfoBuilder; 100 import com.android.wm.shell.TestShellExecutor; 101 import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; 102 import com.android.wm.shell.apptoweb.AssistContentRequester; 103 import com.android.wm.shell.common.DisplayController; 104 import com.android.wm.shell.common.MultiInstanceHelper; 105 import com.android.wm.shell.common.ShellExecutor; 106 import com.android.wm.shell.common.SyncTransactionQueue; 107 import com.android.wm.shell.desktopmode.CaptionState; 108 import com.android.wm.shell.desktopmode.DesktopModeEventLogger; 109 import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger; 110 import com.android.wm.shell.desktopmode.DesktopRepository; 111 import com.android.wm.shell.desktopmode.DesktopUserRepositories; 112 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository; 113 import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy; 114 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; 115 import com.android.wm.shell.splitscreen.SplitScreenController; 116 import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams; 117 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader; 118 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; 119 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; 120 import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder; 121 import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder; 122 123 import kotlin.Unit; 124 import kotlin.jvm.functions.Function0; 125 import kotlin.jvm.functions.Function1; 126 import kotlin.jvm.functions.Function2; 127 128 import kotlinx.coroutines.CoroutineScope; 129 import kotlinx.coroutines.MainCoroutineDispatcher; 130 131 import org.junit.After; 132 import org.junit.Before; 133 import org.junit.BeforeClass; 134 import org.junit.Ignore; 135 import org.junit.Test; 136 import org.junit.runner.RunWith; 137 import org.mockito.ArgumentCaptor; 138 import org.mockito.Captor; 139 import org.mockito.Mock; 140 import org.mockito.quality.Strictness; 141 142 import java.util.List; 143 import java.util.function.Consumer; 144 import java.util.function.Supplier; 145 146 /** 147 * Tests for {@link DesktopModeWindowDecoration}. 148 * 149 * Build/Install/Run: 150 * atest WMShellUnitTests:DesktopModeWindowDecorationTests 151 */ 152 @SmallTest 153 @TestableLooper.RunWithLooper 154 @RunWith(AndroidTestingRunner.class) 155 public class DesktopModeWindowDecorationTests extends ShellTestCase { 156 private static final String USE_WINDOW_SHADOWS_SYSPROP_KEY = 157 "persist.wm.debug.desktop_use_window_shadows"; 158 private static final String FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY = 159 "persist.wm.debug.desktop_use_window_shadows_focused_window"; 160 private static final String USE_ROUNDED_CORNERS_SYSPROP_KEY = 161 "persist.wm.debug.desktop_use_rounded_corners"; 162 163 private static final Uri TEST_URI1 = Uri.parse("https://www.google.com/"); 164 private static final Uri TEST_URI2 = Uri.parse("https://docs.google.com/"); 165 private static final Uri TEST_URI3 = Uri.parse("https://slides.google.com/"); 166 private static final Uri TEST_URI4 = Uri.parse("https://calendar.google.com/"); 167 168 private static final boolean DEFAULT_APPLY_START_TRANSACTION_ON_DRAW = true; 169 private static final boolean DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP = false; 170 private static final boolean DEFAULT_IS_STATUSBAR_VISIBLE = true; 171 private static final boolean DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED = false; 172 private static final boolean DEFAULT_IS_IN_FULL_IMMERSIVE_MODE = false; 173 private static final boolean DEFAULT_IS_DRAGGING = false; 174 private static final boolean DEFAULT_HAS_GLOBAL_FOCUS = true; 175 private static final boolean DEFAULT_SHOULD_IGNORE_CORNER_RADIUS = false; 176 private static final boolean DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS = false; 177 178 179 @Mock 180 private DisplayController mMockDisplayController; 181 @Mock 182 private SplitScreenController mMockSplitScreenController; 183 @Mock 184 private ShellTaskOrganizer mMockShellTaskOrganizer; 185 @Mock 186 private DesktopUserRepositories mMockDesktopUserRepositories; 187 @Mock 188 private Choreographer mMockChoreographer; 189 @Mock 190 private MainCoroutineDispatcher mMockMainCoroutineDispatcher; 191 @Mock 192 private CoroutineScope mMockBgCoroutineScope; 193 @Mock 194 private SyncTransactionQueue mMockSyncQueue; 195 @Mock 196 private AppHeaderViewHolder.Factory mMockAppHeaderViewHolderFactory; 197 @Mock 198 private AppHandleViewHolder.Factory mMockAppHandleViewHolderFactory; 199 @Mock 200 private AppHeaderViewHolder mMockAppHeaderViewHolder; 201 @Mock 202 private AppHandleViewHolder mMockAppHandleViewHolder; 203 @Mock 204 private RootTaskDisplayAreaOrganizer mMockRootTaskDisplayAreaOrganizer; 205 @Mock 206 private Supplier<SurfaceControl.Transaction> mMockTransactionSupplier; 207 @Mock 208 private SurfaceControl mMockSurfaceControl; 209 @Mock 210 private SurfaceControlViewHost mMockSurfaceControlViewHost; 211 @Mock 212 private AttachedSurfaceControl mMockRootSurfaceControl; 213 @Mock 214 private WindowDecorViewHostSupplier<WindowDecorViewHost> mMockWindowDecorViewHostSupplier; 215 @Mock 216 private WindowDecorViewHost mMockWindowDecorViewHost; 217 @Mock 218 private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory; 219 @Mock 220 private TypedArray mMockRoundedCornersRadiusArray; 221 @Mock 222 private TestTouchEventListener mMockTouchEventListener; 223 @Mock 224 private DesktopModeWindowDecoration.ExclusionRegionListener mMockExclusionRegionListener; 225 @Mock 226 private PackageManager mMockPackageManager; 227 @Mock 228 private Handler mMockHandler; 229 @Mock 230 private Consumer<Intent> mMockOpenInBrowserClickListener; 231 @Mock 232 private AppToWebGenericLinksParser mMockGenericLinksParser; 233 @Mock 234 private WindowManager mMockWindowManager; 235 @Mock 236 private AssistContentRequester mMockAssistContentRequester; 237 @Mock 238 private HandleMenu mMockHandleMenu; 239 @Mock 240 private HandleMenuFactory mMockHandleMenuFactory; 241 @Mock 242 private MultiInstanceHelper mMockMultiInstanceHelper; 243 @Mock 244 private WindowDecorCaptionHandleRepository mMockCaptionHandleRepository; 245 @Mock 246 private DesktopModeEventLogger mDesktopModeEventLogger; 247 @Mock 248 private DesktopModeUiEventLogger mDesktopModeUiEventLogger; 249 @Mock 250 private DesktopRepository mDesktopRepository; 251 @Mock 252 private WindowDecorTaskResourceLoader mMockTaskResourceLoader; 253 @Mock 254 private DesktopModeCompatPolicy mDesktopModeCompatPolicy; 255 @Captor 256 private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener; 257 @Captor 258 private ArgumentCaptor<Runnable> mCloseMaxMenuRunnable; 259 260 private final InsetsState mInsetsState = createInsetsState(statusBars(), /* visible= */true); 261 private SurfaceControl.Transaction mMockTransaction; 262 private StaticMockitoSession mMockitoSession; 263 private TestableContext mTestableContext; 264 private final ShellExecutor mBgExecutor = new TestShellExecutor(); 265 private final ShellExecutor mMainExecutor = new TestShellExecutor(); 266 private final AssistContent mAssistContent = new AssistContent(); 267 private final Region mExclusionRegion = Region.obtain(); 268 269 /** Set up run before test class. */ 270 @BeforeClass setUpClass()271 public static void setUpClass() { 272 // Reset the sysprop settings before running the test. 273 SystemProperties.set(USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); 274 SystemProperties.set(FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); 275 SystemProperties.set(USE_ROUNDED_CORNERS_SYSPROP_KEY, ""); 276 } 277 278 @Before setUp()279 public void setUp() throws PackageManager.NameNotFoundException { 280 mMockitoSession = mockitoSession() 281 .strictness(Strictness.LENIENT) 282 .spyStatic(DesktopModeStatus.class) 283 .startMocking(); 284 when(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(false); 285 doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create( 286 any(), any(), any()); 287 when(mMockSurfaceControlViewHost.getRootSurfaceControl()) 288 .thenReturn(mMockRootSurfaceControl); 289 mMockTransaction = createMockSurfaceControlTransaction(); 290 doReturn(mMockTransaction).when(mMockTransactionSupplier).get(); 291 mTestableContext = new TestableContext(mContext); 292 mTestableContext.ensureTestableResources(); 293 mContext.setMockPackageManager(mMockPackageManager); 294 when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any(), anyInt())) 295 .thenReturn(false); 296 when(mMockPackageManager.getApplicationLabel(any())).thenReturn("applicationLabel"); 297 final ActivityInfo activityInfo = createActivityInfo(); 298 when(mMockPackageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo); 299 final ResolveInfo resolveInfo = createResolveInfo(false /* handleAllWebDataUri */); 300 when(mMockPackageManager.resolveActivityAsUser(any(), anyInt(), anyInt())) 301 .thenReturn(resolveInfo); 302 final Display defaultDisplay = mock(Display.class); 303 doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY); 304 doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt()); 305 when(mMockHandleMenuFactory.create(any(), any(), any(), any(), any(), anyInt(), any(), 306 anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), 307 anyBoolean(), any(), any(), anyInt(), anyInt(), anyInt(), anyInt())) 308 .thenReturn(mMockHandleMenu); 309 when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any(), anyInt())) 310 .thenReturn(false); 311 when(mMockAppHeaderViewHolderFactory 312 .create(any(), any(), any(), any(), any(), any(), any(), any(), any(), any())) 313 .thenReturn(mMockAppHeaderViewHolder); 314 when(mMockAppHandleViewHolderFactory 315 .create(any(), any(), any(), any(), any(), any())) 316 .thenReturn(mMockAppHandleViewHolder); 317 when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); 318 when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository); 319 when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay))) 320 .thenReturn(mMockWindowDecorViewHost); 321 when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class)); 322 } 323 324 @After tearDown()325 public void tearDown() { 326 mMockitoSession.finishMocking(); 327 } 328 329 @Test testMenusClosedWhenTaskIsInvisible()330 public void testMenusClosedWhenTaskIsInvisible() { 331 doReturn(mMockTransaction).when(mMockTransaction).hide(any()); 332 333 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(false /* visible */); 334 final DesktopModeWindowDecoration spyWindowDecor = 335 spy(createWindowDecoration(taskInfo)); 336 337 spyWindowDecor.relayout(taskInfo, false /* hasGlobalFocus */, mExclusionRegion); 338 339 // Menus should close if open before the task being invisible causes relayout to return. 340 verify(spyWindowDecor).closeHandleMenu(); 341 verify(spyWindowDecor).closeMaximizeMenu(); 342 343 } 344 345 @Test 346 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform_dynamicDisabled()347 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform_dynamicDisabled() { 348 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 349 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 350 RelayoutParams relayoutParams = new RelayoutParams(); 351 352 updateRelayoutParams(relayoutParams, taskInfo); 353 354 assertThat(relayoutParams.mShadowRadius) 355 .isNotEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS); 356 } 357 358 @Test 359 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen_dynamicDisabled()360 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen_dynamicDisabled() { 361 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 362 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 363 RelayoutParams relayoutParams = new RelayoutParams(); 364 365 updateRelayoutParams(relayoutParams, taskInfo); 366 367 assertThat(relayoutParams.mShadowRadius).isEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS); 368 } 369 370 @Test 371 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit_dynamicDisabled()372 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit_dynamicDisabled() { 373 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 374 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 375 RelayoutParams relayoutParams = new RelayoutParams(); 376 377 updateRelayoutParams(relayoutParams, taskInfo); 378 379 assertThat(relayoutParams.mShadowRadius).isEqualTo(WindowDecoration.INVALID_SHADOW_RADIUS); 380 } 381 382 @Test 383 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform_dynamicDisabled()384 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform_dynamicDisabled() { 385 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 386 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 387 fillRoundedCornersResources(/* fillValue= */ 30); 388 RelayoutParams relayoutParams = new RelayoutParams(); 389 390 updateRelayoutParams(relayoutParams, taskInfo); 391 392 assertThat(relayoutParams.mCornerRadius).isGreaterThan(0); 393 } 394 395 @Test 396 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen_dynamicDisabled()397 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen_dynamicDisabled() { 398 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 399 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 400 fillRoundedCornersResources(/* fillValue= */ 30); 401 RelayoutParams relayoutParams = new RelayoutParams(); 402 403 updateRelayoutParams(relayoutParams, taskInfo); 404 405 assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS); 406 } 407 408 @Test 409 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit_dynamicDisabled()410 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit_dynamicDisabled() { 411 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 412 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 413 fillRoundedCornersResources(/* fillValue= */ 30); 414 RelayoutParams relayoutParams = new RelayoutParams(); 415 416 updateRelayoutParams(relayoutParams, taskInfo); 417 418 assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS); 419 } 420 421 @Test 422 @DisableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet_dynamicDisabled()423 public void updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet_dynamicDisabled() { 424 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 425 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 426 fillRoundedCornersResources(/* fillValue= */ 30); 427 RelayoutParams relayoutParams = new RelayoutParams(); 428 429 DesktopModeWindowDecoration.updateRelayoutParams( 430 relayoutParams, 431 mTestableContext, 432 taskInfo, 433 mMockSplitScreenController, 434 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 435 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 436 DEFAULT_IS_STATUSBAR_VISIBLE, 437 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 438 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 439 DEFAULT_IS_DRAGGING, 440 new InsetsState(), 441 DEFAULT_HAS_GLOBAL_FOCUS, 442 mExclusionRegion, 443 /* shouldIgnoreCornerRadius= */ true, 444 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 445 446 assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS); 447 } 448 449 @Test 450 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform()451 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreSetForFreeform() { 452 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 453 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 454 RelayoutParams relayoutParams = new RelayoutParams(); 455 456 updateRelayoutParams(relayoutParams, taskInfo); 457 458 assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL); 459 } 460 461 @Test 462 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen()463 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForFullscreen() { 464 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 465 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 466 RelayoutParams relayoutParams = new RelayoutParams(); 467 468 updateRelayoutParams(relayoutParams, taskInfo); 469 470 assertThat(relayoutParams.mShadowRadiusId).isEqualTo(Resources.ID_NULL); 471 } 472 473 @Test 474 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit()475 public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreNotSetForSplit() { 476 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 477 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 478 RelayoutParams relayoutParams = new RelayoutParams(); 479 480 updateRelayoutParams(relayoutParams, taskInfo); 481 482 assertThat(relayoutParams.mShadowRadiusId).isEqualTo(Resources.ID_NULL); 483 } 484 485 @Test 486 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform()487 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() { 488 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 489 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 490 RelayoutParams relayoutParams = new RelayoutParams(); 491 492 updateRelayoutParams(relayoutParams, taskInfo); 493 494 assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL); 495 } 496 497 @Test 498 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen()499 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() { 500 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 501 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 502 RelayoutParams relayoutParams = new RelayoutParams(); 503 504 updateRelayoutParams(relayoutParams, taskInfo); 505 506 assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL); 507 } 508 509 @Test 510 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit()511 public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForSplit() { 512 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 513 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 514 RelayoutParams relayoutParams = new RelayoutParams(); 515 516 updateRelayoutParams(relayoutParams, taskInfo); 517 518 assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL); 519 } 520 521 @Test 522 @EnableFlags(Flags.FLAG_ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX) updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet()523 public void updateRelayoutParams_shouldIgnoreCornerRadius_roundedCornersNotSet() { 524 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 525 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 526 RelayoutParams relayoutParams = new RelayoutParams(); 527 528 DesktopModeWindowDecoration.updateRelayoutParams( 529 relayoutParams, 530 mTestableContext, 531 taskInfo, 532 mMockSplitScreenController, 533 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 534 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 535 DEFAULT_IS_STATUSBAR_VISIBLE, 536 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 537 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 538 DEFAULT_IS_DRAGGING, 539 new InsetsState(), 540 DEFAULT_HAS_GLOBAL_FOCUS, 541 mExclusionRegion, 542 /* shouldIgnoreCornerRadius= */ true, 543 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 544 545 assertThat(relayoutParams.mCornerRadiusId).isEqualTo(Resources.ID_NULL); 546 } 547 548 @Test 549 @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY) updateRelayoutParams_appHeader_usesTaskDensity()550 public void updateRelayoutParams_appHeader_usesTaskDensity() { 551 final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources() 552 .getConfiguration().densityDpi; 553 final int customTaskDensity = systemDensity + 300; 554 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 555 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 556 taskInfo.configuration.densityDpi = customTaskDensity; 557 final RelayoutParams relayoutParams = new RelayoutParams(); 558 559 updateRelayoutParams(relayoutParams, taskInfo); 560 561 assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(customTaskDensity); 562 } 563 564 @Test 565 @DisableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY) updateRelayoutParams_appHeader_usesSystemDensity()566 public void updateRelayoutParams_appHeader_usesSystemDensity() { 567 when(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(true); 568 final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources() 569 .getConfiguration().densityDpi; 570 final int customTaskDensity = systemDensity + 300; 571 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 572 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 573 taskInfo.configuration.densityDpi = customTaskDensity; 574 final RelayoutParams relayoutParams = new RelayoutParams(); 575 576 updateRelayoutParams(relayoutParams, taskInfo); 577 578 assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(systemDensity); 579 } 580 581 @Test 582 @DisableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough()583 public void updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() { 584 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 585 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 586 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance( 587 APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND); 588 final RelayoutParams relayoutParams = new RelayoutParams(); 589 590 updateRelayoutParams(relayoutParams, taskInfo); 591 592 assertThat(relayoutParams.hasInputFeatureSpy()).isTrue(); 593 } 594 595 @Test 596 @EnableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_freeformAndTransparentAppearance_limitedTouchRegion()597 public void updateRelayoutParams_freeformAndTransparentAppearance_limitedTouchRegion() { 598 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 599 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 600 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance( 601 APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND); 602 final RelayoutParams relayoutParams = new RelayoutParams(); 603 604 updateRelayoutParams(relayoutParams, taskInfo); 605 606 assertThat(relayoutParams.mLimitTouchRegionToSystemAreas).isTrue(); 607 } 608 609 @Test 610 @DisableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_freeformButOpaqueAppearance_disallowsInputFallthrough()611 public void updateRelayoutParams_freeformButOpaqueAppearance_disallowsInputFallthrough() { 612 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 613 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 614 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0); 615 final RelayoutParams relayoutParams = new RelayoutParams(); 616 617 updateRelayoutParams(relayoutParams, taskInfo); 618 619 assertThat(relayoutParams.hasInputFeatureSpy()).isFalse(); 620 } 621 622 @Test 623 @EnableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_freeformButOpaqueAppearance_unlimitedTouchRegion()624 public void updateRelayoutParams_freeformButOpaqueAppearance_unlimitedTouchRegion() { 625 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 626 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 627 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0); 628 final RelayoutParams relayoutParams = new RelayoutParams(); 629 630 updateRelayoutParams(relayoutParams, taskInfo); 631 632 assertThat(relayoutParams.mLimitTouchRegionToSystemAreas).isFalse(); 633 } 634 635 @Test 636 @DisableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_fullscreen_disallowsInputFallthrough()637 public void updateRelayoutParams_fullscreen_disallowsInputFallthrough() { 638 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 639 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 640 final RelayoutParams relayoutParams = new RelayoutParams(); 641 642 updateRelayoutParams(relayoutParams, taskInfo); 643 644 assertThat(relayoutParams.hasInputFeatureSpy()).isFalse(); 645 } 646 647 @Test 648 @EnableFlags(Flags.FLAG_ENABLE_ACCESSIBLE_CUSTOM_HEADERS) updateRelayoutParams_fullscreen_unlimitedTouchRegion()649 public void updateRelayoutParams_fullscreen_unlimitedTouchRegion() { 650 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 651 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 652 final RelayoutParams relayoutParams = new RelayoutParams(); 653 654 updateRelayoutParams(relayoutParams, taskInfo); 655 656 assertThat(relayoutParams.mLimitTouchRegionToSystemAreas).isFalse(); 657 } 658 659 @Test updateRelayoutParams_freeform_inputChannelNeeded()660 public void updateRelayoutParams_freeform_inputChannelNeeded() { 661 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 662 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 663 final RelayoutParams relayoutParams = new RelayoutParams(); 664 665 updateRelayoutParams(relayoutParams, taskInfo); 666 667 assertThat(hasNoInputChannelFeature(relayoutParams)).isFalse(); 668 } 669 670 @Test 671 @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX) updateRelayoutParams_fullscreen_inputChannelNotNeeded()672 public void updateRelayoutParams_fullscreen_inputChannelNotNeeded() { 673 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 674 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 675 final RelayoutParams relayoutParams = new RelayoutParams(); 676 677 updateRelayoutParams(relayoutParams, taskInfo); 678 679 assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue(); 680 } 681 682 @Test 683 @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX) updateRelayoutParams_multiwindow_inputChannelNotNeeded()684 public void updateRelayoutParams_multiwindow_inputChannelNotNeeded() { 685 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 686 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 687 final RelayoutParams relayoutParams = new RelayoutParams(); 688 689 updateRelayoutParams(relayoutParams, taskInfo); 690 691 assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue(); 692 } 693 694 @Test 695 @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION) updateRelayoutParams_defaultHeader_addsForceConsumingFlag()696 public void updateRelayoutParams_defaultHeader_addsForceConsumingFlag() { 697 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 698 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 699 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0); 700 final RelayoutParams relayoutParams = new RelayoutParams(); 701 702 updateRelayoutParams(relayoutParams, taskInfo); 703 704 assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) != 0).isTrue(); 705 } 706 707 @Test 708 @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION) updateRelayoutParams_customHeader_noForceConsumptionFlag()709 public void updateRelayoutParams_customHeader_noForceConsumptionFlag() { 710 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 711 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 712 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance( 713 APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND); 714 final RelayoutParams relayoutParams = new RelayoutParams(); 715 716 updateRelayoutParams(relayoutParams, taskInfo); 717 718 assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) == 0).isTrue(); 719 } 720 721 @Test 722 @EnableFlags({Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION, 723 Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS}) updateRelayoutParams_excludeCaptionTrue_forceConsumptionFalse()724 public void updateRelayoutParams_excludeCaptionTrue_forceConsumptionFalse() { 725 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 726 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 727 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0); 728 final RelayoutParams relayoutParams = new RelayoutParams(); 729 730 DesktopModeWindowDecoration.updateRelayoutParams( 731 relayoutParams, 732 mTestableContext, 733 taskInfo, 734 mMockSplitScreenController, 735 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 736 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 737 DEFAULT_IS_STATUSBAR_VISIBLE, 738 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 739 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 740 DEFAULT_IS_DRAGGING, 741 new InsetsState(), 742 DEFAULT_HAS_GLOBAL_FOCUS, 743 mExclusionRegion, 744 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 745 /* shouldExcludeCaptionFromAppBounds */ true); 746 747 // Force consuming flags are disabled. 748 assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) == 0).isTrue(); 749 assertThat( 750 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) == 0) 751 .isTrue(); 752 // Exclude caption from app bounds is true. 753 assertThat(relayoutParams.mShouldSetAppBounds).isTrue(); 754 } 755 756 @Test 757 @EnableFlags({Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION, 758 Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS}) updateRelayoutParams_excludeCaptionFalse_forceConsumptionTrue()759 public void updateRelayoutParams_excludeCaptionFalse_forceConsumptionTrue() { 760 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 761 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 762 taskInfo.taskDescription.setTopOpaqueSystemBarsAppearance(0); 763 final RelayoutParams relayoutParams = new RelayoutParams(); 764 765 DesktopModeWindowDecoration.updateRelayoutParams( 766 relayoutParams, 767 mTestableContext, 768 taskInfo, 769 mMockSplitScreenController, 770 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 771 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 772 DEFAULT_IS_STATUSBAR_VISIBLE, 773 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 774 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 775 DEFAULT_IS_DRAGGING, 776 new InsetsState(), 777 DEFAULT_HAS_GLOBAL_FOCUS, 778 mExclusionRegion, 779 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 780 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 781 782 assertThat((relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING) != 0).isTrue(); 783 assertThat( 784 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) 785 .isTrue(); 786 // Exclude caption from app bounds is false. 787 assertThat(relayoutParams.mShouldSetAppBounds).isFalse(); 788 } 789 790 @Test 791 @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS) updateRelayoutParams_header_addsForceConsumingCaptionBar()792 public void updateRelayoutParams_header_addsForceConsumingCaptionBar() { 793 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 794 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 795 final RelayoutParams relayoutParams = new RelayoutParams(); 796 797 updateRelayoutParams(relayoutParams, taskInfo); 798 799 assertThat( 800 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) 801 .isTrue(); 802 } 803 804 @Test 805 @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS) updateRelayoutParams_handle_skipsForceConsumingCaptionBar()806 public void updateRelayoutParams_handle_skipsForceConsumingCaptionBar() { 807 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 808 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 809 final RelayoutParams relayoutParams = new RelayoutParams(); 810 811 updateRelayoutParams(relayoutParams, taskInfo); 812 813 assertThat( 814 (relayoutParams.mInsetSourceFlags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) == 0) 815 .isTrue(); 816 } 817 818 @Test updateRelayoutParams_handle_bottomSplitIsInsetSource()819 public void updateRelayoutParams_handle_bottomSplitIsInsetSource() { 820 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 821 final RelayoutParams relayoutParams = new RelayoutParams(); 822 when(mMockSplitScreenController.isLeftRightSplit()).thenReturn(false); 823 when(mMockSplitScreenController.getSplitPosition(taskInfo.taskId)) 824 .thenReturn(SPLIT_POSITION_BOTTOM_OR_RIGHT); 825 826 updateRelayoutParams(relayoutParams, taskInfo); 827 828 assertThat(relayoutParams.mIsInsetSource).isTrue(); 829 } 830 831 @Test 832 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) updateRelayoutParams_header_addsPaddingInFullImmersive()833 public void updateRelayoutParams_header_addsPaddingInFullImmersive() { 834 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 835 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 836 taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 1000, 2000)); 837 final InsetsState insetsState = createInsetsState(List.of( 838 createInsetsSource( 839 0 /* id */, statusBars(), true /* visible */, new Rect(0, 0, 1000, 50)), 840 createInsetsSource( 841 1 /* id */, captionBar(), true /* visible */, new Rect(0, 0, 1000, 100)))); 842 final RelayoutParams relayoutParams = new RelayoutParams(); 843 844 DesktopModeWindowDecoration.updateRelayoutParams( 845 relayoutParams, 846 mTestableContext, 847 taskInfo, 848 mMockSplitScreenController, 849 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 850 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 851 DEFAULT_IS_STATUSBAR_VISIBLE, 852 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 853 /* inFullImmersiveMode */ true, 854 DEFAULT_IS_DRAGGING, 855 insetsState, 856 DEFAULT_HAS_GLOBAL_FOCUS, 857 mExclusionRegion, 858 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 859 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 860 861 // Takes status bar inset as padding, ignores caption bar inset. 862 assertThat(relayoutParams.mCaptionTopPadding).isEqualTo(50); 863 } 864 865 @Test 866 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) updateRelayoutParams_header_notAnInsetsSourceInFullyImmersive()867 public void updateRelayoutParams_header_notAnInsetsSourceInFullyImmersive() { 868 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 869 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 870 final RelayoutParams relayoutParams = new RelayoutParams(); 871 872 DesktopModeWindowDecoration.updateRelayoutParams( 873 relayoutParams, 874 mTestableContext, 875 taskInfo, 876 mMockSplitScreenController, 877 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 878 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 879 DEFAULT_IS_STATUSBAR_VISIBLE, 880 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 881 /* inFullImmersiveMode */ true, 882 DEFAULT_IS_DRAGGING, 883 new InsetsState(), 884 DEFAULT_HAS_GLOBAL_FOCUS, 885 mExclusionRegion, 886 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 887 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 888 889 assertThat(relayoutParams.mIsInsetSource).isFalse(); 890 } 891 892 @Test 893 @DisableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) updateRelayoutParams_header_statusBarInvisible_captionVisible()894 public void updateRelayoutParams_header_statusBarInvisible_captionVisible() { 895 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 896 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 897 final RelayoutParams relayoutParams = new RelayoutParams(); 898 899 DesktopModeWindowDecoration.updateRelayoutParams( 900 relayoutParams, 901 mTestableContext, 902 taskInfo, 903 mMockSplitScreenController, 904 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 905 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 906 /* isStatusBarVisible */ false, 907 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 908 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 909 DEFAULT_IS_DRAGGING, 910 new InsetsState(), 911 DEFAULT_HAS_GLOBAL_FOCUS, 912 mExclusionRegion, 913 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 914 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 915 916 // Header is always shown because it's assumed the status bar is always visible. 917 assertThat(relayoutParams.mIsCaptionVisible).isTrue(); 918 } 919 920 @Test updateRelayoutParams_handle_statusBarVisibleAndNotOverKeyguard_captionVisible()921 public void updateRelayoutParams_handle_statusBarVisibleAndNotOverKeyguard_captionVisible() { 922 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 923 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 924 final RelayoutParams relayoutParams = new RelayoutParams(); 925 926 DesktopModeWindowDecoration.updateRelayoutParams( 927 relayoutParams, 928 mTestableContext, 929 taskInfo, 930 mMockSplitScreenController, 931 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 932 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 933 /* isStatusBarVisible */ true, 934 /* isKeyguardVisibleAndOccluded */ false, 935 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 936 DEFAULT_IS_DRAGGING, 937 new InsetsState(), 938 DEFAULT_HAS_GLOBAL_FOCUS, 939 mExclusionRegion, 940 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 941 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 942 943 assertThat(relayoutParams.mIsCaptionVisible).isTrue(); 944 } 945 946 @Test updateRelayoutParams_handle_statusBarInvisible_captionNotVisible()947 public void updateRelayoutParams_handle_statusBarInvisible_captionNotVisible() { 948 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 949 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 950 final RelayoutParams relayoutParams = new RelayoutParams(); 951 952 DesktopModeWindowDecoration.updateRelayoutParams( 953 relayoutParams, 954 mTestableContext, 955 taskInfo, 956 mMockSplitScreenController, 957 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 958 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 959 /* isStatusBarVisible */ false, 960 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 961 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 962 DEFAULT_IS_DRAGGING, 963 new InsetsState(), 964 DEFAULT_HAS_GLOBAL_FOCUS, 965 mExclusionRegion, 966 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 967 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 968 969 assertThat(relayoutParams.mIsCaptionVisible).isFalse(); 970 } 971 972 @Test updateRelayoutParams_handle_overKeyguard_captionNotVisible()973 public void updateRelayoutParams_handle_overKeyguard_captionNotVisible() { 974 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 975 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 976 final RelayoutParams relayoutParams = new RelayoutParams(); 977 978 DesktopModeWindowDecoration.updateRelayoutParams( 979 relayoutParams, 980 mTestableContext, 981 taskInfo, 982 mMockSplitScreenController, 983 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 984 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 985 DEFAULT_IS_STATUSBAR_VISIBLE, 986 /* isKeyguardVisibleAndOccluded */ true, 987 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 988 DEFAULT_IS_DRAGGING, 989 new InsetsState(), 990 DEFAULT_HAS_GLOBAL_FOCUS, 991 mExclusionRegion, 992 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 993 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 994 995 assertThat(relayoutParams.mIsCaptionVisible).isFalse(); 996 } 997 998 @Test 999 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) updateRelayoutParams_header_fullyImmersive_captionVisFollowsStatusBar()1000 public void updateRelayoutParams_header_fullyImmersive_captionVisFollowsStatusBar() { 1001 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1002 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 1003 final RelayoutParams relayoutParams = new RelayoutParams(); 1004 1005 DesktopModeWindowDecoration.updateRelayoutParams( 1006 relayoutParams, 1007 mTestableContext, 1008 taskInfo, 1009 mMockSplitScreenController, 1010 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 1011 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 1012 /* isStatusBarVisible */ true, 1013 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 1014 /* inFullImmersiveMode */ true, 1015 DEFAULT_IS_DRAGGING, 1016 new InsetsState(), 1017 DEFAULT_HAS_GLOBAL_FOCUS, 1018 mExclusionRegion, 1019 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 1020 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 1021 1022 assertThat(relayoutParams.mIsCaptionVisible).isTrue(); 1023 1024 DesktopModeWindowDecoration.updateRelayoutParams( 1025 relayoutParams, 1026 mTestableContext, 1027 taskInfo, 1028 mMockSplitScreenController, 1029 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 1030 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 1031 /* isStatusBarVisible */ false, 1032 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 1033 /* inFullImmersiveMode */ true, 1034 DEFAULT_IS_DRAGGING, 1035 new InsetsState(), 1036 DEFAULT_HAS_GLOBAL_FOCUS, 1037 mExclusionRegion, 1038 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 1039 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 1040 1041 assertThat(relayoutParams.mIsCaptionVisible).isFalse(); 1042 } 1043 1044 @Test 1045 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX) updateRelayoutParams_header_fullyImmersive_captionVisDuringDrag()1046 public void updateRelayoutParams_header_fullyImmersive_captionVisDuringDrag() { 1047 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1048 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1049 final RelayoutParams relayoutParams = new RelayoutParams(); 1050 1051 DesktopModeWindowDecoration.updateRelayoutParams( 1052 relayoutParams, 1053 mTestableContext, 1054 taskInfo, 1055 mMockSplitScreenController, 1056 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 1057 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 1058 /* isStatusBarVisible */ false, 1059 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 1060 /* inFullImmersiveMode */ true, 1061 /* isDragging */ true, 1062 new InsetsState(), 1063 DEFAULT_HAS_GLOBAL_FOCUS, 1064 mExclusionRegion, 1065 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 1066 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 1067 1068 assertThat(relayoutParams.mIsCaptionVisible).isTrue(); 1069 } 1070 1071 @Test 1072 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) updateRelayoutParams_header_fullyImmersive_overKeyguard_captionNotVisible()1073 public void updateRelayoutParams_header_fullyImmersive_overKeyguard_captionNotVisible() { 1074 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1075 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 1076 final RelayoutParams relayoutParams = new RelayoutParams(); 1077 1078 DesktopModeWindowDecoration.updateRelayoutParams( 1079 relayoutParams, 1080 mTestableContext, 1081 taskInfo, 1082 mMockSplitScreenController, 1083 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 1084 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 1085 DEFAULT_IS_STATUSBAR_VISIBLE, 1086 /* isKeyguardVisibleAndOccluded */ true, 1087 /* inFullImmersiveMode */ true, 1088 DEFAULT_IS_DRAGGING, 1089 new InsetsState(), 1090 DEFAULT_HAS_GLOBAL_FOCUS, 1091 mExclusionRegion, 1092 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 1093 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 1094 1095 assertThat(relayoutParams.mIsCaptionVisible).isFalse(); 1096 } 1097 1098 @Test updateRelayoutParams_handle_requestsAsyncViewHostRendering()1099 public void updateRelayoutParams_handle_requestsAsyncViewHostRendering() { 1100 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1101 // Make the task fullscreen so that its decoration is an App Handle. 1102 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1103 final RelayoutParams relayoutParams = new RelayoutParams(); 1104 1105 updateRelayoutParams(relayoutParams, taskInfo); 1106 1107 // App Handles don't need to be rendered in sync with the task animation, per UX. 1108 assertThat(relayoutParams.mAsyncViewHost).isTrue(); 1109 } 1110 1111 @Test updateRelayoutParams_header_requestsSyncViewHostRendering()1112 public void updateRelayoutParams_header_requestsSyncViewHostRendering() { 1113 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1114 // Make the task freeform so that its decoration is an App Header. 1115 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 1116 final RelayoutParams relayoutParams = new RelayoutParams(); 1117 1118 updateRelayoutParams(relayoutParams, taskInfo); 1119 1120 // App Headers must be rendered in sync with the task animation, so it cannot be delayed. 1121 assertThat(relayoutParams.mAsyncViewHost).isFalse(); 1122 } 1123 1124 @Test relayout_fullscreenTask_appliesTransactionImmediately()1125 public void relayout_fullscreenTask_appliesTransactionImmediately() { 1126 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1127 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1128 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1129 1130 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1131 1132 verify(mMockTransaction).apply(); 1133 verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any()); 1134 } 1135 1136 @Test 1137 @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error") relayout_freeformTask_appliesTransactionOnDraw()1138 public void relayout_freeformTask_appliesTransactionOnDraw() { 1139 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1140 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1141 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 1142 // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT) 1143 taskInfo.isResizeable = false; 1144 1145 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1146 1147 verify(mMockTransaction, never()).apply(); 1148 verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction); 1149 } 1150 1151 @Test createMaximizeMenu_showsMenu()1152 public void createMaximizeMenu_showsMenu() { 1153 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1154 final MaximizeMenu menu = mock(MaximizeMenu.class); 1155 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1156 new FakeMaximizeMenuFactory(menu)); 1157 assertFalse(decoration.isMaximizeMenuActive()); 1158 1159 createMaximizeMenu(decoration); 1160 1161 verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(), 1162 mOnMaxMenuHoverChangeListener.capture(), any()); 1163 assertTrue(decoration.isMaximizeMenuActive()); 1164 } 1165 1166 @Test maximizeMenu_unHoversMenu_schedulesCloseMenu()1167 public void maximizeMenu_unHoversMenu_schedulesCloseMenu() { 1168 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1169 final MaximizeMenu menu = mock(MaximizeMenu.class); 1170 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1171 new FakeMaximizeMenuFactory(menu)); 1172 decoration.setAppHeaderMaximizeButtonHovered(false); 1173 createMaximizeMenu(decoration); 1174 verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(), 1175 mOnMaxMenuHoverChangeListener.capture(), any()); 1176 1177 mOnMaxMenuHoverChangeListener.getValue().invoke(false); 1178 1179 verify(mMockHandler) 1180 .postDelayed(mCloseMaxMenuRunnable.capture(), eq(CLOSE_MAXIMIZE_MENU_DELAY_MS)); 1181 1182 mCloseMaxMenuRunnable.getValue().run(); 1183 verify(menu).close(any()); 1184 assertFalse(decoration.isMaximizeMenuActive()); 1185 } 1186 1187 @Test maximizeMenu_unHoversButton_schedulesCloseMenu()1188 public void maximizeMenu_unHoversButton_schedulesCloseMenu() { 1189 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1190 final MaximizeMenu menu = mock(MaximizeMenu.class); 1191 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1192 new FakeMaximizeMenuFactory(menu)); 1193 decoration.setAppHeaderMaximizeButtonHovered(true); 1194 createMaximizeMenu(decoration); 1195 1196 decoration.setAppHeaderMaximizeButtonHovered(false); 1197 1198 verify(mMockHandler) 1199 .postDelayed(mCloseMaxMenuRunnable.capture(), eq(CLOSE_MAXIMIZE_MENU_DELAY_MS)); 1200 1201 mCloseMaxMenuRunnable.getValue().run(); 1202 verify(menu).close(any()); 1203 assertFalse(decoration.isMaximizeMenuActive()); 1204 } 1205 1206 @Test maximizeMenu_hoversMenu_cancelsCloseMenu()1207 public void maximizeMenu_hoversMenu_cancelsCloseMenu() { 1208 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1209 final MaximizeMenu menu = mock(MaximizeMenu.class); 1210 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1211 new FakeMaximizeMenuFactory(menu)); 1212 createMaximizeMenu(decoration); 1213 verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(), 1214 mOnMaxMenuHoverChangeListener.capture(), any()); 1215 1216 mOnMaxMenuHoverChangeListener.getValue().invoke(true); 1217 1218 verify(mMockHandler).removeCallbacks(any()); 1219 } 1220 1221 @Test maximizeMenu_hoversButton_cancelsCloseMenu()1222 public void maximizeMenu_hoversButton_cancelsCloseMenu() { 1223 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1224 final MaximizeMenu menu = mock(MaximizeMenu.class); 1225 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1226 new FakeMaximizeMenuFactory(menu)); 1227 createMaximizeMenu(decoration); 1228 verify(menu).show(anyBoolean(), anyBoolean(), anyBoolean(), any(), any(), any(), any(), 1229 mOnMaxMenuHoverChangeListener.capture(), any()); 1230 1231 decoration.setAppHeaderMaximizeButtonHovered(true); 1232 1233 verify(mMockHandler).removeCallbacks(any()); 1234 } 1235 1236 @Test 1237 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) createMaximizeMenu_taskRequestsImmersive_showsImmersiveOption()1238 public void createMaximizeMenu_taskRequestsImmersive_showsImmersiveOption() { 1239 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1240 taskInfo.requestedVisibleTypes = ~statusBars(); 1241 final MaximizeMenu menu = mock(MaximizeMenu.class); 1242 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1243 new FakeMaximizeMenuFactory(menu)); 1244 1245 createMaximizeMenu(decoration); 1246 1247 verify(menu).show( 1248 anyBoolean(), 1249 /* showImmersiveOption= */ eq(true), 1250 anyBoolean(), 1251 any(), 1252 any(), 1253 any(), 1254 any(), 1255 any(), 1256 any() 1257 ); 1258 } 1259 1260 @Test 1261 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) createMaximizeMenu_taskDoesNotRequestImmersive_hiddenImmersiveOption()1262 public void createMaximizeMenu_taskDoesNotRequestImmersive_hiddenImmersiveOption() { 1263 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1264 taskInfo.requestedVisibleTypes = statusBars(); 1265 final MaximizeMenu menu = mock(MaximizeMenu.class); 1266 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1267 new FakeMaximizeMenuFactory(menu)); 1268 1269 createMaximizeMenu(decoration); 1270 1271 verify(menu).show( 1272 anyBoolean(), 1273 /* showImmersiveOption= */ eq(false), 1274 anyBoolean(), 1275 any(), 1276 any(), 1277 any(), 1278 any(), 1279 any(), 1280 any() 1281 ); 1282 } 1283 1284 @Test 1285 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) createMaximizeMenu_taskResizable_showsSnapOptions()1286 public void createMaximizeMenu_taskResizable_showsSnapOptions() { 1287 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1288 taskInfo.isResizeable = true; 1289 final MaximizeMenu menu = mock(MaximizeMenu.class); 1290 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1291 new FakeMaximizeMenuFactory(menu)); 1292 1293 createMaximizeMenu(decoration); 1294 1295 verify(menu).show( 1296 anyBoolean(), 1297 anyBoolean(), 1298 /* showSnapOptions= */ eq(true), 1299 any(), 1300 any(), 1301 any(), 1302 any(), 1303 any(), 1304 any() 1305 ); 1306 } 1307 1308 @Test 1309 @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) createMaximizeMenu_taskUnresizable_hiddenSnapOptions()1310 public void createMaximizeMenu_taskUnresizable_hiddenSnapOptions() { 1311 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1312 taskInfo.isResizeable = false; 1313 final MaximizeMenu menu = mock(MaximizeMenu.class); 1314 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1315 new FakeMaximizeMenuFactory(menu)); 1316 1317 createMaximizeMenu(decoration); 1318 1319 verify(menu).show( 1320 anyBoolean(), 1321 anyBoolean(), 1322 /* showSnapOptions= */ eq(false), 1323 any(), 1324 any(), 1325 any(), 1326 any(), 1327 any(), 1328 any() 1329 ); 1330 } 1331 1332 @Test 1333 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) capturedLink_CapturedLinkUsedIfValidAndWebUriUnavailable()1334 public void capturedLink_CapturedLinkUsedIfValidAndWebUriUnavailable() { 1335 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1336 final DesktopModeWindowDecoration decor = createWindowDecoration( 1337 taskInfo, TEST_URI1 /* captured link */, null /* web uri */, 1338 null /* session transfer uri */, TEST_URI4 /* generic link */); 1339 1340 // Verify handle menu's browser link set as captured link 1341 createHandleMenu(decor); 1342 verifyHandleMenuCreated(TEST_URI1); 1343 } 1344 1345 @Test 1346 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) capturedLink_capturedLinkNotResetToSameLink()1347 public void capturedLink_capturedLinkNotResetToSameLink() { 1348 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1349 final DesktopModeWindowDecoration decor = createWindowDecoration( 1350 taskInfo, TEST_URI1 /* captured link */, null /* web uri */, 1351 null /* session transfer uri */, null /* generic link */); 1352 final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = 1353 ArgumentCaptor.forClass(Function1.class); 1354 1355 createHandleMenu(decor); 1356 verify(mMockHandleMenu).show(any(), 1357 any(), 1358 any(), 1359 any(), 1360 any(), 1361 any(), 1362 any(), 1363 openInBrowserCaptor.capture(), 1364 any(), 1365 any(), 1366 any(), 1367 any(), 1368 anyBoolean() 1369 ); 1370 // Run runnable to set captured link to used 1371 openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1)); 1372 1373 // Relayout decor with same captured link 1374 decor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1375 1376 // Verify handle menu's browser link not set to captured link since link is already used 1377 createHandleMenu(decor); 1378 verifyHandleMenuCreated(null /* uri */); 1379 } 1380 1381 @Test 1382 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) capturedLink_capturedLinkSetToUsedAfterClick()1383 public void capturedLink_capturedLinkSetToUsedAfterClick() { 1384 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1385 final DesktopModeWindowDecoration decor = createWindowDecoration( 1386 taskInfo, TEST_URI1 /* captured link */, null /* web uri */, 1387 null /* session transfer uri */, null /* generic link */); 1388 final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = 1389 ArgumentCaptor.forClass(Function1.class); 1390 1391 // Simulate menu opening and clicking open in browser button 1392 createHandleMenu(decor); 1393 verify(mMockHandleMenu).show( 1394 any(), 1395 any(), 1396 any(), 1397 any(), 1398 any(), 1399 any(), 1400 any(), 1401 openInBrowserCaptor.capture(), 1402 any(), 1403 any(), 1404 any(), 1405 any(), 1406 anyBoolean() 1407 ); 1408 openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1)); 1409 1410 // Verify handle menu's browser link not set to captured link since link not valid after 1411 // open in browser clicked 1412 createHandleMenu(decor); 1413 verifyHandleMenuCreated(null /* uri */); 1414 } 1415 1416 @Test 1417 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) capturedLink_openInBrowserListenerCalledOnClick()1418 public void capturedLink_openInBrowserListenerCalledOnClick() { 1419 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1420 final DesktopModeWindowDecoration decor = createWindowDecoration( 1421 taskInfo, TEST_URI1 /* captured link */, null /* web uri */, 1422 null /* session transfer uri */, null /* generic link */); 1423 final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = 1424 ArgumentCaptor.forClass(Function1.class); 1425 createHandleMenu(decor); 1426 verify(mMockHandleMenu).show( 1427 any(), 1428 any(), 1429 any(), 1430 any(), 1431 any(), 1432 any(), 1433 any(), 1434 openInBrowserCaptor.capture(), 1435 any(), 1436 any(), 1437 any(), 1438 any(), 1439 anyBoolean() 1440 ); 1441 1442 openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1)); 1443 1444 verify(mMockOpenInBrowserClickListener).accept( 1445 argThat(intent -> intent.getData() == TEST_URI1)); 1446 } 1447 1448 @Test 1449 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) sessionTransferUri_sessionTransferUriUsedWhenWhenAvailable()1450 public void sessionTransferUri_sessionTransferUriUsedWhenWhenAvailable() { 1451 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1452 final DesktopModeWindowDecoration decor = createWindowDecoration( 1453 taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, 1454 TEST_URI3 /* session transfer uri */, TEST_URI4 /* generic link */); 1455 // Verify handle menu's browser link set as web uri link when captured link is unavailable 1456 createHandleMenu(decor); 1457 verifyHandleMenuCreated(TEST_URI3); 1458 } 1459 1460 @Test 1461 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) webUri_webUriUsedWhenSessionTransferUriUnavailable()1462 public void webUri_webUriUsedWhenSessionTransferUriUnavailable() { 1463 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1464 final DesktopModeWindowDecoration decor = createWindowDecoration( 1465 taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, 1466 null /* session transfer uri */, TEST_URI4 /* generic link */); 1467 // Verify handle menu's browser link set as web uri link when captured link is unavailable 1468 createHandleMenu(decor); 1469 verifyHandleMenuCreated(TEST_URI2); 1470 } 1471 1472 @Test 1473 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) genericLink_genericLinkUsedWhenCapturedLinkAndAssistContentUriUnavailable()1474 public void genericLink_genericLinkUsedWhenCapturedLinkAndAssistContentUriUnavailable() { 1475 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1476 final DesktopModeWindowDecoration decor = createWindowDecoration( 1477 taskInfo, null /* captured link */, null /* web uri */, 1478 null /* session transfer uri */, TEST_URI4 /* generic link */); 1479 1480 // Verify handle menu's browser link set as generic link when captured link and web uri link 1481 // are unavailable 1482 createHandleMenu(decor); 1483 verifyHandleMenuCreated(TEST_URI4); 1484 } 1485 1486 @Test handleMenu_onCloseMenuClick_closesMenu()1487 public void handleMenu_onCloseMenuClick_closesMenu() { 1488 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1489 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1490 true /* relayout */); 1491 final ArgumentCaptor<Function0<Unit>> closeClickListener = 1492 ArgumentCaptor.forClass(Function0.class); 1493 createHandleMenu(decoration); 1494 verify(mMockHandleMenu).show( 1495 any(), 1496 any(), 1497 any(), 1498 any(), 1499 any(), 1500 any(), 1501 any(), 1502 any(), 1503 any(), 1504 any(), 1505 closeClickListener.capture(), 1506 any(), 1507 anyBoolean() 1508 ); 1509 1510 closeClickListener.getValue().invoke(); 1511 1512 verify(mMockHandleMenu).close(); 1513 assertFalse(decoration.isHandleMenuActive()); 1514 } 1515 1516 @Test createHandleMenu_immersiveWindow_forceShowsSystemBars()1517 public void createHandleMenu_immersiveWindow_forceShowsSystemBars() { 1518 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1519 final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, 1520 true /* relayout */); 1521 when(mMockDesktopUserRepositories.getCurrent() 1522 .isTaskInFullImmersiveState(taskInfo.taskId)).thenReturn(true); 1523 1524 createHandleMenu(decoration); 1525 1526 verify(mMockHandleMenu).show( 1527 any(), 1528 any(), 1529 any(), 1530 any(), 1531 any(), 1532 any(), 1533 any(), 1534 any(), 1535 any(), 1536 any(), 1537 any(), 1538 any(), 1539 /* forceShowSystemBars= */ eq(true) 1540 ); 1541 } 1542 1543 @Test 1544 @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION, 1545 Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION_INTEGRATION}) notifyCaptionStateChanged_flagDisabled_doNoNotify()1546 public void notifyCaptionStateChanged_flagDisabled_doNoNotify() { 1547 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1548 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1549 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1550 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1551 1552 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1553 1554 verify(mMockCaptionHandleRepository, never()).notifyCaptionChanged(any()); 1555 } 1556 1557 @Test 1558 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible()1559 public void notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible() { 1560 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1561 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1562 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1563 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1564 ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( 1565 CaptionState.class); 1566 1567 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1568 1569 verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged( 1570 captionStateArgumentCaptor.capture()); 1571 assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf( 1572 CaptionState.AppHandle.class); 1573 } 1574 1575 @Test 1576 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) 1577 @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error") notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible()1578 public void notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible() { 1579 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1580 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1581 when(mMockAppHeaderViewHolder.getAppChipLocationInWindow()).thenReturn( 1582 new Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3)); 1583 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1584 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); 1585 // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT) 1586 taskInfo.isResizeable = false; 1587 ArgumentCaptor<Function0<Unit>> runnableArgumentCaptor = ArgumentCaptor.forClass( 1588 Function0.class); 1589 ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( 1590 CaptionState.class); 1591 1592 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1593 verify(mMockAppHeaderViewHolder, atLeastOnce()).runOnAppChipGlobalLayout( 1594 runnableArgumentCaptor.capture()); 1595 runnableArgumentCaptor.getValue().invoke(); 1596 1597 verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged( 1598 captionStateArgumentCaptor.capture()); 1599 assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf( 1600 CaptionState.AppHeader.class); 1601 } 1602 1603 @Test 1604 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible()1605 public void notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible() { 1606 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1607 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ false); 1608 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1609 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); 1610 ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( 1611 CaptionState.class); 1612 1613 spyWindowDecor.relayout(taskInfo, false /* hasGlobalFocus */, mExclusionRegion); 1614 1615 verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged( 1616 captionStateArgumentCaptor.capture()); 1617 assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf( 1618 CaptionState.NoCaption.class); 1619 } 1620 1621 @Test 1622 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded()1623 public void notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded() { 1624 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1625 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1626 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1627 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1628 ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( 1629 CaptionState.class); 1630 1631 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1632 createHandleMenu(spyWindowDecor); 1633 1634 verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged( 1635 captionStateArgumentCaptor.capture()); 1636 assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf( 1637 CaptionState.AppHandle.class); 1638 assertThat( 1639 ((CaptionState.AppHandle) captionStateArgumentCaptor.getValue()) 1640 .isHandleMenuExpanded()).isEqualTo( 1641 true); 1642 } 1643 1644 @Test 1645 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed()1646 public void notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed() { 1647 when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); 1648 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); 1649 final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); 1650 taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1651 ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( 1652 CaptionState.class); 1653 1654 spyWindowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1655 createHandleMenu(spyWindowDecor); 1656 spyWindowDecor.closeHandleMenu(); 1657 1658 verify(mMockCaptionHandleRepository, atLeastOnce()).notifyCaptionChanged( 1659 captionStateArgumentCaptor.capture()); 1660 assertThat(captionStateArgumentCaptor.getValue()).isInstanceOf( 1661 CaptionState.AppHandle.class); 1662 assertThat( 1663 ((CaptionState.AppHandle) captionStateArgumentCaptor.getValue()) 1664 .isHandleMenuExpanded()).isEqualTo( 1665 false); 1666 1667 } 1668 1669 @Test 1670 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) browserApp_transferSessionUriUsedForBrowserAppWhenAvailable()1671 public void browserApp_transferSessionUriUsedForBrowserAppWhenAvailable() { 1672 // Make {@link AppToWebUtils#isBrowserApp} return true 1673 ResolveInfo browserResolveInfo = createResolveInfo(true /* handleAllWebUriData */); 1674 when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())) 1675 .thenReturn(List.of(browserResolveInfo)); 1676 1677 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1678 final DesktopModeWindowDecoration decor = createWindowDecoration( 1679 taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, 1680 null /* transfer session uri */, TEST_URI4 /* generic link */); 1681 1682 // Verify web uri used for browser applications 1683 createHandleMenu(decor); 1684 verifyHandleMenuCreated(TEST_URI2); 1685 } 1686 1687 1688 @Test 1689 @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) browserApp_webUriUsedForBrowserAppWhenTransferSessionUriUnavailable()1690 public void browserApp_webUriUsedForBrowserAppWhenTransferSessionUriUnavailable() { 1691 // Make {@link AppToWebUtils#isBrowserApp} return true 1692 ResolveInfo resolveInfo = new ResolveInfo(); 1693 resolveInfo.handleAllWebDataURI = true; 1694 resolveInfo.activityInfo = createActivityInfo(); 1695 when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())) 1696 .thenReturn(List.of(resolveInfo)); 1697 1698 final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); 1699 final DesktopModeWindowDecoration decor = createWindowDecoration( 1700 taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, 1701 TEST_URI3 /* transfer session uri */, TEST_URI4 /* generic link */); 1702 1703 // Verify web uri used for browser applications 1704 createHandleMenu(decor); 1705 verifyHandleMenuCreated(TEST_URI3); 1706 } 1707 1708 verifyHandleMenuCreated(@ullable Uri uri)1709 private void verifyHandleMenuCreated(@Nullable Uri uri) { 1710 verify(mMockHandleMenuFactory).create(any(), any(), any(), any(), any(), anyInt(), 1711 any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), 1712 anyBoolean(), anyBoolean(), argThat(intent -> 1713 (uri == null && intent == null) || intent.getData().equals(uri)), 1714 any(), anyInt(), anyInt(), anyInt(), anyInt()); 1715 } 1716 createMaximizeMenu(DesktopModeWindowDecoration decoration)1717 private void createMaximizeMenu(DesktopModeWindowDecoration decoration) { 1718 final Function0<Unit> l = () -> Unit.INSTANCE; 1719 decoration.setOnMaximizeOrRestoreClickListener(l); 1720 decoration.setOnImmersiveOrRestoreClickListener(l); 1721 decoration.setOnLeftSnapClickListener(l); 1722 decoration.setOnRightSnapClickListener(l); 1723 decoration.createMaximizeMenu(); 1724 } 1725 fillRoundedCornersResources(int fillValue)1726 private void fillRoundedCornersResources(int fillValue) { 1727 when(mMockRoundedCornersRadiusArray.getDimensionPixelSize(anyInt(), anyInt())) 1728 .thenReturn(fillValue); 1729 mTestableContext.getOrCreateTestableResources().addOverride( 1730 R.array.config_roundedCornerRadiusArray, mMockRoundedCornersRadiusArray); 1731 mTestableContext.getOrCreateTestableResources().addOverride( 1732 R.dimen.rounded_corner_radius, fillValue); 1733 mTestableContext.getOrCreateTestableResources().addOverride( 1734 R.array.config_roundedCornerTopRadiusArray, mMockRoundedCornersRadiusArray); 1735 mTestableContext.getOrCreateTestableResources().addOverride( 1736 R.dimen.rounded_corner_radius_top, fillValue); 1737 mTestableContext.getOrCreateTestableResources().addOverride( 1738 R.array.config_roundedCornerBottomRadiusArray, mMockRoundedCornersRadiusArray); 1739 mTestableContext.getOrCreateTestableResources().addOverride( 1740 R.dimen.rounded_corner_radius_bottom, fillValue); 1741 } 1742 updateRelayoutParams( RelayoutParams relayoutParams, ActivityManager.RunningTaskInfo taskInfo)1743 private void updateRelayoutParams( 1744 RelayoutParams relayoutParams, ActivityManager.RunningTaskInfo taskInfo) { 1745 DesktopModeWindowDecoration.updateRelayoutParams( 1746 relayoutParams, 1747 mTestableContext, 1748 taskInfo, 1749 mMockSplitScreenController, 1750 DEFAULT_APPLY_START_TRANSACTION_ON_DRAW, 1751 DEFAULT_SHOULD_SET_TASK_POSITIONING_AND_CROP, 1752 DEFAULT_IS_STATUSBAR_VISIBLE, 1753 DEFAULT_IS_KEYGUARD_VISIBLE_AND_OCCLUDED, 1754 DEFAULT_IS_IN_FULL_IMMERSIVE_MODE, 1755 DEFAULT_IS_DRAGGING, 1756 new InsetsState(), 1757 DEFAULT_HAS_GLOBAL_FOCUS, 1758 mExclusionRegion, 1759 DEFAULT_SHOULD_IGNORE_CORNER_RADIUS, 1760 DEFAULT_SHOULD_EXCLUDE_CAPTION_FROM_APP_BOUNDS); 1761 } 1762 createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, @Nullable Uri capturedLink, @Nullable Uri webUri, @Nullable Uri sessionTransferUri, @Nullable Uri genericLink)1763 private DesktopModeWindowDecoration createWindowDecoration( 1764 ActivityManager.RunningTaskInfo taskInfo, @Nullable Uri capturedLink, 1765 @Nullable Uri webUri, @Nullable Uri sessionTransferUri, @Nullable Uri genericLink) { 1766 taskInfo.capturedLink = capturedLink; 1767 taskInfo.capturedLinkTimestamp = System.currentTimeMillis(); 1768 mAssistContent.setWebUri(webUri); 1769 mAssistContent.setSessionTransferUri(sessionTransferUri); 1770 final String genericLinkString = genericLink == null ? null : genericLink.toString(); 1771 doReturn(genericLinkString).when(mMockGenericLinksParser).getGenericLink(any()); 1772 // Relayout to set captured link 1773 return createWindowDecoration(taskInfo, new FakeMaximizeMenuFactory(), true /* relayout */); 1774 } 1775 createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo)1776 private DesktopModeWindowDecoration createWindowDecoration( 1777 ActivityManager.RunningTaskInfo taskInfo) { 1778 return createWindowDecoration(taskInfo, new FakeMaximizeMenuFactory(), 1779 false /* relayout */); 1780 } 1781 createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, boolean relayout)1782 private DesktopModeWindowDecoration createWindowDecoration( 1783 ActivityManager.RunningTaskInfo taskInfo, boolean relayout) { 1784 return createWindowDecoration(taskInfo, new FakeMaximizeMenuFactory(), relayout); 1785 } 1786 createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, MaximizeMenuFactory maximizeMenuFactory)1787 private DesktopModeWindowDecoration createWindowDecoration( 1788 ActivityManager.RunningTaskInfo taskInfo, 1789 MaximizeMenuFactory maximizeMenuFactory) { 1790 return createWindowDecoration(taskInfo, maximizeMenuFactory, false /* relayout */); 1791 } 1792 createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, MaximizeMenuFactory maximizeMenuFactory, boolean relayout)1793 private DesktopModeWindowDecoration createWindowDecoration( 1794 ActivityManager.RunningTaskInfo taskInfo, 1795 MaximizeMenuFactory maximizeMenuFactory, 1796 boolean relayout) { 1797 final DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext, 1798 mContext, mMockDisplayController, mMockTaskResourceLoader, 1799 mMockSplitScreenController, mMockDesktopUserRepositories, mMockShellTaskOrganizer, 1800 taskInfo, mMockSurfaceControl, mMockHandler, mMainExecutor, 1801 mMockMainCoroutineDispatcher, mMockBgCoroutineScope, mBgExecutor, 1802 mMockChoreographer, mMockSyncQueue, mMockAppHeaderViewHolderFactory, 1803 mMockAppHandleViewHolderFactory, mMockRootTaskDisplayAreaOrganizer, 1804 mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new, 1805 mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, 1806 new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory, 1807 mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory, 1808 mMockMultiInstanceHelper, mMockCaptionHandleRepository, mDesktopModeEventLogger, 1809 mDesktopModeUiEventLogger, mDesktopModeCompatPolicy); 1810 windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener, 1811 mMockTouchEventListener, mMockTouchEventListener); 1812 windowDecor.setExclusionRegionListener(mMockExclusionRegionListener); 1813 windowDecor.setOpenInBrowserClickListener(mMockOpenInBrowserClickListener); 1814 windowDecor.mDecorWindowContext = mContext; 1815 if (relayout) { 1816 windowDecor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion); 1817 } 1818 return windowDecor; 1819 } 1820 createResolveInfo(boolean handleAllWebDataURI)1821 private ResolveInfo createResolveInfo(boolean handleAllWebDataURI) { 1822 final ResolveInfo info = new ResolveInfo(); 1823 info.handleAllWebDataURI = handleAllWebDataURI; 1824 info.activityInfo = createActivityInfo(); 1825 return info; 1826 } 1827 createTaskInfo(boolean visible)1828 private ActivityManager.RunningTaskInfo createTaskInfo(boolean visible) { 1829 final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = 1830 new ActivityManager.TaskDescription.Builder(); 1831 ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() 1832 .setDisplayId(Display.DEFAULT_DISPLAY) 1833 .setTaskDescriptionBuilder(taskDescriptionBuilder) 1834 .setVisible(visible) 1835 .build(); 1836 taskInfo.isVisibleRequested = visible; 1837 taskInfo.realActivity = new ComponentName("com.android.wm.shell.windowdecor", 1838 "DesktopModeWindowDecorationTests"); 1839 taskInfo.baseActivity = new ComponentName("com.android.wm.shell.windowdecor", 1840 "DesktopModeWindowDecorationTests"); 1841 taskInfo.topActivityInfo = createActivityInfo(); 1842 return taskInfo; 1843 1844 } 1845 createHandleMenu(@onNull DesktopModeWindowDecoration decor)1846 private void createHandleMenu(@NonNull DesktopModeWindowDecoration decor) { 1847 decor.createHandleMenu(false); 1848 // Call DesktopModeWindowDecoration#onAssistContentReceived because decor waits to receive 1849 // {@link AssistContent} before creating the menu 1850 decor.onAssistContentReceived(mAssistContent); 1851 } 1852 createActivityInfo()1853 private static ActivityInfo createActivityInfo() { 1854 final ApplicationInfo applicationInfo = new ApplicationInfo(); 1855 applicationInfo.packageName = "DesktopModeWindowDecorationTestPackage"; 1856 final ActivityInfo activityInfo = new ActivityInfo(); 1857 activityInfo.applicationInfo = applicationInfo; 1858 activityInfo.packageName = "DesktopModeWindowDecorationTestPackage"; 1859 activityInfo.name = "DesktopModeWindowDecorationTest"; 1860 return activityInfo; 1861 } 1862 hasNoInputChannelFeature(RelayoutParams params)1863 private static boolean hasNoInputChannelFeature(RelayoutParams params) { 1864 return (params.mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) 1865 != 0; 1866 } 1867 createInsetsSource(int id, @WindowInsets.Type.InsetsType int type, boolean visible, @NonNull Rect frame)1868 private InsetsSource createInsetsSource(int id, @WindowInsets.Type.InsetsType int type, 1869 boolean visible, @NonNull Rect frame) { 1870 final InsetsSource source = new InsetsSource(id, type); 1871 source.setVisible(visible); 1872 source.setFrame(frame); 1873 return source; 1874 } 1875 createInsetsState(@onNull List<InsetsSource> sources)1876 private InsetsState createInsetsState(@NonNull List<InsetsSource> sources) { 1877 final InsetsState state = new InsetsState(); 1878 sources.forEach(state::addSource); 1879 return state; 1880 } 1881 createInsetsState(@indowInsets.Type.InsetsType int type, boolean visible)1882 private InsetsState createInsetsState(@WindowInsets.Type.InsetsType int type, boolean visible) { 1883 final InsetsSource source = createInsetsSource(0 /* id */, type, visible, new Rect()); 1884 return createInsetsState(List.of(source)); 1885 } 1886 1887 private static class TestTouchEventListener extends GestureDetector.SimpleOnGestureListener 1888 implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, 1889 View.OnGenericMotionListener, DragDetector.MotionEventHandler { 1890 1891 @Override onClick(View v)1892 public void onClick(View v) {} 1893 1894 @Override onGenericMotion(View v, MotionEvent event)1895 public boolean onGenericMotion(View v, MotionEvent event) { 1896 return false; 1897 } 1898 1899 @Override onLongClick(View v)1900 public boolean onLongClick(View v) { 1901 return false; 1902 } 1903 1904 @Override onTouch(View v, MotionEvent event)1905 public boolean onTouch(View v, MotionEvent event) { 1906 return false; 1907 } 1908 1909 @Override handleMotionEvent(@ullable View v, MotionEvent ev)1910 public boolean handleMotionEvent(@Nullable View v, MotionEvent ev) { 1911 return false; 1912 } 1913 } 1914 1915 private static final class FakeMaximizeMenuFactory implements MaximizeMenuFactory { 1916 private final MaximizeMenu mMaximizeMenu; 1917 FakeMaximizeMenuFactory()1918 FakeMaximizeMenuFactory() { 1919 this(mock(MaximizeMenu.class)); 1920 } 1921 FakeMaximizeMenuFactory(MaximizeMenu menu)1922 FakeMaximizeMenuFactory(MaximizeMenu menu) { 1923 mMaximizeMenu = menu; 1924 } 1925 1926 @NonNull 1927 @Override create(@onNull SyncTransactionQueue syncQueue, @NonNull RootTaskDisplayAreaOrganizer rootTdaOrganizer, @NonNull DisplayController displayController, @NonNull ActivityManager.RunningTaskInfo taskInfo, @NonNull Context decorWindowContext, @NonNull Function2<? super Integer,? super Integer,? extends Point> positionSupplier, @NonNull Supplier<SurfaceControl.Transaction> transactionSupplier, @NonNull DesktopModeUiEventLogger desktopModeUiEventLogger)1928 public MaximizeMenu create(@NonNull SyncTransactionQueue syncQueue, 1929 @NonNull RootTaskDisplayAreaOrganizer rootTdaOrganizer, 1930 @NonNull DisplayController displayController, 1931 @NonNull ActivityManager.RunningTaskInfo taskInfo, 1932 @NonNull Context decorWindowContext, 1933 @NonNull Function2<? super Integer,? super Integer,? extends Point> 1934 positionSupplier, 1935 @NonNull Supplier<SurfaceControl.Transaction> transactionSupplier, 1936 @NonNull DesktopModeUiEventLogger desktopModeUiEventLogger) { 1937 return mMaximizeMenu; 1938 } 1939 } 1940 } 1941