1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.wm.shell.pip.phone; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.times; 22 import static org.mockito.Mockito.verify; 23 24 import android.graphics.Rect; 25 import android.testing.AndroidTestingRunner; 26 import android.testing.TestableLooper; 27 import android.util.Size; 28 29 import androidx.test.filters.SmallTest; 30 31 import com.android.wm.shell.ShellTestCase; 32 import com.android.wm.shell.common.DisplayLayout; 33 import com.android.wm.shell.common.FloatingContentCoordinator; 34 import com.android.wm.shell.common.ShellExecutor; 35 import com.android.wm.shell.common.pip.PhoneSizeSpecSource; 36 import com.android.wm.shell.common.pip.PipBoundsAlgorithm; 37 import com.android.wm.shell.common.pip.PipBoundsState; 38 import com.android.wm.shell.common.pip.PipDisplayLayoutState; 39 import com.android.wm.shell.common.pip.PipKeepClearAlgorithmInterface; 40 import com.android.wm.shell.common.pip.PipSnapAlgorithm; 41 import com.android.wm.shell.common.pip.PipUiEventLogger; 42 import com.android.wm.shell.common.pip.SizeSpecSource; 43 import com.android.wm.shell.pip.PipTaskOrganizer; 44 import com.android.wm.shell.pip.PipTransitionController; 45 import com.android.wm.shell.sysui.ShellInit; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.mockito.Mock; 51 import org.mockito.Mockito; 52 import org.mockito.MockitoAnnotations; 53 54 /** 55 * Unit tests against {@link PipTouchHandler}, including but not limited to: 56 * - Update movement bounds based on new bounds 57 * - Update movement bounds based on IME/shelf 58 * - Update movement bounds to PipResizeHandler 59 */ 60 @RunWith(AndroidTestingRunner.class) 61 @SmallTest 62 @TestableLooper.RunWithLooper(setAsMainLooper = true) 63 public class PipTouchHandlerTest extends ShellTestCase { 64 65 private static final int INSET = 10; 66 private static final int PIP_LENGTH = 100; 67 68 private PipTouchHandler mPipTouchHandler; 69 70 @Mock 71 private PhonePipMenuController mPhonePipMenuController; 72 73 @Mock 74 private PipTaskOrganizer mPipTaskOrganizer; 75 76 @Mock 77 private PipTransitionController mMockPipTransitionController; 78 79 @Mock 80 private FloatingContentCoordinator mFloatingContentCoordinator; 81 82 @Mock 83 private PipUiEventLogger mPipUiEventLogger; 84 85 @Mock 86 private ShellInit mShellInit; 87 88 @Mock 89 private ShellExecutor mMainExecutor; 90 91 private PipBoundsState mPipBoundsState; 92 private PipBoundsAlgorithm mPipBoundsAlgorithm; 93 private PipSnapAlgorithm mPipSnapAlgorithm; 94 private PipMotionHelper mMotionHelper; 95 private PipResizeGestureHandler mPipResizeGestureHandler; 96 private SizeSpecSource mSizeSpecSource; 97 private PipDisplayLayoutState mPipDisplayLayoutState; 98 99 private DisplayLayout mDisplayLayout; 100 private Rect mInsetBounds; 101 private Rect mPipBounds; 102 private Rect mCurBounds; 103 private boolean mFromImeAdjustment; 104 private boolean mFromShelfAdjustment; 105 private int mDisplayRotation; 106 private int mImeHeight; 107 108 @Before setUp()109 public void setUp() throws Exception { 110 MockitoAnnotations.initMocks(this); 111 mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); 112 mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState); 113 mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState); 114 mPipSnapAlgorithm = new PipSnapAlgorithm(); 115 mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm, 116 new PipKeepClearAlgorithmInterface() {}, mPipDisplayLayoutState, mSizeSpecSource); 117 PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState, 118 mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm, 119 mMockPipTransitionController, mFloatingContentCoordinator); 120 mPipTouchHandler = new PipTouchHandler(mContext, mShellInit, mPhonePipMenuController, 121 mPipBoundsAlgorithm, mPipBoundsState, mSizeSpecSource, mPipTaskOrganizer, 122 pipMotionHelper, mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor); 123 // We aren't actually using ShellInit, so just call init directly 124 mPipTouchHandler.onInit(); 125 mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper()); 126 mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler()); 127 mPipTouchHandler.setPipMotionHelper(mMotionHelper); 128 mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler); 129 130 mDisplayLayout = new DisplayLayout(mContext, mContext.getDisplay()); 131 mPipDisplayLayoutState.setDisplayLayout(mDisplayLayout); 132 mInsetBounds = new Rect(mPipBoundsState.getDisplayBounds().left + INSET, 133 mPipBoundsState.getDisplayBounds().top + INSET, 134 mPipBoundsState.getDisplayBounds().right - INSET, 135 mPipBoundsState.getDisplayBounds().bottom - INSET); 136 // minBounds of 100x100 bottom right corner 137 mPipBounds = new Rect(mPipBoundsState.getDisplayBounds().right - INSET - PIP_LENGTH, 138 mPipBoundsState.getDisplayBounds().bottom - INSET - PIP_LENGTH, 139 mPipBoundsState.getDisplayBounds().right - INSET, 140 mPipBoundsState.getDisplayBounds().bottom - INSET); 141 mCurBounds = new Rect(mPipBounds); 142 mFromImeAdjustment = false; 143 mFromShelfAdjustment = false; 144 mDisplayRotation = 0; 145 mImeHeight = 100; 146 } 147 148 @Test instantiate_addInitCallback()149 public void instantiate_addInitCallback() { 150 verify(mShellInit, times(1)).addInitCallback(any(), any()); 151 } 152 153 @Test updateMovementBounds_minMaxBounds()154 public void updateMovementBounds_minMaxBounds() { 155 final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(), 156 mPipBoundsState.getDisplayBounds().height()); 157 Rect expectedMovementBounds = new Rect(); 158 mPipBoundsAlgorithm.getMovementBounds(mPipBounds, mInsetBounds, expectedMovementBounds, 159 0); 160 161 mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mPipBounds, mCurBounds, 162 mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); 163 164 // getting the expected min and max size 165 float aspectRatio = (float) mPipBounds.width() / mPipBounds.height(); 166 Size expectedMinSize = mSizeSpecSource.getMinSize(aspectRatio); 167 Size expectedMaxSize = mSizeSpecSource.getMaxSize(aspectRatio); 168 169 assertEquals(expectedMovementBounds, mPipBoundsState.getNormalMovementBounds()); 170 verify(mPipResizeGestureHandler, times(1)) 171 .updateMinSize(expectedMinSize.getWidth(), expectedMinSize.getHeight()); 172 173 verify(mPipResizeGestureHandler, times(1)) 174 .updateMaxSize(expectedMaxSize.getWidth(), expectedMaxSize.getHeight()); 175 } 176 } 177