1 package com.android.quickstep; 2 3 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 4 5 import android.app.Activity; 6 import android.content.Context; 7 import android.content.res.Resources; 8 import android.graphics.Rect; 9 import android.os.Bundle; 10 11 import androidx.annotation.Nullable; 12 13 import com.android.launcher3.R; 14 import com.android.launcher3.taskbar.TaskbarActivityContext; 15 import com.android.launcher3.testing.TestInformationHandler; 16 import com.android.launcher3.testing.shared.TestProtocol; 17 import com.android.launcher3.touch.PagedOrientationHandler; 18 import com.android.launcher3.util.DisplayController; 19 import com.android.quickstep.util.LayoutUtils; 20 import com.android.quickstep.util.TISBindHelper; 21 22 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.ExecutionException; 24 import java.util.function.Consumer; 25 import java.util.function.Function; 26 27 public class QuickstepTestInformationHandler extends TestInformationHandler { 28 29 protected final Context mContext; 30 QuickstepTestInformationHandler(Context context)31 public QuickstepTestInformationHandler(Context context) { 32 mContext = context; 33 } 34 35 @Override call(String method, String arg, @Nullable Bundle extras)36 public Bundle call(String method, String arg, @Nullable Bundle extras) { 37 final Bundle response = new Bundle(); 38 switch (method) { 39 case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: { 40 final float swipeHeight = 41 LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile); 42 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight); 43 return response; 44 } 45 46 case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: { 47 final float swipeHeight = 48 LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile, 49 PagedOrientationHandler.PORTRAIT); 50 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight); 51 return response; 52 } 53 54 case TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET: { 55 if (!mDeviceProfile.isTablet) { 56 return null; 57 } 58 Rect focusedTaskRect = new Rect(); 59 LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile, 60 focusedTaskRect, PagedOrientationHandler.PORTRAIT); 61 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height()); 62 return response; 63 } 64 65 case TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET: { 66 if (!mDeviceProfile.isTablet) { 67 return null; 68 } 69 Rect gridTaskRect = new Rect(); 70 LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile, 71 gridTaskRect, PagedOrientationHandler.PORTRAIT); 72 response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect); 73 return response; 74 } 75 76 case TestProtocol.REQUEST_GET_OVERVIEW_PAGE_SPACING: { 77 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, 78 mDeviceProfile.overviewPageSpacing); 79 return response; 80 } 81 82 case TestProtocol.REQUEST_HAS_TIS: { 83 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true); 84 return response; 85 } 86 87 case TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING: 88 runOnTISBinder(tisBinder -> { 89 enableManualTaskbarStashing(tisBinder, true); 90 }); 91 return response; 92 93 case TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING: 94 runOnTISBinder(tisBinder -> { 95 enableManualTaskbarStashing(tisBinder, false); 96 }); 97 return response; 98 99 case TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED: 100 runOnTISBinder(tisBinder -> { 101 enableManualTaskbarStashing(tisBinder, true); 102 103 // Allow null-pointer to catch illegal states. 104 tisBinder.getTaskbarManager().getCurrentActivityContext() 105 .unstashTaskbarIfStashed(); 106 107 enableManualTaskbarStashing(tisBinder, false); 108 }); 109 return response; 110 111 case TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT: { 112 final Resources resources = mContext.getResources(); 113 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, 114 resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size)); 115 return response; 116 } 117 118 case TestProtocol.REQUEST_STASHED_TASKBAR_SCALE: { 119 runOnTISBinder(tisBinder -> { 120 response.putFloat(TestProtocol.TEST_INFO_RESPONSE_FIELD, 121 tisBinder.getTaskbarManager() 122 .getCurrentActivityContext() 123 .getStashedTaskbarScale()); 124 }); 125 return response; 126 } 127 128 case TestProtocol.REQUEST_TASKBAR_ALL_APPS_TOP_PADDING: { 129 return getTISBinderUIProperty(Bundle::putInt, tisBinder -> 130 tisBinder.getTaskbarManager() 131 .getCurrentActivityContext() 132 .getTaskbarAllAppsTopPadding()); 133 } 134 135 case TestProtocol.REQUEST_TASKBAR_APPS_LIST_SCROLL_Y: { 136 return getTISBinderUIProperty(Bundle::putInt, tisBinder -> 137 tisBinder.getTaskbarManager() 138 .getCurrentActivityContext() 139 .getTaskbarAllAppsScroll()); 140 } 141 142 case TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT: 143 runOnTISBinder(tisBinder -> { 144 enableBlockingTimeout(tisBinder, true); 145 }); 146 return response; 147 148 case TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT: 149 runOnTISBinder(tisBinder -> { 150 enableBlockingTimeout(tisBinder, false); 151 }); 152 return response; 153 154 case TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR: 155 enableTransientTaskbar(true); 156 return response; 157 158 case TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR: 159 enableTransientTaskbar(false); 160 return response; 161 162 case TestProtocol.REQUEST_SHELL_DRAG_READY: 163 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, 164 SystemUiProxy.INSTANCE.get(mContext).isDragAndDropReady()); 165 return response; 166 } 167 168 return super.call(method, arg, extras); 169 } 170 171 @Override getCurrentActivity()172 protected Activity getCurrentActivity() { 173 RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext); 174 OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads); 175 try { 176 return observer.getActivityInterface().getCreatedActivity(); 177 } finally { 178 observer.onDestroy(); 179 rads.destroy(); 180 } 181 } 182 183 @Override isLauncherInitialized()184 protected boolean isLauncherInitialized() { 185 return super.isLauncherInitialized() && TouchInteractionService.isInitialized(); 186 } 187 enableManualTaskbarStashing( TouchInteractionService.TISBinder tisBinder, boolean enable)188 private void enableManualTaskbarStashing( 189 TouchInteractionService.TISBinder tisBinder, boolean enable) { 190 // Allow null-pointer to catch illegal states. 191 tisBinder.getTaskbarManager().getCurrentActivityContext().enableManualStashingDuringTests( 192 enable); 193 } 194 enableBlockingTimeout( TouchInteractionService.TISBinder tisBinder, boolean enable)195 private void enableBlockingTimeout( 196 TouchInteractionService.TISBinder tisBinder, boolean enable) { 197 TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext(); 198 if (context == null) { 199 return; 200 } 201 context.enableBlockingTimeoutDuringTests(enable); 202 } 203 enableTransientTaskbar(boolean enable)204 private void enableTransientTaskbar(boolean enable) { 205 DisplayController.INSTANCE.get(mContext).enableTransientTaskbarForTests(enable); 206 } 207 208 /** 209 * Runs the given command on the UI thread, after ensuring we are connected to 210 * TouchInteractionService. 211 */ runOnTISBinder(Consumer<TouchInteractionService.TISBinder> connectionCallback)212 protected void runOnTISBinder(Consumer<TouchInteractionService.TISBinder> connectionCallback) { 213 try { 214 CountDownLatch countDownLatch = new CountDownLatch(1); 215 TISBindHelper helper = MAIN_EXECUTOR.submit(() -> 216 new TISBindHelper(mContext, tisBinder -> { 217 connectionCallback.accept(tisBinder); 218 countDownLatch.countDown(); 219 })).get(); 220 countDownLatch.await(); 221 MAIN_EXECUTOR.execute(helper::onDestroy); 222 } catch (ExecutionException | InterruptedException e) { 223 throw new RuntimeException(e); 224 } 225 } 226 getTISBinderUIProperty( BundleSetter<T> bundleSetter, Function<TouchInteractionService.TISBinder, T> provider)227 private <T> Bundle getTISBinderUIProperty( 228 BundleSetter<T> bundleSetter, Function<TouchInteractionService.TISBinder, T> provider) { 229 Bundle response = new Bundle(); 230 231 runOnTISBinder(tisBinder -> bundleSetter.set( 232 response, 233 TestProtocol.TEST_INFO_RESPONSE_FIELD, 234 provider.apply(tisBinder))); 235 236 return response; 237 } 238 } 239