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 android.graphics.Rect; 22 23 import androidx.annotation.NonNull; 24 import androidx.test.uiautomator.By; 25 import androidx.test.uiautomator.BySelector; 26 import androidx.test.uiautomator.UiObject2; 27 28 import com.android.launcher3.testing.shared.TestProtocol; 29 30 import java.util.List; 31 import java.util.regex.Pattern; 32 import java.util.stream.Collectors; 33 34 /** 35 * A recent task in the overview panel carousel. 36 */ 37 public final class OverviewTask { 38 private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; 39 40 static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync"); 41 static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect"); 42 static final Pattern SPLIT_START_EVENT = Pattern.compile("launchSplitTasks"); 43 private final LauncherInstrumentation mLauncher; 44 private final UiObject2 mTask; 45 private final BaseOverview mOverview; 46 OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview)47 OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview) { 48 mLauncher = launcher; 49 mTask = task; 50 mOverview = overview; 51 verifyActiveContainer(); 52 } 53 verifyActiveContainer()54 private void verifyActiveContainer() { 55 mOverview.verifyActiveContainer(); 56 } 57 getVisibleHeight()58 int getVisibleHeight() { 59 return mTask.getVisibleBounds().height(); 60 } 61 getVisibleWidth()62 int getVisibleWidth() { 63 return mTask.getVisibleBounds().width(); 64 } 65 getTaskCenterX()66 int getTaskCenterX() { 67 return mTask.getVisibleCenter().x; 68 } 69 getExactCenterX()70 float getExactCenterX() { 71 return mTask.getVisibleBounds().exactCenterX(); 72 } 73 getUiObject()74 UiObject2 getUiObject() { 75 return mTask; 76 } 77 78 /** 79 * Dismisses the task by swiping up. 80 */ dismiss()81 public void dismiss() { 82 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 83 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 84 "want to dismiss an overview task")) { 85 verifyActiveContainer(); 86 int taskCountBeforeDismiss = mOverview.getTaskCount(); 87 mLauncher.assertNotEquals("Unable to find a task", 0, taskCountBeforeDismiss); 88 if (taskCountBeforeDismiss == 1) { 89 dismissBySwipingUp(); 90 return; 91 } 92 93 boolean taskWasFocused = mLauncher.isTablet() && getVisibleHeight() == mLauncher 94 .getFocusedTaskHeightForTablet(); 95 List<Integer> originalTasksCenterX = getCurrentTasksCenterXList(); 96 boolean isClearAllVisibleBeforeDismiss = mOverview.isClearAllVisible(); 97 98 dismissBySwipingUp(); 99 100 try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("dismissed")) { 101 if (taskWasFocused) { 102 mLauncher.assertNotNull("No task became focused", 103 mOverview.getFocusedTaskForTablet()); 104 } 105 if (!isClearAllVisibleBeforeDismiss) { 106 List<Integer> currentTasksCenterX = getCurrentTasksCenterXList(); 107 if (originalTasksCenterX.size() == currentTasksCenterX.size()) { 108 // Check for the same number of visible tasks before and after to 109 // avoid asserting on cases of shifting all tasks to close the distance 110 // between clear all and tasks at the end of the grid. 111 mLauncher.assertTrue("Task centers not aligned", 112 originalTasksCenterX.equals(currentTasksCenterX)); 113 } 114 } 115 } 116 } 117 } 118 dismissBySwipingUp()119 private void dismissBySwipingUp() { 120 verifyActiveContainer(); 121 // Dismiss the task via flinging it up. 122 final Rect taskBounds = mLauncher.getVisibleBounds(mTask); 123 final int centerX = taskBounds.centerX(); 124 final int centerY = taskBounds.centerY(); 125 mLauncher.executeAndWaitForLauncherEvent( 126 () -> mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false, 127 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER), 128 event -> TestProtocol.DISMISS_ANIMATION_ENDS_MESSAGE.equals(event.getClassName()), 129 () -> "Didn't receive a dismiss animation ends message: " + centerX + ", " 130 + centerY, "swiping to dismiss"); 131 } 132 getCurrentTasksCenterXList()133 private List<Integer> getCurrentTasksCenterXList() { 134 return mLauncher.isTablet() 135 ? mOverview.getCurrentTasksForTablet().stream() 136 .map(OverviewTask::getTaskCenterX) 137 .collect(Collectors.toList()) 138 : List.of(mOverview.getCurrentTask().getTaskCenterX()); 139 } 140 141 /** 142 * Clicks the task. 143 */ open()144 public LaunchedAppState open() { 145 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { 146 verifyActiveContainer(); 147 mLauncher.executeAndWaitForEvent( 148 () -> mLauncher.clickLauncherObject(mTask), 149 event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, 150 () -> "Launching task didn't open a new window: " 151 + mTask.getParent().getContentDescription(), 152 "clicking an overview task"); 153 if (mOverview.getContainerType() 154 == LauncherInstrumentation.ContainerType.SPLIT_SCREEN_SELECT) { 155 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SPLIT_START_EVENT); 156 157 try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 158 "launched splitscreen")) { 159 160 BySelector divider = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle"); 161 mLauncher.waitForSystemUiObject(divider); 162 return new LaunchedAppState(mLauncher); 163 } 164 } else { 165 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT); 166 return new LaunchedAppState(mLauncher); 167 } 168 } 169 } 170 171 /** Taps the task menu. */ 172 @NonNull tapMenu()173 public OverviewTaskMenu tapMenu() { 174 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 175 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 176 "want to tap the task menu")) { 177 mLauncher.clickLauncherObject( 178 mLauncher.waitForObjectInContainer(mTask.getParent(), "icon")); 179 180 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 181 "tapped the task menu")) { 182 return new OverviewTaskMenu(mLauncher); 183 } 184 } 185 } 186 isTaskSplit()187 boolean isTaskSplit() { 188 return mLauncher.findObjectInContainer(mTask.getParent(), "bottomright_snapshot") != null; 189 } 190 } 191