• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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