diff options
| author | 2022-12-01 22:01:45 +0000 | |
|---|---|---|
| committer | 2022-12-01 22:01:45 +0000 | |
| commit | 08752d91410efba7d7446f30d5d31afad0ac0393 (patch) | |
| tree | d0f9294881601c2a278783b5d69c48eac664399e | |
| parent | 436f1faa8180fa89d715aff06874450cb579fc66 (diff) | |
| parent | 9fcbcb07622501ecbea466273811eaef19e7a0b4 (diff) | |
Merge "Rename WindowDecorModelView to reflect purposes" into tm-qpr-dev am: 9fcbcb0762
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20534843
Change-Id: Iae39084cfb0cbd5102d116e5df6f28bb96511871
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
8 files changed, 408 insertions, 86 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 90b35a5a55e1..44bcdb2d5de5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -82,7 +82,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { mTasks.put(taskInfo.taskId, state); if (!Transitions.ENABLE_SHELL_TRANSITIONS) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t); + mWindowDecorationViewModel.onTaskOpening(taskInfo, leash, t, t); t.apply(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java index 168f6d79a390..6e710f7caeda 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java @@ -120,7 +120,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mWindowDecorViewModel.createWindowDecoration( + mWindowDecorViewModel.onTaskOpening( change.getTaskInfo(), change.getLeash(), startT, finishT); } @@ -128,31 +128,23 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mWindowDecorViewModel.setupWindowDecorationForTransition( - change.getTaskInfo(), startT, finishT); + mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT); } private void onChangeTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mWindowDecorViewModel.setupWindowDecorationForTransition( - change.getTaskInfo(), startT, finishT); + mWindowDecorViewModel.onTaskChanging( + change.getTaskInfo(), change.getLeash(), startT, finishT); } private void onToFrontTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - boolean exists = mWindowDecorViewModel.setupWindowDecorationForTransition( - change.getTaskInfo(), - startT, - finishT); - if (!exists) { - // Window caption does not exist, create it - mWindowDecorViewModel.createWindowDecoration( - change.getTaskInfo(), change.getLeash(), startT, finishT); - } + mWindowDecorViewModel.onTaskChanging( + change.getTaskInfo(), change.getLeash(), startT, finishT); } @Override @@ -188,4 +180,4 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i)); } } -} +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java index 75a4091c7d78..6623f5ca84ee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java @@ -103,7 +103,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { if (mWindowDecorViewModelOptional.isPresent()) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); createdWindowDecor = mWindowDecorViewModelOptional.get() - .createWindowDecoration(taskInfo, leash, t, t); + .onTaskOpening(taskInfo, leash, t, t); t.apply(); } if (!createdWindowDecor) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 8369569b4163..e40db4e4dcf2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -55,6 +55,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; import com.android.wm.shell.transition.Transitions; +import java.util.function.Supplier; + /** * View model for the window decoration with a caption and shadows. Works with * {@link CaptionWindowDecoration}. @@ -62,6 +64,8 @@ import com.android.wm.shell.transition.Transitions; public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private static final String TAG = "CaptionViewModel"; + private final CaptionWindowDecoration.Factory mCaptionWindowDecorFactory; + private final Supplier<InputManager> mInputManagerSupplier; private final ActivityTaskManager mActivityTaskManager; private final ShellTaskOrganizer mTaskOrganizer; private final Context mContext; @@ -77,6 +81,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>(); private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl(); + private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory(); public CaptionWindowDecorViewModel( Context context, @@ -86,6 +91,29 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { DisplayController displayController, SyncTransactionQueue syncQueue, DesktopModeController desktopModeController) { + this( + context, + mainHandler, + mainChoreographer, + taskOrganizer, + displayController, + syncQueue, + desktopModeController, + new CaptionWindowDecoration.Factory(), + InputManager::getInstance); + } + + public CaptionWindowDecorViewModel( + Context context, + Handler mainHandler, + Choreographer mainChoreographer, + ShellTaskOrganizer taskOrganizer, + DisplayController displayController, + SyncTransactionQueue syncQueue, + DesktopModeController desktopModeController, + CaptionWindowDecoration.Factory captionWindowDecorFactory, + Supplier<InputManager> inputManagerSupplier) { + mContext = context; mMainHandler = mainHandler; mMainChoreographer = mainChoreographer; @@ -94,7 +122,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mDisplayController = displayController; mSyncQueue = syncQueue; mDesktopModeController = desktopModeController; - mTransitionDragActive = false; + + mCaptionWindowDecorFactory = captionWindowDecorFactory; + mInputManagerSupplier = inputManagerSupplier; + } + + void setEventReceiverFactory(EventReceiverFactory eventReceiverFactory) { + mEventReceiverFactory = eventReceiverFactory; } @Override @@ -103,42 +137,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } @Override - public boolean createWindowDecoration( + public boolean onTaskOpening( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { if (!shouldShowWindowDecor(taskInfo)) return false; - CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId); - if (oldDecoration != null) { - // close the old decoration if it exists to avoid two window decorations being added - oldDecoration.close(); - } - final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration( - mContext, - mDisplayController, - mTaskOrganizer, - taskInfo, - taskSurface, - mMainHandler, - mMainChoreographer, - mSyncQueue); - mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); - - TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration, - mDragStartListener); - CaptionTouchEventListener touchEventListener = - new CaptionTouchEventListener(taskInfo, taskPositioner, - windowDecoration.getDragDetector()); - windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); - windowDecoration.setDragResizeCallback(taskPositioner); - setupWindowDecorationForTransition(taskInfo, startT, finishT); - if (mInputMonitor == null) { - mInputMonitor = InputManager.getInstance().monitorGestureInput( - "caption-touch", mContext.getDisplayId()); - mEventReceiver = new EventReceiver( - mInputMonitor.getInputChannel(), Looper.myLooper()); - } + createWindowDecoration(taskInfo, taskSurface, startT, finishT); return true; } @@ -151,25 +156,45 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } @Override - public boolean setupWindowDecorationForTransition( + public void onTaskChanging( + RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); + + if (!shouldShowWindowDecor(taskInfo)) { + if (decoration != null) { + destroyWindowDecoration(taskInfo); + } + return; + } + + if (decoration == null) { + createWindowDecoration(taskInfo, taskSurface, startT, finishT); + } else { + decoration.relayout(taskInfo, startT, finishT); + } + } + + @Override + public void onTaskClosing( RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); - if (decoration == null) return false; + if (decoration == null) return; decoration.relayout(taskInfo, startT, finishT); - return true; } @Override - public boolean destroyWindowDecoration(RunningTaskInfo taskInfo) { + public void destroyWindowDecoration(RunningTaskInfo taskInfo) { final CaptionWindowDecoration decoration = mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId); - if (decoration == null) return false; + if (decoration == null) return; decoration.close(); - return true; } private class CaptionTouchEventListener implements @@ -217,6 +242,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { decoration.setButtonVisibility(); } } + private void injectBackKey() { sendBackEvent(KeyEvent.ACTION_DOWN); sendBackEvent(KeyEvent.ACTION_UP); @@ -266,7 +292,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { */ private void handleEventForMove(MotionEvent e) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); - int windowingMode = mDesktopModeController + int windowingMode = mDesktopModeController .getDisplayAreaWindowingMode(taskInfo.displayId); if (windowingMode == WINDOWING_MODE_FULLSCREEN) { return; @@ -302,7 +328,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } // InputEventReceiver to listen for touch input outside of caption bounds - private class EventReceiver extends InputEventReceiver { + class EventReceiver extends InputEventReceiver { EventReceiver(InputChannel channel, Looper looper) { super(channel, looper); } @@ -318,8 +344,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } } + class EventReceiverFactory { + EventReceiver create(InputChannel channel, Looper looper) { + return new EventReceiver(channel, looper); + } + } + /** * Handle MotionEvents relevant to focused task's caption that don't directly touch it + * * @param ev the {@link MotionEvent} received by {@link EventReceiver} */ private void handleReceivedMotionEvent(MotionEvent ev) { @@ -401,7 +434,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { return focusedDecor; } - private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) { if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true; return DesktopModeStatus.IS_SUPPORTED @@ -410,7 +442,47 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { .getResources().getConfiguration().smallestScreenWidthDp >= 600; } - private class DragStartListenerImpl implements TaskPositioner.DragStartListener{ + private void createWindowDecoration( + ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId); + if (oldDecoration != null) { + // close the old decoration if it exists to avoid two window decorations being added + oldDecoration.close(); + } + final CaptionWindowDecoration windowDecoration = + mCaptionWindowDecorFactory.create( + mContext, + mDisplayController, + mTaskOrganizer, + taskInfo, + taskSurface, + mMainHandler, + mMainChoreographer, + mSyncQueue); + mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); + + TaskPositioner taskPositioner = + new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener); + CaptionTouchEventListener touchEventListener = + new CaptionTouchEventListener( + taskInfo, taskPositioner, windowDecoration.getDragDetector()); + windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); + windowDecoration.setDragResizeCallback(taskPositioner); + windowDecoration.relayout(taskInfo, startT, finishT); + if (mInputMonitor == null) { + InputManager inputManager = mInputManagerSupplier.get(); + mInputMonitor = + inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId()); + mEventReceiver = + mEventReceiverFactory.create( + mInputMonitor.getInputChannel(), Looper.myLooper()); + } + } + + private class DragStartListenerImpl implements TaskPositioner.DragStartListener { @Override public void onDragStart(int taskId) { mWindowDecorByTaskId.get(taskId).closeHandleMenu(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 59576cd3ec15..037ca2031254 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -42,7 +42,8 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; /** * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with - * {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close button. + * {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close + * button. * * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ @@ -181,12 +182,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) { closeDragResizeListener(); mDragResizeListener = new DragResizeInputListener( - mContext, - mHandler, - mChoreographer, - mDisplay.getDisplayId(), - mDecorationContainerSurface, - mDragResizeCallback); + mContext, + mHandler, + mChoreographer, + mDisplay.getDisplayId(), + mDecorationContainerSurface, + mDragResizeCallback); } int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop(); @@ -242,7 +243,6 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL /** * Sets the visibility of buttons and color of caption based on desktop mode status - * */ void setButtonVisibility() { mDesktopActive = DesktopModeStatus.isActive(mContext); @@ -313,6 +313,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL /** * Close an open handle menu if input is outside of menu coordinates + * * @param ev the tapped point to compare against */ void closeHandleMenuIfNeeded(MotionEvent ev) { @@ -329,6 +330,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL /** * Offset the coordinates of a {@link MotionEvent} to be in the same coordinate space as caption + * * @param ev the {@link MotionEvent} to offset * @return the point of the input in local space */ @@ -343,7 +345,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL /** * Determine if a passed MotionEvent is in a view in caption - * @param ev the {@link MotionEvent} to check + * + * @param ev the {@link MotionEvent} to check * @param layoutId the id of the view * @return {@code true} if event is inside the specified view, {@code false} if not */ @@ -363,6 +366,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL * Check a passed MotionEvent if a click has occurred on any button on this caption * Note this should only be called when a regular onClick is not possible * (i.e. the button was clicked through status bar layer) + * * @param ev the MotionEvent to compare */ void checkClickEvent(MotionEvent ev) { @@ -399,4 +403,27 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL closeHandleMenu(); super.close(); } + + static class Factory { + + CaptionWindowDecoration create( + Context context, + DisplayController displayController, + ShellTaskOrganizer taskOrganizer, + ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + Handler handler, + Choreographer choreographer, + SyncTransactionQueue syncQueue) { + return new CaptionWindowDecoration( + context, + displayController, + taskOrganizer, + taskInfo, + taskSurface, + handler, + choreographer, + syncQueue); + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java index 2ce4d04377a1..907977c661f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java @@ -28,7 +28,6 @@ import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; * servers. */ public interface WindowDecorViewModel { - /** * Sets the transition starter that starts freeform task transitions. * @@ -37,16 +36,16 @@ public interface WindowDecorViewModel { void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter); /** - * Creates a window decoration for the given task. - * Can be {@code null} for Fullscreen tasks but not Freeform ones. + * Creates a window decoration for the given task. Can be {@code null} for Fullscreen tasks but + * not Freeform ones. * - * @param taskInfo the initial task info of the task + * @param taskInfo the initial task info of the task * @param taskSurface the surface of the task - * @param startT the start transaction to be applied before the transition - * @param finishT the finish transaction to restore states after the transition + * @param startT the start transaction to be applied before the transition + * @param finishT the finish transaction to restore states after the transition * @return {@code true} if window decoration was created, {@code false} otherwise */ - boolean createWindowDecoration( + boolean onTaskOpening( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, SurfaceControl.Transaction startT, @@ -54,7 +53,7 @@ public interface WindowDecorViewModel { /** * Notifies a task info update on the given task, with the window decoration created previously - * for this task by {@link #createWindowDecoration}. + * for this task by {@link #onTaskOpening}. * * @param taskInfo the new task info of the task */ @@ -62,13 +61,29 @@ public interface WindowDecorViewModel { /** * Notifies a transition is about to start about the given task to give the window decoration a - * chance to prepare for this transition. + * chance to prepare for this transition. Unlike {@link #onTaskInfoChanged}, this method creates + * a window decoration if one does not exist but is required. + * + * @param taskInfo the initial task info of the task + * @param taskSurface the surface of the task + * @param startT the start transaction to be applied before the transition + * @param finishT the finish transaction to restore states after the transition + */ + void onTaskChanging( + ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl taskSurface, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT); + + /** + * Notifies that the given task is about to close to give the window decoration a chance to + * prepare for this transition. * - * @param startT the start transaction to be applied before the transition - * @param finishT the finish transaction to restore states after the transition - * @return {@code true} if window decoration exists, {@code false} otherwise + * @param taskInfo the initial task info of the task + * @param startT the start transaction to be applied before the transition + * @param finishT the finish transaction to restore states after the transition */ - boolean setupWindowDecorationForTransition( + void onTaskClosing( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT); @@ -77,7 +92,6 @@ public interface WindowDecorViewModel { * Destroys the window decoration of the give task. * * @param taskInfo the info of the task - * @return {@code true} if window decoration was destroyed, {@code false} otherwise */ - boolean destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo); -} + void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo); +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java index 7068a84c3056..48415d47304c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java @@ -103,7 +103,7 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mWindowDecorViewModel).createWindowDecoration( + verify(mWindowDecorViewModel).onTaskOpening( change.getTaskInfo(), change.getLeash(), startT, finishT); } @@ -120,7 +120,7 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mWindowDecorViewModel).setupWindowDecorationForTransition( + verify(mWindowDecorViewModel).onTaskClosing( change.getTaskInfo(), startT, finishT); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java new file mode 100644 index 000000000000..8b134ed1dfe4 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java @@ -0,0 +1,217 @@ +/* + * 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.windowdecor; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.hardware.input.InputManager; +import android.os.Handler; +import android.os.Looper; +import android.view.Choreographer; +import android.view.Display; +import android.view.InputChannel; +import android.view.InputMonitor; +import android.view.SurfaceControl; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.GrantPermissionRule; + +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestRunningTaskInfoBuilder; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.desktopmode.DesktopModeController; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +/** Tests of {@link CaptionWindowDecorViewModel} */ +@SmallTest +public class CaptionWindowDecorViewModelTests extends ShellTestCase { + @Mock private CaptionWindowDecoration mCaptionWindowDecoration; + + @Mock private CaptionWindowDecoration.Factory mCaptionWindowDecorFactory; + + @Mock private Handler mMainHandler; + + @Mock private Choreographer mMainChoreographer; + + @Mock private ShellTaskOrganizer mTaskOrganizer; + + @Mock private DisplayController mDisplayController; + + @Mock private SyncTransactionQueue mSyncQueue; + + @Mock private DesktopModeController mDesktopModeController; + + @Mock private InputMonitor mInputMonitor; + + @Mock private InputChannel mInputChannel; + + @Mock private CaptionWindowDecorViewModel.EventReceiverFactory mEventReceiverFactory; + + @Mock private CaptionWindowDecorViewModel.EventReceiver mEventReceiver; + + @Mock private InputManager mInputManager; + + private final List<InputManager> mMockInputManagers = new ArrayList<>(); + + private CaptionWindowDecorViewModel mCaptionWindowDecorViewModel; + + @Before + public void setUp() { + mMockInputManagers.add(mInputManager); + + mCaptionWindowDecorViewModel = + new CaptionWindowDecorViewModel( + mContext, + mMainHandler, + mMainChoreographer, + mTaskOrganizer, + mDisplayController, + mSyncQueue, + mDesktopModeController, + mCaptionWindowDecorFactory, + new MockObjectSupplier<>(mMockInputManagers, () -> mock(InputManager.class))); + mCaptionWindowDecorViewModel.setEventReceiverFactory(mEventReceiverFactory); + + doReturn(mCaptionWindowDecoration) + .when(mCaptionWindowDecorFactory) + .create(any(), any(), any(), any(), any(), any(), any(), any()); + + when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor); + when(mEventReceiverFactory.create(any(), any())).thenReturn(mEventReceiver); + when(mInputMonitor.getInputChannel()).thenReturn(mInputChannel); + } + + @Test + public void testDeleteCaptionOnChangeTransitionWhenNecessary() throws Exception { + Looper.prepare(); + final int taskId = 1; + final ActivityManager.RunningTaskInfo taskInfo = + createTaskInfo(taskId, WINDOWING_MODE_FREEFORM); + SurfaceControl surfaceControl = mock(SurfaceControl.class); + final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); + GrantPermissionRule.grant(android.Manifest.permission.MONITOR_INPUT); + + mCaptionWindowDecorViewModel.onTaskOpening(taskInfo, surfaceControl, startT, finishT); + verify(mCaptionWindowDecorFactory) + .create( + mContext, + mDisplayController, + mTaskOrganizer, + taskInfo, + surfaceControl, + mMainHandler, + mMainChoreographer, + mSyncQueue); + + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); + taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); + mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT); + verify(mCaptionWindowDecoration).close(); + } + + @Test + public void testCreateCaptionOnChangeTransitionWhenNecessary() throws Exception { + final int taskId = 1; + final ActivityManager.RunningTaskInfo taskInfo = + createTaskInfo(taskId, WINDOWING_MODE_UNDEFINED); + SurfaceControl surfaceControl = mock(SurfaceControl.class); + final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); + taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); + + mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT); + + verify(mCaptionWindowDecorFactory, never()) + .create( + mContext, + mDisplayController, + mTaskOrganizer, + taskInfo, + surfaceControl, + mMainHandler, + mMainChoreographer, + mSyncQueue); + + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); + taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD); + + mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT); + + verify(mCaptionWindowDecorFactory) + .create( + mContext, + mDisplayController, + mTaskOrganizer, + taskInfo, + surfaceControl, + mMainHandler, + mMainChoreographer, + mSyncQueue); + } + + private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) { + ActivityManager.RunningTaskInfo taskInfo = + new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setVisible(true) + .build(); + taskInfo.taskId = taskId; + taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode); + return taskInfo; + } + + private static class MockObjectSupplier<T> implements Supplier<T> { + private final List<T> mObjects; + private final Supplier<T> mDefaultSupplier; + private int mNumOfCalls = 0; + + private MockObjectSupplier(List<T> objects, Supplier<T> defaultSupplier) { + mObjects = objects; + mDefaultSupplier = defaultSupplier; + } + + @Override + public T get() { + final T mock = + mNumOfCalls < mObjects.size() ? mObjects.get(mNumOfCalls) + : mDefaultSupplier.get(); + ++mNumOfCalls; + return mock; + } + } +} |