Snap for 8774677 from 6c7361fb46 to tm-qpr1-release
Change-Id: I8831c78255b256f56f17fa609c09255de41e5343
This commit is contained in:
@@ -17,6 +17,7 @@ package com.android.quickstep.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
|
||||
@@ -31,6 +32,8 @@ import com.android.launcher3.testing.TestProtocol;
|
||||
*/
|
||||
public class MotionPauseDetector {
|
||||
|
||||
private static final String TAG = "MotionPauseDetector";
|
||||
|
||||
// The percentage of the previous speed that determines whether this is a rapid deceleration.
|
||||
// The bigger this number, the easier it is to trigger the first pause.
|
||||
private static final float RAPID_DECELERATION_FACTOR = 0.6f;
|
||||
@@ -85,7 +88,8 @@ public class MotionPauseDetector {
|
||||
mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
|
||||
mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
|
||||
mForcePauseTimeout = new Alarm();
|
||||
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
|
||||
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */,
|
||||
"Force pause timeout after " + alarm.getLastSetTimeout() + "ms" /* reason */));
|
||||
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
|
||||
mVelocityProvider = new SystemVelocityProvider(axis);
|
||||
}
|
||||
@@ -102,7 +106,7 @@ public class MotionPauseDetector {
|
||||
*/
|
||||
public void setDisallowPause(boolean disallowPause) {
|
||||
mDisallowPause = disallowPause;
|
||||
updatePaused(mIsPaused);
|
||||
updatePaused(mIsPaused, "Set disallowPause=" + disallowPause);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,21 +138,27 @@ public class MotionPauseDetector {
|
||||
float speed = Math.abs(velocity);
|
||||
float previousSpeed = Math.abs(prevVelocity);
|
||||
boolean isPaused;
|
||||
String isPausedReason = "";
|
||||
if (mIsPaused) {
|
||||
// Continue to be paused until moving at a fast speed.
|
||||
isPaused = speed < mSpeedFast || previousSpeed < mSpeedFast;
|
||||
isPausedReason = "Was paused, but started moving at a fast speed";
|
||||
} else {
|
||||
if (velocity < 0 != prevVelocity < 0) {
|
||||
// We're just changing directions, not necessarily stopping.
|
||||
isPaused = false;
|
||||
isPausedReason = "Velocity changed directions";
|
||||
} else {
|
||||
isPaused = speed < mSpeedVerySlow && previousSpeed < mSpeedVerySlow;
|
||||
isPausedReason = "Pause requires back to back slow speeds";
|
||||
if (!isPaused && !mHasEverBeenPaused) {
|
||||
// We want to be more aggressive about detecting the first pause to ensure it
|
||||
// feels as responsive as possible; getting two very slow speeds back to back
|
||||
// takes too long, so also check for a rapid deceleration.
|
||||
boolean isRapidDeceleration = speed < previousSpeed * RAPID_DECELERATION_FACTOR;
|
||||
isPaused = isRapidDeceleration && speed < mSpeedSomewhatFast;
|
||||
isPausedReason = "Didn't have back to back slow speeds, checking for rapid"
|
||||
+ " deceleration on first pause only";
|
||||
}
|
||||
if (mMakePauseHarderToTrigger) {
|
||||
if (speed < mSpeedSlow) {
|
||||
@@ -156,22 +166,27 @@ public class MotionPauseDetector {
|
||||
mSlowStartTime = time;
|
||||
}
|
||||
isPaused = time - mSlowStartTime >= HARDER_TRIGGER_TIMEOUT;
|
||||
isPausedReason = "Maintained slow speed for sufficient duration when making"
|
||||
+ " pause harder to trigger";
|
||||
} else {
|
||||
mSlowStartTime = 0;
|
||||
isPaused = false;
|
||||
isPausedReason = "Intentionally making pause harder to trigger";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
updatePaused(isPaused);
|
||||
updatePaused(isPaused, isPausedReason);
|
||||
}
|
||||
|
||||
private void updatePaused(boolean isPaused) {
|
||||
private void updatePaused(boolean isPaused, String reason) {
|
||||
if (mDisallowPause) {
|
||||
reason = "Disallow pause; otherwise, would have been " + isPaused + " due to " + reason;
|
||||
isPaused = false;
|
||||
}
|
||||
if (mIsPaused != isPaused) {
|
||||
mIsPaused = isPaused;
|
||||
Log.d(TAG, "onMotionPauseChanged, paused=" + mIsPaused + " reason=" + reason);
|
||||
boolean isFirstDetectedPause = !mHasEverBeenPaused && mIsPaused;
|
||||
if (mIsPaused) {
|
||||
AccessibilityManagerCompat.sendPauseDetectedEventToTest(mContext);
|
||||
|
||||
@@ -30,6 +30,7 @@ public class Alarm implements Runnable{
|
||||
private Handler mHandler;
|
||||
private OnAlarmListener mAlarmListener;
|
||||
private boolean mAlarmPending = false;
|
||||
private long mLastSetTimeout;
|
||||
|
||||
public Alarm() {
|
||||
mHandler = new Handler();
|
||||
@@ -46,6 +47,7 @@ public class Alarm implements Runnable{
|
||||
mAlarmPending = true;
|
||||
long oldTriggerTime = mAlarmTriggerTime;
|
||||
mAlarmTriggerTime = currentTime + millisecondsInFuture;
|
||||
mLastSetTimeout = millisecondsInFuture;
|
||||
|
||||
// If the previous alarm was set for a longer duration, cancel it.
|
||||
if (mWaitingForCallback && oldTriggerTime > mAlarmTriggerTime) {
|
||||
@@ -84,4 +86,9 @@ public class Alarm implements Runnable{
|
||||
public boolean alarmPending() {
|
||||
return mAlarmPending;
|
||||
}
|
||||
|
||||
/** Returns the last value passed to {@link #setAlarm(long)} */
|
||||
public long getLastSetTimeout() {
|
||||
return mLastSetTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,8 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
||||
return true;
|
||||
}
|
||||
if (isSearching()) {
|
||||
if (isSearching()
|
||||
&& mActivityContext.getDragLayer().isEventOverView(getVisibleContainerView(), ev)) {
|
||||
// if in search state, consume touch event.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -277,6 +277,10 @@ public final class FeatureFlags {
|
||||
"ENABLE_DISMISS_PREDICTION_UNDO", false,
|
||||
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
|
||||
|
||||
public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(
|
||||
"ENABLE_CACHED_WIDGET", true,
|
||||
"Show previously cached widgets as opposed to deferred widget where available");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.SparseArray;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -37,6 +38,7 @@ import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.WidgetsModel;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
@@ -70,13 +72,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
|
||||
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
|
||||
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
|
||||
private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>();
|
||||
private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
|
||||
|
||||
private final Context mContext;
|
||||
private int mFlags = FLAG_STATE_IS_NORMAL;
|
||||
|
||||
private IntConsumer mAppWidgetRemovedCallback = null;
|
||||
|
||||
|
||||
public LauncherAppWidgetHost(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -95,6 +98,11 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
if (mPendingViews.get(appWidgetId) != null) {
|
||||
view = mPendingViews.get(appWidgetId);
|
||||
mPendingViews.remove(appWidgetId);
|
||||
} else if (mDeferredViews.get(appWidgetId) != null) {
|
||||
// In case the widget view is deferred, we will simply return the deferred view as
|
||||
// opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher
|
||||
// already added the former to the workspace.
|
||||
view = mDeferredViews.get(appWidgetId);
|
||||
} else {
|
||||
view = new LauncherAppWidgetHostView(context);
|
||||
}
|
||||
@@ -120,12 +128,25 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
// widgets upon bind anyway. See issue 14255011 for more context.
|
||||
}
|
||||
|
||||
// We go in reverse order and inflate any deferred widget
|
||||
// We go in reverse order and inflate any deferred or cached widget
|
||||
for (int i = mViews.size() - 1; i >= 0; i--) {
|
||||
LauncherAppWidgetHostView view = mViews.valueAt(i);
|
||||
if (view instanceof DeferredAppWidgetHostView) {
|
||||
view.reInflate();
|
||||
}
|
||||
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
|
||||
final int appWidgetId = mViews.keyAt(i);
|
||||
if (view == mDeferredViews.get(appWidgetId)) {
|
||||
// If the widget view was deferred, we'll need to call super.createView here
|
||||
// to make the binder call to system process to fetch cumulative updates to this
|
||||
// widget, as well as setting up this view for future updates.
|
||||
super.createView(view.mLauncher, appWidgetId, view.getAppWidgetInfo());
|
||||
// At this point #onCreateView should have been called, which in turn returned
|
||||
// the deferred view. There's no reason to keep the reference anymore, so we
|
||||
// removed it here.
|
||||
mDeferredViews.remove(appWidgetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,10 +242,28 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
|
||||
return lahv;
|
||||
} else if ((mFlags & FLAG_LISTENING) == 0) {
|
||||
DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
|
||||
view.setAppWidget(appWidgetId, appWidget);
|
||||
mViews.put(appWidgetId, view);
|
||||
return view;
|
||||
// Since the launcher hasn't started listening to widget updates, we can't simply call
|
||||
// super.createView here because the later will make a binder call to retrieve
|
||||
// RemoteViews from system process.
|
||||
// TODO: have launcher always listens to widget updates in background so that this
|
||||
// check can be removed altogether.
|
||||
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()
|
||||
&& mCachedRemoteViews.get(appWidgetId) != null) {
|
||||
// We've found RemoteViews from cache for this widget, so we will instantiate a
|
||||
// widget host view and populate it with the cached RemoteViews.
|
||||
final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
|
||||
view.setAppWidget(appWidgetId, appWidget);
|
||||
view.updateAppWidget(mCachedRemoteViews.get(appWidgetId));
|
||||
mDeferredViews.put(appWidgetId, view);
|
||||
mViews.put(appWidgetId, view);
|
||||
return view;
|
||||
} else {
|
||||
// When cache misses, a placeholder for the widget will be returned instead.
|
||||
DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
|
||||
view.setAppWidget(appWidgetId, appWidget);
|
||||
mViews.put(appWidgetId, view);
|
||||
return view;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return super.createView(context, appWidgetId, appWidget);
|
||||
@@ -281,6 +320,16 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
|
||||
@Override
|
||||
public void clearViews() {
|
||||
super.clearViews();
|
||||
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
|
||||
// First, we clear any previously cached content from existing widgets
|
||||
mCachedRemoteViews.clear();
|
||||
// Then we proceed to cache the content from the widgets
|
||||
for (int i = 0; i < mViews.size(); i++) {
|
||||
final int appWidgetId = mViews.keyAt(i);
|
||||
final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
|
||||
mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
|
||||
}
|
||||
}
|
||||
mViews.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.launcher3.CheckLongPressHelper;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
@@ -85,7 +86,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
|
||||
private Runnable mAutoAdvanceRunnable;
|
||||
|
||||
private long mDeferUpdatesUntilMillis = 0;
|
||||
private RemoteViews mDeferredRemoteViews;
|
||||
RemoteViews mLastRemoteViews;
|
||||
private boolean mHasDeferredColorChange = false;
|
||||
private @Nullable SparseIntArray mDeferredColorChange = null;
|
||||
|
||||
@@ -150,11 +151,18 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
|
||||
TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
|
||||
mTrackingWidgetUpdate = false;
|
||||
}
|
||||
if (isDeferringUpdates()) {
|
||||
mDeferredRemoteViews = remoteViews;
|
||||
return;
|
||||
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
|
||||
mLastRemoteViews = remoteViews;
|
||||
if (isDeferringUpdates()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (isDeferringUpdates()) {
|
||||
mLastRemoteViews = remoteViews;
|
||||
return;
|
||||
}
|
||||
mLastRemoteViews = null;
|
||||
}
|
||||
mDeferredRemoteViews = null;
|
||||
|
||||
super.updateAppWidget(remoteViews);
|
||||
|
||||
@@ -218,8 +226,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
|
||||
SparseIntArray deferredColors;
|
||||
boolean hasDeferredColors;
|
||||
mDeferUpdatesUntilMillis = 0;
|
||||
remoteViews = mDeferredRemoteViews;
|
||||
mDeferredRemoteViews = null;
|
||||
remoteViews = mLastRemoteViews;
|
||||
deferredColors = mDeferredColorChange;
|
||||
hasDeferredColors = mHasDeferredColorChange;
|
||||
mDeferredColorChange = null;
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
@@ -191,6 +192,17 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
isInState(() -> LauncherState.ALL_APPS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testAllAppsDeadzoneForTablet() throws Exception {
|
||||
assumeTrue(mLauncher.isTablet());
|
||||
|
||||
mLauncher.getWorkspace().switchToAllApps().dismissByTappingOutsideForTablet(
|
||||
true /* tapRight */);
|
||||
mLauncher.getWorkspace().switchToAllApps().dismissByTappingOutsideForTablet(
|
||||
false /* tapRight */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ScreenRecord // b/202433017
|
||||
public void testWorkspace() throws Exception {
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.launcher3.tapl;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.SystemClock;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
@@ -50,25 +45,15 @@ public class Folder {
|
||||
}
|
||||
}
|
||||
|
||||
private void touchOutsideFolder() {
|
||||
Rect containerBounds = mLauncher.getVisibleBounds(this.mContainer);
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
Point containerLeftTopCorner = new Point(containerBounds.left - 1, containerBounds.top - 1);
|
||||
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
|
||||
containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
|
||||
mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP,
|
||||
containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
|
||||
}
|
||||
|
||||
/**
|
||||
* CLose opened folder if possible. It throws assertion error if the folder is already closed.
|
||||
* Close opened folder if possible. It throws assertion error if the folder is already closed.
|
||||
*/
|
||||
public Workspace close() {
|
||||
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
|
||||
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"Want to close opened folder")) {
|
||||
mLauncher.waitForLauncherObject(FOLDER_CONTENT_RES_ID);
|
||||
touchOutsideFolder();
|
||||
mLauncher.touchOutsideContainer(this.mContainer, false /* tapRight */);
|
||||
mLauncher.waitUntilLauncherObjectGone(FOLDER_CONTENT_RES_ID);
|
||||
return mLauncher.getWorkspace();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
public class HomeAllApps extends AllApps {
|
||||
private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
|
||||
|
||||
HomeAllApps(LauncherInstrumentation launcher) {
|
||||
super(launcher);
|
||||
@@ -45,4 +46,23 @@ public class HomeAllApps extends AllApps {
|
||||
protected boolean hasSearchBox() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only.
|
||||
* @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
|
||||
*/
|
||||
public Workspace dismissByTappingOutsideForTablet(boolean tapRight) {
|
||||
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
|
||||
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to tap outside AllApps bottom sheet on the "
|
||||
+ (tapRight ? "right" : "left"))) {
|
||||
final UiObject2 allAppsBottomSheet =
|
||||
mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
|
||||
mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
|
||||
try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
|
||||
"tapped outside AllApps bottom sheet")) {
|
||||
return mLauncher.getWorkspace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1831,4 +1831,26 @@ public final class LauncherInstrumentation {
|
||||
return ResourceUtils.getBoolByName(
|
||||
"config_supportsRoundedCornersOnWindows", resources, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Taps outside container to dismiss.
|
||||
* @param container container to be dismissed
|
||||
* @param tapRight tap on the right of the container if true, or left otherwise
|
||||
*/
|
||||
void touchOutsideContainer(UiObject2 container, boolean tapRight) {
|
||||
try (LauncherInstrumentation.Closable c = addContextLayer(
|
||||
"want to tap outside container on the " + (tapRight ? "right" : "left"))) {
|
||||
Rect containerBounds = getVisibleBounds(container);
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
final Point tapTarget = new Point(
|
||||
tapRight
|
||||
? (containerBounds.right + getRealDisplaySize().x) / 2
|
||||
: containerBounds.left / 2,
|
||||
containerBounds.top + 1);
|
||||
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
|
||||
LauncherInstrumentation.GestureScope.INSIDE);
|
||||
sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
|
||||
LauncherInstrumentation.GestureScope.INSIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
public class SearchResultFromQsb {
|
||||
// The input resource id in the search box.
|
||||
private static final String INPUT_RES = "input";
|
||||
private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
|
||||
private final LauncherInstrumentation mLauncher;
|
||||
|
||||
SearchResultFromQsb(LauncherInstrumentation launcher) {
|
||||
@@ -47,4 +48,23 @@ public class SearchResultFromQsb {
|
||||
UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
|
||||
return new AllAppsAppIcon(mLauncher, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only.
|
||||
* @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
|
||||
*/
|
||||
public Workspace dismissByTappingOutsideForTablet(boolean tapRight) {
|
||||
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
|
||||
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to tap outside AllApps bottom sheet on the "
|
||||
+ (tapRight ? "right" : "left"))) {
|
||||
final UiObject2 allAppsBottomSheet =
|
||||
mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
|
||||
mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
|
||||
try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
|
||||
"tapped outside AllApps bottom sheet")) {
|
||||
return mLauncher.getWorkspace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user