Merge "Clean up some more refs to thumbnail data" into ub-launcher3-qt-dev
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 39f8448..900b94e 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -19,15 +19,21 @@
import android.annotation.TargetApi;
import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.UserManagerCompat;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -37,7 +43,16 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
- private static final String TAG = "TouchInteractionService";
+ private static final String TAG = "GoTouchInteractionService";
+ private boolean mIsUserUnlocked;
+ private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ initWhenUserUnlocked();
+ }
+ }
+ };
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@@ -53,17 +68,21 @@
@Override
public void onOverviewToggle() {
- mOverviewCommandHelper.onOverviewToggle();
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onOverviewToggle();
+ }
}
@Override
public void onOverviewShown(boolean triggeredFromAltTab) {
- mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
+ }
}
@Override
public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (triggeredFromAltTab && !triggeredFromHomeKey) {
+ if (mIsUserUnlocked && triggeredFromAltTab && !triggeredFromHomeKey) {
// onOverviewShownFromAltTab hides the overview and ends at the target app
mOverviewCommandHelper.onOverviewHidden();
}
@@ -71,7 +90,9 @@
@Override
public void onTip(int actionType, int viewType) {
- mOverviewCommandHelper.onTip(actionType, viewType);
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onTip(actionType, viewType);
+ }
}
@Override
@@ -123,17 +144,31 @@
@Override
public void onCreate() {
super.onCreate();
- mRecentsModel = RecentsModel.INSTANCE.get(this);
- mOverviewComponentObserver = new OverviewComponentObserver(this);
- mOverviewCommandHelper = new OverviewCommandHelper(this,
- mOverviewComponentObserver);
+ if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) {
+ initWhenUserUnlocked();
+ } else {
+ mIsUserUnlocked = false;
+ registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+ }
sConnected = true;
}
+ private void initWhenUserUnlocked() {
+ mRecentsModel = RecentsModel.INSTANCE.get(this);
+ mOverviewComponentObserver = new OverviewComponentObserver(this);
+ mOverviewCommandHelper = new OverviewCommandHelper(this,
+ mOverviewComponentObserver);
+ mIsUserUnlocked = true;
+ Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
+ }
+
@Override
public void onDestroy() {
- mOverviewComponentObserver.onDestroy();
+ if (mIsUserUnlocked) {
+ mOverviewComponentObserver.onDestroy();
+ }
+ Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
sConnected = false;
super.onDestroy();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 22ebe61..8f08f0d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -81,6 +81,7 @@
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantTouchConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -614,6 +615,10 @@
} else if (mGestureBlockingActivity != null && runningTaskInfo != null
&& mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
return mResetGestureInputConsumer;
+ } else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
+ return new FallbackNoButtonInputConsumer(this, activityControl,
+ mInputMonitorCompat, mSwipeSharedState, mSwipeTouchRegion,
+ mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
} else {
return createOtherActivityInputConsumer(event, runningTaskInfo);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
new file mode 100644
index 0000000..d05ca2a
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_SWIPE_DURATION;
+import static com.android.quickstep.inputconsumers.OtherActivityInputConsumer.QUICKSTEP_TOUCH_SLOP_RATIO;
+import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.R;
+import com.android.quickstep.ActivityControlHelper;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.SwipeSharedState;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
+import com.android.quickstep.util.NavBarPosition;
+import com.android.quickstep.util.RecentsAnimationListenerSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimationListener {
+
+ private static final int STATE_NOT_FINISHED = 0;
+ private static final int STATE_FINISHED_TO_HOME = 1;
+ private static final int STATE_FINISHED_TO_APP = 2;
+
+ private static final float PROGRESS_TO_END_GESTURE = -2;
+
+ private final ActivityControlHelper mActivityControlHelper;
+ private final InputMonitorCompat mInputMonitor;
+ private final Context mContext;
+ private final NavBarPosition mNavBarPosition;
+ private final SwipeSharedState mSwipeSharedState;
+ private final OverviewComponentObserver mOverviewComponentObserver;
+ private final int mRunningTaskId;
+
+ private final ClipAnimationHelper mClipAnimationHelper;
+ private final TransformParams mTransformParams = new TransformParams();
+ private final float mTransitionDragLength;
+ private final DeviceProfile mDP;
+
+ private final RectF mSwipeTouchRegion;
+ private final boolean mDisableHorizontalSwipe;
+
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+
+ private int mActivePointerId = -1;
+ // Slop used to determine when we say that the gesture has started.
+ private boolean mPassedPilferInputSlop;
+
+ private VelocityTracker mVelocityTracker;
+
+ // Distance after which we start dragging the window.
+ private final float mTouchSlop;
+
+ // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
+ private float mStartDisplacement;
+ private SwipeAnimationTargetSet mSwipeAnimationTargetSet;
+ private float mProgress;
+
+ private int mState = STATE_NOT_FINISHED;
+
+ public FallbackNoButtonInputConsumer(Context context,
+ ActivityControlHelper activityControlHelper, InputMonitorCompat inputMonitor,
+ SwipeSharedState swipeSharedState, RectF swipeTouchRegion,
+ OverviewComponentObserver overviewComponentObserver,
+ boolean disableHorizontalSwipe, RunningTaskInfo runningTaskInfo) {
+ mContext = context;
+ mActivityControlHelper = activityControlHelper;
+ mInputMonitor = inputMonitor;
+ mOverviewComponentObserver = overviewComponentObserver;
+ mRunningTaskId = runningTaskInfo.id;
+
+ mSwipeSharedState = swipeSharedState;
+ mSwipeTouchRegion = swipeTouchRegion;
+ mDisableHorizontalSwipe = disableHorizontalSwipe;
+
+ mNavBarPosition = new NavBarPosition(context);
+ mVelocityTracker = VelocityTracker.obtain();
+
+ mTouchSlop = QUICKSTEP_TOUCH_SLOP_RATIO
+ * ViewConfiguration.get(context).getScaledTouchSlop();
+
+ mClipAnimationHelper = new ClipAnimationHelper(context);
+
+ mDP = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context).copy(context);
+ Rect tempRect = new Rect();
+ mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
+ mDP, context, tempRect);
+ mClipAnimationHelper.updateTargetRect(tempRect);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_FALLBACK_NO_BUTTON;
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ return;
+ }
+
+ mVelocityTracker.addMovement(ev);
+ if (ev.getActionMasked() == ACTION_POINTER_UP) {
+ mVelocityTracker.clear();
+ }
+
+ switch (ev.getActionMasked()) {
+ case ACTION_DOWN: {
+ mActivePointerId = ev.getPointerId(0);
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
+ break;
+ }
+ case ACTION_POINTER_DOWN: {
+ if (!mPassedPilferInputSlop) {
+ // Cancel interaction in case of multi-touch interaction
+ int ptrIdx = ev.getActionIndex();
+ if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
+ forceCancelGesture(ev);
+ }
+ }
+ break;
+ }
+ case ACTION_POINTER_UP: {
+ int ptrIdx = ev.getActionIndex();
+ int ptrId = ev.getPointerId(ptrIdx);
+ if (ptrId == mActivePointerId) {
+ final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+ mDownPos.set(
+ ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+ ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+ mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+ mActivePointerId = ev.getPointerId(newPointerIdx);
+ }
+ break;
+ }
+ case ACTION_MOVE: {
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == INVALID_POINTER_ID) {
+ break;
+ }
+ mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+ float displacement = getDisplacement(ev);
+
+ if (!mPassedPilferInputSlop) {
+ if (mDisableHorizontalSwipe && Math.abs(mLastPos.x - mDownPos.x)
+ > Math.abs(mLastPos.y - mDownPos.y)) {
+ // Horizontal gesture is not allowed in this region
+ forceCancelGesture(ev);
+ break;
+ }
+
+ if (Math.abs(displacement) >= mTouchSlop) {
+ mPassedPilferInputSlop = true;
+
+ // Deferred gesture, start the animation and gesture tracking once
+ // we pass the actual touch slop
+ startTouchTrackingForWindowAnimation(displacement);
+ }
+ } else {
+ updateDisplacement(displacement - mStartDisplacement);
+ }
+ break;
+ }
+ case ACTION_CANCEL:
+ case ACTION_UP: {
+ finishTouchTracking(ev);
+ break;
+ }
+ }
+ }
+
+ private void startTouchTrackingForWindowAnimation(float displacement) {
+ mStartDisplacement = Math.min(displacement, -mTouchSlop);
+
+ RecentsAnimationListenerSet listenerSet =
+ mSwipeSharedState.newRecentsAnimationListenerSet();
+ listenerSet.addListener(this);
+ Intent homeIntent = mOverviewComponentObserver.getHomeIntent();
+ BackgroundExecutor.get().submit(
+ () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+ homeIntent, null, listenerSet, null, null));
+
+ ActivityManagerWrapper.getInstance().closeSystemWindows(
+ CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ mInputMonitor.pilferPointers();
+ }
+
+ private void updateDisplacement(float displacement) {
+ mProgress = displacement / mTransitionDragLength;
+ mTransformParams.setProgress(mProgress);
+
+ if (mSwipeAnimationTargetSet != null) {
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+ }
+ }
+
+ private void forceCancelGesture(MotionEvent ev) {
+ int action = ev.getAction();
+ ev.setAction(ACTION_CANCEL);
+ finishTouchTracking(ev);
+ ev.setAction(action);
+ }
+
+ /**
+ * Called when the gesture has ended. Does not correlate to the completion of the interaction as
+ * the animation can still be running.
+ */
+ private void finishTouchTracking(MotionEvent ev) {
+ if (ev.getAction() == ACTION_CANCEL) {
+ mState = STATE_FINISHED_TO_APP;
+ } else {
+ mVelocityTracker.computeCurrentVelocity(1000,
+ ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
+ float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
+ float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
+ float velocity = mNavBarPosition.isRightEdge() ? velocityX
+ : mNavBarPosition.isLeftEdge() ? -velocityX
+ : velocityY;
+ float flingThreshold = mContext.getResources()
+ .getDimension(R.dimen.quickstep_fling_threshold_velocity);
+ boolean isFling = Math.abs(velocity) > flingThreshold;
+
+ boolean goingHome;
+ if (!isFling) {
+ goingHome = -mProgress >= MIN_PROGRESS_FOR_OVERVIEW;
+ } else {
+ goingHome = velocity < 0;
+ }
+
+ if (goingHome) {
+ mState = STATE_FINISHED_TO_HOME;
+ } else {
+ mState = STATE_FINISHED_TO_APP;
+ }
+ }
+
+ if (mSwipeAnimationTargetSet != null) {
+ finishAnimationTargetSet();
+ }
+ }
+
+ private void finishAnimationTargetSet() {
+ if (mState == STATE_FINISHED_TO_APP) {
+ mSwipeAnimationTargetSet.finishController(false, null, false);
+ } else {
+ if (mProgress < PROGRESS_TO_END_GESTURE) {
+ mSwipeAnimationTargetSet.finishController(true, null, true);
+ } else {
+ long duration = (long) (Math.min(mProgress - PROGRESS_TO_END_GESTURE, 1)
+ * MAX_SWIPE_DURATION / Math.abs(PROGRESS_TO_END_GESTURE));
+ if (duration < 0) {
+ duration = MIN_SWIPE_DURATION;
+ }
+
+ ValueAnimator anim = ValueAnimator.ofFloat(mProgress, PROGRESS_TO_END_GESTURE);
+ anim.addUpdateListener(a -> {
+ float p = (Float) anim.getAnimatedValue();
+ mTransformParams.setProgress(p);
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+ });
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeAnimationTargetSet.finishController(true, null, true);
+ }
+ });
+ anim.start();
+ }
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
+ mSwipeAnimationTargetSet = targetSet;
+ Rect overviewStackBounds = new Rect(0, 0, mDP.widthPx, mDP.heightPx);
+ RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
+
+ mDP.updateIsSeascape(mContext.getSystemService(WindowManager.class));
+ if (runningTaskTarget != null) {
+ mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
+ }
+ mClipAnimationHelper.prepareAnimation(mDP, false /* isOpening */);
+
+ overviewStackBounds
+ .inset(-overviewStackBounds.width() / 5, -overviewStackBounds.height() / 5);
+ mClipAnimationHelper.updateTargetRect(overviewStackBounds);
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+
+ if (mState != STATE_NOT_FINISHED) {
+ finishAnimationTargetSet();
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled() { }
+
+ private float getDisplacement(MotionEvent ev) {
+ if (mNavBarPosition.isRightEdge()) {
+ return ev.getX() - mDownPos.x;
+ } else if (mNavBarPosition.isLeftEdge()) {
+ return mDownPos.x - ev.getX();
+ } else {
+ return ev.getY() - mDownPos.y;
+ }
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mPassedPilferInputSlop;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
index a1e5d47..f5cf654 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
@@ -33,6 +33,7 @@
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
+ int TYPE_FALLBACK_NO_BUTTON = 1 << 9;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -44,6 +45,7 @@
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
+ "TYPE_FALLBACK_NO_BUTTON", // 9
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 6bc543f..4c137d3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -79,7 +79,7 @@
private static final String UP_EVT = "OtherActivityInputConsumer.UP";
// TODO: Move to quickstep contract
- private static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
+ public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final RunningTaskInfo mRunningTask;
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 0a73b8b..0738aff 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -33,7 +33,6 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.system.QuickStepContract;
import java.util.ArrayList;
/**
@@ -58,7 +57,9 @@
private String mUpdateRegisteredPackage;
private ActivityControlHelper mActivityControlHelper;
private Intent mOverviewIntent;
+ private Intent mHomeIntent;
private int mSystemUiStateFlags;
+ private boolean mIsHomeAndOverviewSame;
public OverviewComponentObserver(Context context) {
mContext = context;
@@ -93,11 +94,14 @@
final String overviewIntentCategory;
ComponentName overviewComponent;
+ mHomeIntent = null;
+
if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 &&
(defaultHome == null || mMyHomeComponent.equals(defaultHome))) {
// User default home is same as out home app. Use Overview integrated in Launcher.
overviewComponent = mMyHomeComponent;
mActivityControlHelper = new LauncherActivityControllerHelper();
+ mIsHomeAndOverviewSame = true;
overviewIntentCategory = Intent.CATEGORY_HOME;
if (mUpdateRegisteredPackage != null) {
@@ -109,8 +113,12 @@
// The default home app is a different launcher. Use the fallback Overview instead.
overviewComponent = new ComponentName(mContext, RecentsActivity.class);
mActivityControlHelper = new FallbackActivityControllerHelper();
+ mIsHomeAndOverviewSame = false;
overviewIntentCategory = Intent.CATEGORY_DEFAULT;
+ mHomeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setComponent(defaultHome);
// User's default home app can change as a result of package updates of this app (such
// as uninstalling the app or removing the "Launcher" feature in an update).
// Listen for package updates of this app (and remove any previously attached
@@ -135,6 +143,9 @@
.addCategory(overviewIntentCategory)
.setComponent(overviewComponent)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (mHomeIntent == null) {
+ mHomeIntent = mOverviewIntent;
+ }
}
/**
@@ -159,6 +170,20 @@
}
/**
+ * Get the current intent for going to the home activity.
+ */
+ public Intent getHomeIntent() {
+ return mHomeIntent;
+ }
+
+ /**
+ * Returns true if home and overview are same activity.
+ */
+ public boolean isHomeAndOverviewSame() {
+ return mIsHomeAndOverviewSame;
+ }
+
+ /**
* Get the current activity control helper for managing interactions to the overview activity.
*
* @return the current activity control helper
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 0135911..e5f949b 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -43,10 +43,12 @@
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.testcomponent.TestCommandReceiver;
+import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
@@ -62,10 +64,14 @@
private final LauncherInstrumentation mLauncher;
private final ActivityInfo mOtherLauncherActivity;
- @Rule public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
- @Rule public final TestRule mQuickstepOnOffExecutor;
+ @Rule
+ public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
- @Rule public final TestRule mSetLauncherCommand;
+ @Rule
+ public final TestRule mSetLauncherCommand;
+
+ @Rule
+ public final TestRule mOrderSensitiveRules;
public FallbackRecentsTest() throws RemoteException {
Instrumentation instrumentation = getInstrumentation();
@@ -74,7 +80,10 @@
mDevice.setOrientationNatural();
mLauncher = new LauncherInstrumentation(instrumentation);
- mQuickstepOnOffExecutor = new NavigationModeSwitchRule(mLauncher);
+ mOrderSensitiveRules = RuleChain.
+ outerRule(new NavigationModeSwitchRule(mLauncher)).
+ around(new FailureWatcher(mDevice));
+
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e663e70..4a0ca5c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -125,7 +125,7 @@
protected TestRule getRulesInsideActivityMonitor() {
return RuleChain.
outerRule(new PortraitLandscapeRunner(this)).
- around(new FailureWatcher(this));
+ around(new FailureWatcher(mDevice));
}
@Rule
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 874ff19..d36126b 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -15,8 +15,9 @@
*/
package com.android.launcher3.ui.widget;
+import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -24,43 +25,37 @@
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Workspace;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
+import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddWidgetInfo;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetHostViewLoader;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Set;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiSelector;
-import java.util.concurrent.Callable;
-
/**
* Tests for bind widget flow.
*
@@ -131,16 +126,14 @@
setupContents(item);
- // Since there is no widget to verify, just wait until the workspace is ready.
- // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
- mLauncher.getWorkspace();
+ final Workspace workspace = mLauncher.getWorkspace();
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
assertEquals(0, mCursor.getCount());
// The view does not exist
- assertFalse(mDevice.findObject(new UiSelector().description(info.label)).exists());
+ assertTrue("Widget exists", workspace.tryGetWidget(info.label, 0) == null);
}
@Test
@@ -189,12 +182,8 @@
setupContents(item);
- // Since there is no widget to verify, just wait until the workspace is ready.
- // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
- mLauncher.getWorkspace();
- // The view does not exist
- assertFalse(mDevice.findObject(
- new UiSelector().className(PendingAppWidgetHostView.class)).exists());
+ assertTrue("Pending widget exists",
+ mLauncher.getWorkspace().tryGetPendingWidget(0) == null);
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
@@ -258,12 +247,12 @@
* widget class is displayed on the homescreen.
*/
private void setupContents(LauncherAppWidgetInfo item) {
- int screenId = Workspace.FIRST_SCREEN_ID;
+ int screenId = FIRST_SCREEN_ID;
// Update the screen id counter for the provider.
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
- if (screenId > Workspace.FIRST_SCREEN_ID) {
- screenId = Workspace.FIRST_SCREEN_ID;
+ if (screenId > FIRST_SCREEN_ID) {
+ screenId = FIRST_SCREEN_ID;
}
// Insert the item
@@ -283,15 +272,13 @@
}
private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) {
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(LauncherAppWidgetHostView.class).description(info.label);
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ assertTrue("Widget is not present",
+ mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
}
private void verifyPendingWidgetPresent() {
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(PendingAppWidgetHostView.class);
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ assertTrue("Pending widget is not present",
+ mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT) != null);
}
/**
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 2766a3e..edec914 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -29,7 +29,6 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
import com.android.launcher3.ItemInfo;
@@ -81,15 +80,10 @@
@Test
public void testPinWidgetNoConfig() throws Throwable {
- runTest("pinWidgetNoConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetNoConfig.class.getName());
- }
- });
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
+ ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
+ ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ .equals(AppWidgetNoConfig.class.getName()));
}
@Test
@@ -99,28 +93,19 @@
RequestPinItemActivity.class, "setRemoteViewColor").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED);
- runTest("pinWidgetNoConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetNoConfig.class.getName());
- }
- }, command);
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
+ ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
+ ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ .equals(AppWidgetNoConfig.class.getName()), command);
}
@Test
public void testPinWidgetWithConfig() throws Throwable {
- runTest("pinWidgetWithConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
+ runTest("pinWidgetWithConfig", true,
+ (info, view) -> info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetWithConfig.class.getName());
- }
- });
+ .equals(AppWidgetWithConfig.class.getName()));
}
@Test
@@ -174,9 +159,7 @@
// call the requested method to start the flow
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, activityMethod));
- UiObject2 widgetCell = mDevice.wait(
- Until.findObject(By.clazz(WidgetCell.class)), DEFAULT_ACTIVITY_TIMEOUT);
- assertNotNull(widgetCell);
+ mLauncher.getWidgetCell();
// Accept confirmation:
BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction);
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 09cc98d..eef2f24 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -4,7 +4,7 @@
import android.util.Log;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import androidx.test.uiautomator.UiDevice;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -16,16 +16,16 @@
public class FailureWatcher extends TestWatcher {
private static final String TAG = "FailureWatcher";
private static int sScreenshotCount = 0;
- private AbstractLauncherUiTest mAbstractLauncherUiTest;
+ final private UiDevice mDevice;
- public FailureWatcher(AbstractLauncherUiTest abstractLauncherUiTest) {
- mAbstractLauncherUiTest = abstractLauncherUiTest;
+ public FailureWatcher(UiDevice device) {
+ mDevice = device;
}
private void dumpViewHierarchy() {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
- mAbstractLauncherUiTest.getDevice().dumpWindowHierarchy(stream);
+ mDevice.dumpWindowHierarchy(stream);
stream.flush();
stream.close();
for (String line : stream.toString().split("\\r?\\n")) {
@@ -38,7 +38,7 @@
@Override
protected void failed(Throwable e, Description description) {
- if (mAbstractLauncherUiTest.getDevice() == null) return;
+ if (mDevice == null) return;
final String pathname = getInstrumentation().getTargetContext().
getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
Log.e(TAG, "Failed test " + description.getMethodName() +
@@ -48,12 +48,12 @@
dumpViewHierarchy();
try {
- final String dumpsysResult = mAbstractLauncherUiTest.getDevice().executeShellCommand(
+ final String dumpsysResult = mDevice.executeShellCommand(
"dumpsys activity service TouchInteractionService");
Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
} catch (IOException ex) {
}
- mAbstractLauncherUiTest.getDevice().takeScreenshot(new File(pathname));
+ mDevice.takeScreenshot(new File(pathname));
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7171bf9..671e8fd 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -502,6 +502,13 @@
}
}
+ @NonNull
+ public WidgetCell getWidgetCell() {
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get widget cell")) {
+ return new WidgetCell(this);
+ }
+ }
+
/**
* Gets the Overview object if the current state is showing the overview panel. Fails if the
* launcher is not in that state.
@@ -516,17 +523,6 @@
}
/**
- * Gets the Base overview object if either Launcher is in overview state or the fallback
- * overview activity is showing. Fails otherwise.
- *
- * @return BaseOverview object.
- */
- @NonNull
- public BaseOverview getBaseOverview() {
- return new BaseOverview(this);
- }
-
- /**
* Gets the All Apps object if the current state is showing the all apps panel opened by swiping
* from workspace. Fails if the launcher is not in that state. Please don't call this method if
* App Apps was opened by swiping up from Overview, as it won't fail and will return an
@@ -617,6 +613,16 @@
}
@NonNull
+ UiObject2 waitForLauncherObject(BySelector selector) {
+ return waitForObjectBySelector(selector.pkg(getLauncherPackageName()));
+ }
+
+ @NonNull
+ UiObject2 tryWaitForLauncherObject(BySelector selector, long timeout) {
+ return tryWaitForObjectBySelector(selector.pkg(getLauncherPackageName()), timeout);
+ }
+
+ @NonNull
UiObject2 waitForFallbackLauncherObject(String resName) {
return waitForObjectBySelector(getFallbackLauncherObjectSelector(resName));
}
@@ -627,6 +633,10 @@
return object;
}
+ private UiObject2 tryWaitForObjectBySelector(BySelector selector, long timeout) {
+ return mDevice.wait(Until.findObject(selector), timeout);
+ }
+
BySelector getLauncherObjectSelector(String resName) {
return By.res(getLauncherPackageName(), resName);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
new file mode 100644
index 0000000..128789d
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+public class Widget {
+ Widget(LauncherInstrumentation launcher, UiObject2 widget) {
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/WidgetCell.java b/tests/tapl/com/android/launcher3/tapl/WidgetCell.java
new file mode 100644
index 0000000..adb69ec
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/WidgetCell.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+
+public class WidgetCell {
+ WidgetCell(LauncherInstrumentation launcher) {
+ final UiObject2 widgetCell = launcher.waitForLauncherObject(By.clazz(
+ "com.android.launcher3.widget.WidgetCell"));
+ launcher.assertNotNull("Can't find widget cell object", widgetCell);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 62050b9..fc0a793 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -27,6 +27,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
@@ -215,4 +216,19 @@
protected int getSwipeStartY() {
return mLauncher.getRealDisplaySize().y - 1;
}
+
+ @Nullable
+ public Widget tryGetWidget(String label, long timeout) {
+ final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
+ By.clazz("com.android.launcher3.widget.LauncherAppWidgetHostView").desc(label),
+ timeout);
+ return widget != null ? new Widget(mLauncher, widget) : null;
+ }
+
+ @Nullable
+ public Widget tryGetPendingWidget(long timeout) {
+ final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
+ By.clazz("com.android.launcher3.widget.PendingAppWidgetHostView"), timeout);
+ return widget != null ? new Widget(mLauncher, widget) : null;
+ }
}
\ No newline at end of file