diff options
| author | 2022-02-09 12:32:28 +0000 | |
|---|---|---|
| committer | 2022-02-17 16:53:38 +0000 | |
| commit | c295edad0bb699d89a4904aecc1d5152dfe7c0f2 (patch) | |
| tree | b98b64f2ab3a6bf1a2b0cb92a01ee75c24062d39 | |
| parent | 68eb4fb58640a0a0fb65a2269da475afb1d6c257 (diff) | |
[14/n] Letterbox Education: Add tests for WM shell code.
In addition, this CL does additional polishing to the code itself.
Bug: 215316431
Test: atest WMShellUnitTests:LetterboxEduDialogLayoutTest
Test: atest WMShellUnitTests:LetterboxEduWindowManagerTest
Test: atest WMShellUnitTests:CompatUIControllerTest
Change-Id: I3cb58f89a52f0d427545e3959dd9082e8b8b5cc7
9 files changed, 653 insertions, 86 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 656dae3af5ac..4ee3c0d8c34e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -292,9 +292,8 @@ public class CompatUIController implements OnDisplaysChangedListener, if (context == null) { return; } - LetterboxEduWindowManager newLayout = new LetterboxEduWindowManager(context, taskInfo, - mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), - this::onLetterboxEduDismissed); + LetterboxEduWindowManager newLayout = createLetterboxEduWindowManager(context, taskInfo, + taskListener); if (newLayout.createLayout(showOnDisplay(taskInfo.displayId))) { // The new layout is eligible to be shown, make it the active layout. if (mActiveLetterboxEduLayout != null) { @@ -307,6 +306,14 @@ public class CompatUIController implements OnDisplaysChangedListener, } } + @VisibleForTesting + LetterboxEduWindowManager createLetterboxEduWindowManager(Context context, TaskInfo taskInfo, + ShellTaskOrganizer.TaskListener taskListener) { + return new LetterboxEduWindowManager(context, taskInfo, + mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), + this::onLetterboxEduDismissed); + } + private void onLetterboxEduDismissed() { mActiveLetterboxEduLayout = null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java index 5679bc479f93..face24340a4e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java @@ -22,6 +22,10 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; + import android.annotation.Nullable; import android.app.TaskInfo; import android.content.Context; @@ -110,7 +114,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana * @param canShow whether the layout is allowed to be shown by the parent controller. * @return whether the layout is eligible to be shown. */ - protected boolean createLayout(boolean canShow) { + @VisibleForTesting(visibility = PROTECTED) + public boolean createLayout(boolean canShow) { if (!eligibleToShowLayout()) { return false; } @@ -184,7 +189,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana * @param canShow whether the layout is allowed to be shown by the parent controller. * @return whether the layout is eligible to be shown. */ - protected boolean updateCompatInfo(TaskInfo taskInfo, + @VisibleForTesting(visibility = PROTECTED) + public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { final Configuration prevTaskConfig = mTaskConfig; final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener; @@ -201,7 +207,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana View layout = getLayout(); if (layout == null || prevTaskListener != taskListener) { - // TaskListener changed, recreate the layout for new surface parent. + // Layout wasn't created yet or TaskListener changed, recreate the layout for new + // surface parent. release(); return createLayout(canShow); } @@ -227,7 +234,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana * * @param canShow whether the layout is allowed to be shown by the parent controller. */ - void updateVisibility(boolean canShow) { + @VisibleForTesting(visibility = PACKAGE) + public void updateVisibility(boolean canShow) { View layout = getLayout(); if (layout == null) { // Layout may not have been created because it was hidden previously. @@ -242,7 +250,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana } /** Called when display layout changed. */ - void updateDisplayLayout(DisplayLayout displayLayout) { + @VisibleForTesting(visibility = PACKAGE) + public void updateDisplayLayout(DisplayLayout displayLayout) { final Rect prevStableBounds = mStableBounds; final Rect curStableBounds = new Rect(); displayLayout.getStableBounds(curStableBounds); @@ -255,7 +264,7 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana } /** Called when the surface is ready to be placed under the task surface. */ - @VisibleForTesting + @VisibleForTesting(visibility = PRIVATE) void attachToParentSurface(SurfaceControl.Builder b) { mTaskListener.attachChildSurfaceToTask(mTaskId, b); } @@ -347,8 +356,9 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana return result; } - @VisibleForTesting - SurfaceControlViewHost createSurfaceViewHost() { + /** Creates a {@link SurfaceControlViewHost} for this window manager. */ + @VisibleForTesting(visibility = PRIVATE) + public SurfaceControlViewHost createSurfaceViewHost() { return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java index 3810ecaf9f9e..03986ee3b6d2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java @@ -39,7 +39,6 @@ import com.android.internal.policy.TransitionAnimation; /** * Controls the enter/exit animations of the letterbox education. */ -// TODO(b/215316431): Add tests class LetterboxEduAnimationController { private static final String TAG = "LetterboxEduAnimation"; @@ -99,15 +98,10 @@ class LetterboxEduAnimationController { /** * Starts both the background dim fade-out animation and the dialog exit animation. */ - void startExitAnimation(@Nullable LetterboxEduDialogLayout layout, Runnable endCallback) { + void startExitAnimation(@NonNull LetterboxEduDialogLayout layout, Runnable endCallback) { // Cancel any previous animation if it's still running. cancelAnimation(); - if (layout == null) { - endCallback.run(); - return; - } - final View dialogContainer = layout.getDialogContainer(); mDialogAnimation = loadAnimation(WindowAnimation_windowExitAnimation); if (mDialogAnimation == null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java index fc6fd3f2c959..02197f644a39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java @@ -29,18 +29,28 @@ import com.android.wm.shell.R; /** * Custom layout for Letterbox Education dialog action. */ -// TODO(b/215316431): Add tests class LetterboxEduDialogActionLayout extends FrameLayout { - LetterboxEduDialogActionLayout(Context context, AttributeSet attrs) { - super(context, attrs); + public LetterboxEduDialogActionLayout(Context context) { + this(context, null); + } + + public LetterboxEduDialogActionLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LetterboxEduDialogActionLayout(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public LetterboxEduDialogActionLayout(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); TypedArray styledAttributes = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.LetterboxEduDialogActionLayout, - /* defStyleAttr= */ 0, - /* defStyleRes= */ 0); + attrs, R.styleable.LetterboxEduDialogActionLayout, defStyleAttr, + defStyleRes); int iconId = styledAttributes.getResourceId( R.styleable.LetterboxEduDialogActionLayout_icon, 0); String text = styledAttributes.getString( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java index bb6fe9816905..2da6a6bc70c0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java @@ -16,6 +16,7 @@ package com.android.wm.shell.compatui.letterboxedu; +import android.annotation.Nullable; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; @@ -31,7 +32,6 @@ import com.android.wm.shell.R; * <p>This layout should fill the entire task and the background around the dialog acts as the * background dim which dismisses the dialog when clicked. */ -// TODO(b/215316431): Add tests class LetterboxEduDialogLayout extends ConstraintLayout { // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque). @@ -68,16 +68,16 @@ class LetterboxEduDialogLayout extends ConstraintLayout { /** * Register a callback for the dismiss button and background dim. * - * @param callback The callback to register + * @param callback The callback to register or null if all on click listeners should be removed. */ - void setDismissOnClickListener(Runnable callback) { - findViewById(R.id.letterbox_education_dialog_dismiss_button).setOnClickListener( - view -> callback.run()); + void setDismissOnClickListener(@Nullable Runnable callback) { + final OnClickListener listener = callback == null ? null : view -> callback.run(); + findViewById(R.id.letterbox_education_dialog_dismiss_button).setOnClickListener(listener); // Clicks on the background dim should also dismiss the dialog. - setOnClickListener(view -> callback.run()); + setOnClickListener(listener); // We add a no-op on-click listener to the dialog container so that clicks on it won't // propagate to the listener of the layout (which represents the background dim). - mDialogContainer.setOnClickListener(view -> {}); + mDialogContainer.setOnClickListener(callback == null ? null : view -> {}); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java index bb4d4275d47f..30b9f0838e10 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java @@ -29,6 +29,7 @@ import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.view.WindowManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayLayout; @@ -38,7 +39,6 @@ import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract; /** * Window manager for the Letterbox Education. */ -// TODO(b/215316431): Add tests public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { /** @@ -51,7 +51,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox * Education for specific packages and which user has seen the full dialog for any package. */ - private static final String HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME = + @VisibleForTesting + static final String HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME = "has_seen_letterbox_education"; /** @@ -65,19 +66,37 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { private boolean mEligibleForLetterboxEducation; @Nullable - private LetterboxEduDialogLayout mLayout; + @VisibleForTesting + LetterboxEduDialogLayout mLayout; private final Runnable mOnDismissCallback; + /** + * The vertical margin between the dialog container and the task stable bounds (excluding + * insets). + */ + private final int mDialogVerticalMargin; + public LetterboxEduWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, Runnable onDismissCallback) { + this(context, taskInfo, syncQueue, taskListener, displayLayout, onDismissCallback, + new LetterboxEduAnimationController(context)); + } + + @VisibleForTesting + LetterboxEduWindowManager(Context context, TaskInfo taskInfo, + SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener, + DisplayLayout displayLayout, Runnable onDismissCallback, + LetterboxEduAnimationController animationController) { super(context, taskInfo, syncQueue, taskListener, displayLayout); mOnDismissCallback = onDismissCallback; + mAnimationController = animationController; mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation; - mAnimationController = new LetterboxEduAnimationController(context); mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME, Context.MODE_PRIVATE); + mDialogVerticalMargin = (int) mContext.getResources().getDimension( + R.dimen.letterbox_education_dialog_margin); } @Override @@ -124,13 +143,12 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { } final View dialogContainer = mLayout.getDialogContainer(); MarginLayoutParams marginParams = (MarginLayoutParams) dialogContainer.getLayoutParams(); - int verticalMargin = (int) mContext.getResources().getDimension( - R.dimen.letterbox_education_dialog_margin); final Rect taskBounds = getTaskBounds(); final Rect taskStableBounds = getTaskStableBounds(); - marginParams.topMargin = taskStableBounds.top - taskBounds.top + verticalMargin; - marginParams.bottomMargin = taskBounds.bottom - taskStableBounds.bottom + verticalMargin; + marginParams.topMargin = taskStableBounds.top - taskBounds.top + mDialogVerticalMargin; + marginParams.bottomMargin = + taskBounds.bottom - taskStableBounds.bottom + mDialogVerticalMargin; dialogContainer.setLayoutParams(marginParams); } @@ -147,6 +165,10 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { } private void onDismiss() { + if (mLayout == null) { + return; + } + mLayout.setDismissOnClickListener(null); mAnimationController.startExitAnimation(mLayout, () -> { release(); mOnDismissCallback.run(); @@ -204,7 +226,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { return String.valueOf(mContext.getUserId()); } - private boolean isTaskbarEduShowing() { + @VisibleForTesting + boolean isTaskbarEduShowing() { return Settings.Secure.getInt(mContext.getContentResolver(), LAUNCHER_TASKBAR_EDUCATION_SHOWING, /* def= */ 0) == 1; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index c5be4854ae8f..29e40be457d1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -52,6 +52,7 @@ import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListen import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager; import org.junit.Before; import org.junit.Test; @@ -81,7 +82,8 @@ public class CompatUIControllerTest extends ShellTestCase { private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener; private @Mock SyncTransactionQueue mMockSyncQueue; private @Mock ShellExecutor mMockExecutor; - private @Mock CompatUIWindowManager mMockLayout; + private @Mock CompatUIWindowManager mMockCompatLayout; + private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout; @Captor ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor; @@ -91,16 +93,26 @@ public class CompatUIControllerTest extends ShellTestCase { MockitoAnnotations.initMocks(this); doReturn(mMockDisplayLayout).when(mMockDisplayController).getDisplayLayout(anyInt()); - doReturn(DISPLAY_ID).when(mMockLayout).getDisplayId(); - doReturn(TASK_ID).when(mMockLayout).getTaskId(); - doReturn(true).when(mMockLayout).createLayout(anyBoolean()); - doReturn(true).when(mMockLayout).updateCompatInfo(any(), any(), anyBoolean()); + doReturn(DISPLAY_ID).when(mMockCompatLayout).getDisplayId(); + doReturn(TASK_ID).when(mMockCompatLayout).getTaskId(); + doReturn(true).when(mMockCompatLayout).createLayout(anyBoolean()); + doReturn(true).when(mMockCompatLayout).updateCompatInfo(any(), any(), anyBoolean()); + doReturn(DISPLAY_ID).when(mMockLetterboxEduLayout).getDisplayId(); + doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId(); + doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean()); + doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean()); mController = new CompatUIController(mContext, mMockDisplayController, mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) { @Override CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { - return mMockLayout; + return mMockCompatLayout; + } + + @Override + LetterboxEduWindowManager createLetterboxEduWindowManager(Context context, + TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { + return mMockLetterboxEduLayout; } }; spyOn(mController); @@ -121,68 +133,95 @@ public class CompatUIControllerTest extends ShellTestCase { mController.onCompatInfoChanged(taskInfo, mMockTaskListener); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); + verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); - // Verify that the compat controls are updated with new size compat info. - clearInvocations(mMockLayout); + // Verify that the compat controls and letterbox education are updated with new size compat + // info. + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); clearInvocations(mController); taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ true); + verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + true); + verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + true); - // Verify that compat controls are removed with null task listener. - clearInvocations(mMockLayout); + // Verify that compat controls and letterbox education are removed with null task listener. + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); clearInvocations(mController); mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), /* taskListener= */ null); - verify(mMockLayout).release(); + verify(mMockCompatLayout).release(); + verify(mMockLetterboxEduLayout).release(); } @Test public void testOnCompatInfoChanged_createLayoutReturnsFalse() { - doReturn(false).when(mMockLayout).createLayout(anyBoolean()); + doReturn(false).when(mMockCompatLayout).createLayout(anyBoolean()); + doReturn(false).when(mMockLetterboxEduLayout).createLayout(anyBoolean()); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); + verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); // Verify that the layout is created again. - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); clearInvocations(mController); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); + verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); + verify(mMockLetterboxEduLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); + verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); } @Test public void testOnCompatInfoChanged_updateCompatInfoReturnsFalse() { - doReturn(false).when(mMockLayout).updateCompatInfo(any(), any(), anyBoolean()); + doReturn(false).when(mMockCompatLayout).updateCompatInfo(any(), any(), anyBoolean()); + doReturn(false).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean()); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); + verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); clearInvocations(mController); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ true); + verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + true); + verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + true); // Verify that the layout is created again. - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); clearInvocations(mController); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); + verify(mMockCompatLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); + verify(mMockLetterboxEduLayout, never()).updateCompatInfo(any(), any(), anyBoolean()); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); + verify(mController).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); } @@ -204,14 +243,16 @@ public class CompatUIControllerTest extends ShellTestCase { mController.onDisplayRemoved(DISPLAY_ID + 1); - verify(mMockLayout, never()).release(); + verify(mMockCompatLayout, never()).release(); + verify(mMockLetterboxEduLayout, never()).release(); verify(mMockDisplayInsetsController, never()).removeInsetsChangedListener(eq(DISPLAY_ID), any()); mController.onDisplayRemoved(DISPLAY_ID); verify(mMockDisplayInsetsController).removeInsetsChangedListener(eq(DISPLAY_ID), any()); - verify(mMockLayout).release(); + verify(mMockCompatLayout).release(); + verify(mMockLetterboxEduLayout).release(); } @Test @@ -221,11 +262,13 @@ public class CompatUIControllerTest extends ShellTestCase { mController.onDisplayConfigurationChanged(DISPLAY_ID + 1, new Configuration()); - verify(mMockLayout, never()).updateDisplayLayout(any()); + verify(mMockCompatLayout, never()).updateDisplayLayout(any()); + verify(mMockLetterboxEduLayout, never()).updateDisplayLayout(any()); mController.onDisplayConfigurationChanged(DISPLAY_ID, new Configuration()); - verify(mMockLayout).updateDisplayLayout(mMockDisplayLayout); + verify(mMockCompatLayout).updateDisplayLayout(mMockDisplayLayout); + verify(mMockLetterboxEduLayout).updateDisplayLayout(mMockDisplayLayout); } @Test @@ -242,104 +285,125 @@ public class CompatUIControllerTest extends ShellTestCase { mOnInsetsChangedListenerCaptor.capture()); mOnInsetsChangedListenerCaptor.getValue().insetsChanged(insetsState); - verify(mMockLayout).updateDisplayLayout(mMockDisplayLayout); + verify(mMockCompatLayout).updateDisplayLayout(mMockDisplayLayout); + verify(mMockLetterboxEduLayout).updateDisplayLayout(mMockDisplayLayout); // No update if the insets state is the same. - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); mOnInsetsChangedListenerCaptor.getValue().insetsChanged(new InsetsState(insetsState)); - verify(mMockLayout, never()).updateDisplayLayout(mMockDisplayLayout); + verify(mMockCompatLayout, never()).updateDisplayLayout(mMockDisplayLayout); + verify(mMockLetterboxEduLayout, never()).updateDisplayLayout(mMockDisplayLayout); } @Test - public void testChangeButtonVisibilityOnImeShowHide() { + public void testChangeLayoutsVisibilityOnImeShowHide() { mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); // Verify that the restart button is hidden after IME is showing. mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); - verify(mMockLayout).updateVisibility(false); + verify(mMockCompatLayout).updateVisibility(false); + verify(mMockLetterboxEduLayout).updateVisibility(false); // Verify button remains hidden while IME is showing. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); + verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + false); + verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + false); // Verify button is shown after IME is hidden. mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false); - verify(mMockLayout).updateVisibility(true); + verify(mMockCompatLayout).updateVisibility(true); + verify(mMockLetterboxEduLayout).updateVisibility(true); } @Test - public void testChangeButtonVisibilityOnKeyguardOccludedChanged() { + public void testChangeLayoutsVisibilityOnKeyguardOccludedChanged() { mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); // Verify that the restart button is hidden after keyguard becomes occluded. mController.onKeyguardOccludedChanged(true); - verify(mMockLayout).updateVisibility(false); + verify(mMockCompatLayout).updateVisibility(false); + verify(mMockLetterboxEduLayout).updateVisibility(false); // Verify button remains hidden while keyguard is occluded. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); mController.onCompatInfoChanged(taskInfo, mMockTaskListener); - verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); + verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + false); + verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ + false); // Verify button is shown after keyguard becomes not occluded. mController.onKeyguardOccludedChanged(false); - verify(mMockLayout).updateVisibility(true); + verify(mMockCompatLayout).updateVisibility(true); + verify(mMockLetterboxEduLayout).updateVisibility(true); } @Test - public void testButtonRemainsHiddenOnKeyguardOccludedFalseWhenImeIsShowing() { + public void testLayoutsRemainHiddenOnKeyguardOccludedFalseWhenImeIsShowing() { mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); mController.onKeyguardOccludedChanged(true); - verify(mMockLayout, times(2)).updateVisibility(false); + verify(mMockCompatLayout, times(2)).updateVisibility(false); + verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false); - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); // Verify button remains hidden after keyguard becomes not occluded since IME is showing. mController.onKeyguardOccludedChanged(false); - verify(mMockLayout).updateVisibility(false); + verify(mMockCompatLayout).updateVisibility(false); + verify(mMockLetterboxEduLayout).updateVisibility(false); // Verify button is shown after IME is not showing. mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false); - verify(mMockLayout).updateVisibility(true); + verify(mMockCompatLayout).updateVisibility(true); + verify(mMockLetterboxEduLayout).updateVisibility(true); } @Test - public void testButtonRemainsHiddenOnImeHideWhenKeyguardIsOccluded() { + public void testLayoutsRemainHiddenOnImeHideWhenKeyguardIsOccluded() { mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener); mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); mController.onKeyguardOccludedChanged(true); - verify(mMockLayout, times(2)).updateVisibility(false); + verify(mMockCompatLayout, times(2)).updateVisibility(false); + verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false); - clearInvocations(mMockLayout); + clearInvocations(mMockCompatLayout); + clearInvocations(mMockLetterboxEduLayout); // Verify button remains hidden after IME is hidden since keyguard is occluded. mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false); - verify(mMockLayout).updateVisibility(false); + verify(mMockCompatLayout).updateVisibility(false); + verify(mMockLetterboxEduLayout).updateVisibility(false); // Verify button is shown after keyguard becomes not occluded. mController.onKeyguardOccludedChanged(false); - verify(mMockLayout).updateVisibility(true); + verify(mMockCompatLayout).updateVisibility(true); + verify(mMockLetterboxEduLayout).updateVisibility(true); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java new file mode 100644 index 000000000000..00e4938d866c --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterboxedu; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link LetterboxEduDialogLayout}. + * + * Build/Install/Run: + * atest WMShellUnitTests:LetterboxEduDialogLayoutTest + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class LetterboxEduDialogLayoutTest extends ShellTestCase { + + @Mock + private Runnable mDismissCallback; + + private LetterboxEduDialogLayout mLayout; + private View mDismissButton; + private View mDialogContainer; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mLayout = (LetterboxEduDialogLayout) + LayoutInflater.from(mContext).inflate(R.layout.letterbox_education_dialog_layout, + null); + mDismissButton = mLayout.findViewById(R.id.letterbox_education_dialog_dismiss_button); + mDialogContainer = mLayout.findViewById(R.id.letterbox_education_dialog_container); + mLayout.setDismissOnClickListener(mDismissCallback); + } + + @Test + public void testOnFinishInflate() { + assertEquals(mLayout.getDialogContainer(), + mLayout.findViewById(R.id.letterbox_education_dialog_container)); + assertEquals(mLayout.getBackgroundDim(), mLayout.getBackground()); + assertEquals(mLayout.getBackground().getAlpha(), 0); + } + + @Test + public void testOnDismissButtonClicked() { + assertTrue(mDismissButton.performClick()); + + verify(mDismissCallback).run(); + } + + @Test + public void testOnBackgroundClicked() { + assertTrue(mLayout.performClick()); + + verify(mDismissCallback).run(); + } + + @Test + public void testOnDialogContainerClicked() { + assertTrue(mDialogContainer.performClick()); + + verify(mDismissCallback, never()).run(); + } + + @Test + public void testSetDismissOnClickListenerNull() { + mLayout.setDismissOnClickListener(null); + + assertFalse(mDismissButton.performClick()); + assertFalse(mLayout.performClick()); + assertFalse(mDialogContainer.performClick()); + + verify(mDismissCallback, never()).run(); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java new file mode 100644 index 000000000000..0509dd38abe0 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterboxedu; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.TaskInfo; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Insets; +import android.graphics.Rect; +import android.testing.AndroidTestingRunner; +import android.view.DisplayCutout; +import android.view.DisplayInfo; +import android.view.SurfaceControlViewHost; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.SyncTransactionQueue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link LetterboxEduWindowManager}. + * + * Build/Install/Run: + * atest WMShellUnitTests:LetterboxEduWindowManagerTest + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class LetterboxEduWindowManagerTest extends ShellTestCase { + + private static final int TASK_ID = 1; + + private static final int TASK_WIDTH = 200; + private static final int TASK_HEIGHT = 100; + private static final int DISPLAY_CUTOUT_TOP = 5; + private static final int DISPLAY_CUTOUT_BOTTOM = 10; + private static final int DISPLAY_CUTOUT_HORIZONTAL = 20; + + @Captor + private ArgumentCaptor<WindowManager.LayoutParams> mWindowAttrsCaptor; + @Captor + private ArgumentCaptor<Runnable> mEndCallbackCaptor; + + @Mock private LetterboxEduAnimationController mAnimationController; + @Mock private SyncTransactionQueue mSyncTransactionQueue; + @Mock private ShellTaskOrganizer.TaskListener mTaskListener; + @Mock private SurfaceControlViewHost mViewHost; + @Mock private Runnable mOnDismissCallback; + + private SharedPreferences mSharedPreferences; + private String mPrefKey; + @Nullable + private Boolean mInitialPrefValue = null; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mSharedPreferences = mContext.getSharedPreferences( + LetterboxEduWindowManager.HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME, + Context.MODE_PRIVATE); + mPrefKey = String.valueOf(mContext.getUserId()); + if (mSharedPreferences.contains(mPrefKey)) { + mInitialPrefValue = mSharedPreferences.getBoolean(mPrefKey, /* default= */ false); + mSharedPreferences.edit().remove(mPrefKey).apply(); + } + } + + @After + public void tearDown() { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + if (mInitialPrefValue == null) { + editor.remove(mPrefKey); + } else { + editor.putBoolean(mPrefKey, mInitialPrefValue); + } + editor.apply(); + } + + @Test + public void testCreateLayout_notEligible_doesNotCreateLayout() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ false); + + assertFalse(windowManager.createLayout(/* canShow= */ true)); + + assertNull(windowManager.mLayout); + } + + @Test + public void testCreateLayout_alreadyShownToUser_doesNotCreateLayout() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + mSharedPreferences.edit().putBoolean(mPrefKey, true).apply(); + + assertFalse(windowManager.createLayout(/* canShow= */ true)); + + assertNull(windowManager.mLayout); + } + + @Test + public void testCreateLayout_taskBarEducationIsShowing_doesNotCreateLayout() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ + true, /* isTaskbarEduShowing= */ true); + + assertFalse(windowManager.createLayout(/* canShow= */ true)); + + assertNull(windowManager.mLayout); + } + + @Test + public void testCreateLayout_canShowFalse_returnsTrueButDoesNotCreateLayout() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ false)); + + assertFalse(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false)); + assertNull(windowManager.mLayout); + } + + @Test + public void testCreateLayout_canShowTrue_createsLayoutCorrectly() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + + assertTrue(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false)); + LetterboxEduDialogLayout layout = windowManager.mLayout; + assertNotNull(layout); + verify(mViewHost).setView(eq(layout), mWindowAttrsCaptor.capture()); + verifyLayout(layout, mWindowAttrsCaptor.getValue(), /* expectedWidth= */ TASK_WIDTH, + /* expectedHeight= */ TASK_HEIGHT, /* expectedExtraTopMargin= */ DISPLAY_CUTOUT_TOP, + /* expectedExtraBottomMargin= */ DISPLAY_CUTOUT_BOTTOM); + + // Clicking the layout does nothing until enter animation is done. + layout.performClick(); + verify(mAnimationController, never()).startExitAnimation(any(), any()); + + verifyAndFinishEnterAnimation(layout); + + // Exit animation should start following a click on the layout. + layout.performClick(); + + // Window manager isn't released until exit animation is done. + verify(windowManager, never()).release(); + + // Verify multiple clicks are ignored. + layout.performClick(); + + verifyAndFinishExitAnimation(layout); + + verify(windowManager).release(); + verify(mOnDismissCallback).run(); + } + + @Test + public void testUpdateCompatInfo_updatesLayoutCorrectly() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + LetterboxEduDialogLayout layout = windowManager.mLayout; + assertNotNull(layout); + + assertTrue(windowManager.updateCompatInfo( + createTaskInfo(/* eligible= */ true, new Rect(50, 25, 150, 75)), + mTaskListener, /* canShow= */ true)); + + verifyLayout(layout, layout.getLayoutParams(), /* expectedWidth= */ 100, + /* expectedHeight= */ 50, /* expectedExtraTopMargin= */ 0, + /* expectedExtraBottomMargin= */ 0); + verify(mViewHost).relayout(mWindowAttrsCaptor.capture()); + assertThat(mWindowAttrsCaptor.getValue()).isEqualTo(layout.getLayoutParams()); + + // Window manager should be released (without animation) when eligible becomes false. + assertFalse(windowManager.updateCompatInfo(createTaskInfo(/* eligible= */ false), + mTaskListener, /* canShow= */ true)); + + verify(windowManager).release(); + verify(mOnDismissCallback, never()).run(); + verify(mAnimationController, never()).startExitAnimation(any(), any()); + assertNull(windowManager.mLayout); + } + + @Test + public void testUpdateCompatInfo_notEligibleUntilUpdate_createsLayoutAfterUpdate() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ false); + + assertFalse(windowManager.createLayout(/* canShow= */ true)); + assertNull(windowManager.mLayout); + + assertTrue(windowManager.updateCompatInfo(createTaskInfo(/* eligible= */ true), + mTaskListener, /* canShow= */ true)); + + assertNotNull(windowManager.mLayout); + } + + @Test + public void testUpdateCompatInfo_canShowFalse_doesNothing() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ false)); + assertNull(windowManager.mLayout); + + assertTrue(windowManager.updateCompatInfo(createTaskInfo(/* eligible= */ true), + mTaskListener, /* canShow= */ false)); + + assertNull(windowManager.mLayout); + verify(mViewHost, never()).relayout(any()); + } + + @Test + public void testUpdateDisplayLayout_updatesLayoutCorrectly() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + LetterboxEduDialogLayout layout = windowManager.mLayout; + assertNotNull(layout); + + int newDisplayCutoutTop = DISPLAY_CUTOUT_TOP + 7; + int newDisplayCutoutBottom = DISPLAY_CUTOUT_BOTTOM + 9; + windowManager.updateDisplayLayout(createDisplayLayout( + Insets.of(DISPLAY_CUTOUT_HORIZONTAL, newDisplayCutoutTop, + DISPLAY_CUTOUT_HORIZONTAL, newDisplayCutoutBottom))); + + verifyLayout(layout, layout.getLayoutParams(), /* expectedWidth= */ TASK_WIDTH, + /* expectedHeight= */ TASK_HEIGHT, /* expectedExtraTopMargin= */ + newDisplayCutoutTop, /* expectedExtraBottomMargin= */ newDisplayCutoutBottom); + verify(mViewHost).relayout(mWindowAttrsCaptor.capture()); + assertThat(mWindowAttrsCaptor.getValue()).isEqualTo(layout.getLayoutParams()); + } + + @Test + public void testRelease_animationIsCancelled() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + windowManager.release(); + + verify(mAnimationController).cancelAnimation(); + } + + private void verifyLayout(LetterboxEduDialogLayout layout, ViewGroup.LayoutParams params, + int expectedWidth, int expectedHeight, int expectedExtraTopMargin, + int expectedExtraBottomMargin) { + assertThat(params.width).isEqualTo(expectedWidth); + assertThat(params.height).isEqualTo(expectedHeight); + MarginLayoutParams dialogParams = + (MarginLayoutParams) layout.getDialogContainer().getLayoutParams(); + int verticalMargin = (int) mContext.getResources().getDimension( + R.dimen.letterbox_education_dialog_margin); + assertThat(dialogParams.topMargin).isEqualTo(verticalMargin + expectedExtraTopMargin); + assertThat(dialogParams.bottomMargin).isEqualTo(verticalMargin + expectedExtraBottomMargin); + } + + private void verifyAndFinishEnterAnimation(LetterboxEduDialogLayout layout) { + verify(mAnimationController).startEnterAnimation(eq(layout), mEndCallbackCaptor.capture()); + mEndCallbackCaptor.getValue().run(); + } + + private void verifyAndFinishExitAnimation(LetterboxEduDialogLayout layout) { + verify(mAnimationController).startExitAnimation(eq(layout), mEndCallbackCaptor.capture()); + mEndCallbackCaptor.getValue().run(); + } + + private LetterboxEduWindowManager createWindowManager(boolean eligible) { + return createWindowManager(eligible, /* isTaskbarEduShowing= */ false); + } + + private LetterboxEduWindowManager createWindowManager(boolean eligible, + boolean isTaskbarEduShowing) { + LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext, + createTaskInfo(eligible), mSyncTransactionQueue, mTaskListener, + createDisplayLayout(), mOnDismissCallback, mAnimationController); + + spyOn(windowManager); + doReturn(mViewHost).when(windowManager).createSurfaceViewHost(); + doReturn(isTaskbarEduShowing).when(windowManager).isTaskbarEduShowing(); + + return windowManager; + } + + private DisplayLayout createDisplayLayout() { + return createDisplayLayout( + Insets.of(DISPLAY_CUTOUT_HORIZONTAL, DISPLAY_CUTOUT_TOP, DISPLAY_CUTOUT_HORIZONTAL, + DISPLAY_CUTOUT_BOTTOM)); + } + + private DisplayLayout createDisplayLayout(Insets insets) { + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = TASK_WIDTH; + displayInfo.logicalHeight = TASK_HEIGHT; + displayInfo.displayCutout = new DisplayCutout( + insets, null, null, null, null); + return new DisplayLayout(displayInfo, + mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false); + } + + private static TaskInfo createTaskInfo(boolean eligible) { + return createTaskInfo(eligible, new Rect(0, 0, TASK_WIDTH, TASK_HEIGHT)); + } + + private static TaskInfo createTaskInfo(boolean eligible, Rect bounds) { + ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); + taskInfo.taskId = TASK_ID; + taskInfo.topActivityEligibleForLetterboxEducation = eligible; + taskInfo.configuration.windowConfiguration.setBounds(bounds); + return taskInfo; + } +} |