1 /* 2 * Copyright (C) 2018 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.launcher3.tapl; 18 19 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; 20 21 import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT; 22 import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL; 23 24 import android.graphics.Point; 25 import android.os.SystemClock; 26 import android.view.MotionEvent; 27 28 import androidx.annotation.NonNull; 29 import androidx.test.uiautomator.UiObject2; 30 31 import com.android.launcher3.testing.TestProtocol; 32 33 import java.util.regex.Pattern; 34 35 /** 36 * Indicates the base state with a UI other than Overview running as foreground. It can also 37 * indicate Launcher as long as Launcher is not in Overview state. 38 */ 39 public class Background extends LauncherInstrumentation.VisibleContainer { 40 private static final int ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION = 500; 41 private static final Pattern SQUARE_BUTTON_EVENT = Pattern.compile("onOverviewToggle"); 42 Background(LauncherInstrumentation launcher)43 Background(LauncherInstrumentation launcher) { 44 super(launcher); 45 } 46 47 @Override getContainerType()48 protected LauncherInstrumentation.ContainerType getContainerType() { 49 return LauncherInstrumentation.ContainerType.BACKGROUND; 50 } 51 52 /** 53 * Swipes up or presses the square button to switch to Overview. 54 * Returns the base overview, which can be either in Launcher or the fallback recents. 55 * 56 * @return the Overview panel object. 57 */ 58 @NonNull switchToOverview()59 public BaseOverview switchToOverview() { 60 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 61 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 62 "want to switch from background to overview")) { 63 verifyActiveContainer(); 64 goToOverviewUnchecked(); 65 return mLauncher.isFallbackOverview() ? 66 new BaseOverview(mLauncher) : new Overview(mLauncher); 67 } 68 } 69 zeroButtonToOverviewGestureStartsInLauncher()70 protected boolean zeroButtonToOverviewGestureStartsInLauncher() { 71 return false; 72 } 73 goToOverviewUnchecked()74 protected void goToOverviewUnchecked() { 75 switch (mLauncher.getNavigationModel()) { 76 case ZERO_BUTTON: { 77 final int centerX = mLauncher.getDevice().getDisplayWidth() / 2; 78 final int startY = getSwipeStartY(); 79 final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()). 80 getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); 81 final Point start = new Point(centerX, startY); 82 final Point end = 83 new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop()); 84 85 final long downTime = SystemClock.uptimeMillis(); 86 final LauncherInstrumentation.GestureScope gestureScope = 87 zeroButtonToOverviewGestureStartsInLauncher() 88 ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE 89 : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER; 90 91 mLauncher.sendPointer( 92 downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope); 93 mLauncher.executeAndWaitForLauncherEvent( 94 () -> mLauncher.movePointer( 95 downTime, 96 downTime, 97 ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION, 98 start, 99 end, 100 gestureScope), 101 event -> TestProtocol.PAUSE_DETECTED_MESSAGE.equals(event.getClassName()), 102 () -> "Pause wasn't detected", "swiping and holding"); 103 mLauncher.runToState( 104 () -> mLauncher.sendPointer( 105 downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, end, 106 gestureScope), 107 OVERVIEW_STATE_ORDINAL, "sending UP event"); 108 break; 109 } 110 111 case TWO_BUTTON: { 112 final int startX; 113 final int startY; 114 final int endX; 115 final int endY; 116 final int swipeLength = mLauncher.getTestInfo(getSwipeHeightRequestName()). 117 getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) + mLauncher.getTouchSlop(); 118 119 if (mLauncher.getDevice().isNaturalOrientation()) { 120 startX = endX = mLauncher.getDevice().getDisplayWidth() / 2; 121 startY = getSwipeStartY(); 122 endY = startY - swipeLength; 123 } else { 124 startX = getSwipeStartX(); 125 // TODO(b/184059820) make horizontal swipe use swipe width not height, for the 126 // moment just double the swipe length. 127 endX = startX - swipeLength * 2; 128 startY = endY = mLauncher.getDevice().getDisplayHeight() / 2; 129 } 130 131 mLauncher.swipeToState(startX, startY, endX, endY, 10, OVERVIEW_STATE_ORDINAL, 132 LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER); 133 break; 134 } 135 136 case THREE_BUTTON: 137 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT); 138 mLauncher.runToState( 139 () -> mLauncher.waitForSystemUiObject("recent_apps").click(), 140 OVERVIEW_STATE_ORDINAL, "clicking Recents button"); 141 break; 142 } 143 expectSwitchToOverviewEvents(); 144 } 145 expectSwitchToOverviewEvents()146 private void expectSwitchToOverviewEvents() { 147 } 148 149 @NonNull quickSwitchToPreviousApp()150 public Background quickSwitchToPreviousApp() { 151 boolean toRight = true; 152 quickSwitch(toRight); 153 return new Background(mLauncher); 154 } 155 156 @NonNull quickSwitchToPreviousAppSwipeLeft()157 public Background quickSwitchToPreviousAppSwipeLeft() { 158 boolean toRight = false; 159 quickSwitch(toRight); 160 return new Background(mLauncher); 161 } 162 163 @NonNull quickSwitch(boolean toRight)164 private void quickSwitch(boolean toRight) { 165 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 166 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 167 "want to quick switch to the previous app")) { 168 verifyActiveContainer(); 169 final boolean launcherWasVisible = mLauncher.isLauncherVisible(); 170 boolean transposeInLandscape = false; 171 switch (mLauncher.getNavigationModel()) { 172 case TWO_BUTTON: 173 transposeInLandscape = true; 174 // Fall through, zero button and two button modes behave the same. 175 case ZERO_BUTTON: { 176 final int startX; 177 final int startY; 178 final int endX; 179 final int endY; 180 final int cornerRadius = (int) Math.ceil(mLauncher.getWindowCornerRadius()); 181 if (toRight) { 182 if (mLauncher.getDevice().isNaturalOrientation() || !transposeInLandscape) { 183 // Swipe from the bottom left to the bottom right of the screen. 184 startX = cornerRadius; 185 startY = getSwipeStartY(); 186 endX = mLauncher.getDevice().getDisplayWidth() - cornerRadius; 187 endY = startY; 188 } else { 189 // Swipe from the bottom right to the top right of the screen. 190 startX = getSwipeStartX(); 191 startY = mLauncher.getRealDisplaySize().y - 1 - cornerRadius; 192 endX = startX; 193 endY = cornerRadius; 194 } 195 } else { 196 if (mLauncher.getDevice().isNaturalOrientation() || !transposeInLandscape) { 197 // Swipe from the bottom right to the bottom left of the screen. 198 startX = mLauncher.getDevice().getDisplayWidth() - cornerRadius; 199 startY = getSwipeStartY(); 200 endX = cornerRadius; 201 endY = startY; 202 } else { 203 // Swipe from the bottom left to the top left of the screen. 204 startX = getSwipeStartX(); 205 startY = cornerRadius; 206 endX = startX; 207 endY = mLauncher.getRealDisplaySize().y - 1 - cornerRadius; 208 } 209 } 210 211 final boolean isZeroButton = mLauncher.getNavigationModel() 212 == LauncherInstrumentation.NavigationModel.ZERO_BUTTON; 213 LauncherInstrumentation.GestureScope gestureScope = 214 launcherWasVisible && isZeroButton 215 ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE 216 : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER; 217 mLauncher.executeAndWaitForEvent( 218 () -> mLauncher.linearGesture( 219 startX, startY, endX, endY, 20, false, gestureScope), 220 event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, 221 () -> "Quick switch gesture didn't change window state", "swiping"); 222 break; 223 } 224 225 case THREE_BUTTON: 226 // Double press the recents button. 227 UiObject2 recentsButton = mLauncher.waitForSystemUiObject("recent_apps"); 228 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT); 229 mLauncher.runToState(() -> recentsButton.click(), OVERVIEW_STATE_ORDINAL, 230 "clicking Recents button for the first time"); 231 mLauncher.getOverview(); 232 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT); 233 mLauncher.executeAndWaitForEvent( 234 () -> recentsButton.click(), 235 event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, 236 () -> "Pressing recents button didn't change window state", 237 "clicking Recents button for the second time"); 238 break; 239 } 240 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT); 241 return; 242 } 243 } 244 getSwipeHeightRequestName()245 protected String getSwipeHeightRequestName() { 246 return TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT; 247 } 248 getSwipeStartX()249 protected int getSwipeStartX() { 250 return mLauncher.getRealDisplaySize().x - 1; 251 } 252 getSwipeStartY()253 protected int getSwipeStartY() { 254 return mLauncher.getRealDisplaySize().y - 1; 255 } 256 } 257