summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author tomnatan <tomnatan@google.com> 2022-02-09 12:32:28 +0000
committer tomnatan <tomnatan@google.com> 2022-02-17 16:53:38 +0000
commitc295edad0bb699d89a4904aecc1d5152dfe7c0f2 (patch)
treeb98b64f2ab3a6bf1a2b0cb92a01ee75c24062d39
parent68eb4fb58640a0a0fb65a2269da475afb1d6c257 (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
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogActionLayout.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java41
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java154
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java108
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java351
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;
+ }
+}