Merge "Quick plug to solve flakiness caused by switching QS on/off" into ub-launcher3-master
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index af1b353..76abe8d 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -263,7 +263,9 @@
*/
public Bitmap createIconBitmap(Drawable icon, float scale, int size) {
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-
+ if (icon == null) {
+ return bitmap;
+ }
mCanvas.setBitmap(bitmap);
mOldBounds.set(icon.getBounds());
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 2966cb1..d84633d 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -505,7 +505,7 @@
}
static final class IconDB extends SQLiteCacheHelper {
- private final static int RELEASE_VERSION = 25;
+ private final static int RELEASE_VERSION = 26;
public final static String TABLE_NAME = "icons";
public final static String COLUMN_ROWID = "rowid";
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index 51e9495..027fd91 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -120,13 +120,11 @@
*/
public static void onLauncherStateOrResumeChanged(Launcher launcher) {
LauncherState state = launcher.getStateManager().getState();
- if (!OverviewInteractionState.INSTANCE.get(launcher).swipeGestureInitializing()) {
- DeviceProfile profile = launcher.getDeviceProfile();
- boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
- && !profile.isVerticalBarLayout();
- UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT_CMD,
- visible ? 1 : 0, profile.hotseatBarSizePx);
- }
+ DeviceProfile profile = launcher.getDeviceProfile();
+ boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
+ && !profile.isVerticalBarLayout();
+ UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT_CMD,
+ visible ? 1 : 0, profile.hotseatBarSizePx);
if (state == NORMAL) {
launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 4930dc5..0007b37 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -612,14 +612,10 @@
float transX0 = floatingViewBounds[0] - offsetX;
float transY0 = floatingViewBounds[1] - offsetY;
- // Animate window corner radius from 100% to windowCornerRadius.
- float windowCornerRadius = RecentsModel.INSTANCE.get(mLauncher)
- .getWindowCornerRadius();
float windowRadius = 0;
if (RecentsModel.INSTANCE.get(mLauncher).supportsRoundedCornersOnWindows()) {
- float circleRadius = iconWidth / 2f;
- windowRadius = Utilities.mapRange(easePercent, circleRadius,
- windowCornerRadius);
+ windowRadius = RecentsModel.INSTANCE.get(mLauncher)
+ .getWindowCornerRadius();
}
// Animate the window crop so that it starts off as a square, and then reveals
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index b61268b..3e2e9a6 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -30,8 +30,7 @@
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
-
-import java.util.function.Supplier;
+import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
/**
* Helper class for batching input events
@@ -49,29 +48,23 @@
ACTION_VIRTUAL | (2 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_QUICK_SCRUB_END =
ACTION_VIRTUAL | (3 << ACTION_POINTER_INDEX_SHIFT);
- private static final int ACTION_RESET =
+ private static final int ACTION_NEW_GESTURE =
ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_SHOW_OVERVIEW_FROM_ALT_TAB =
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
- private static final int ACTION_QUICK_STEP =
- ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
- private static final int ACTION_COMMAND =
- ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT);
- private static final int ACTION_SWITCH_CONSUMER =
- ACTION_VIRTUAL | (8 << ACTION_POINTER_INDEX_SHIFT);
private final InputEventDispatcher mDispatcher;
private final InputEventReceiver mReceiver;
-
- private final Object mConsumerParamsLock = new Object();
- private Supplier[] mConsumerParams = new Supplier[2];
+ private final ConsumerFactory mConsumerFactory;
private TouchConsumer mConsumer;
- public MotionEventQueue(Looper looper, Choreographer choreographer) {
+ public MotionEventQueue(Looper looper, Choreographer choreographer,
+ ConsumerFactory consumerFactory) {
Pair<InputEventDispatcher, InputEventReceiver> pair = InputChannelCompat.createPair(
"sysui-callbacks", looper, choreographer, this::onInputEvent);
+ mConsumerFactory = consumerFactory;
mConsumer = TouchConsumer.NO_OP;
mDispatcher = pair.first;
mReceiver = pair.second;
@@ -93,26 +86,16 @@
case ACTION_QUICK_SCRUB_END:
mConsumer.onQuickScrubEnd();
break;
- case ACTION_RESET:
- mConsumer.reset();
+ case ACTION_NEW_GESTURE: {
+ boolean useSharedState = mConsumer.isActive();
+ mConsumer.onConsumerAboutToBeSwitched();
+ mConsumer = mConsumerFactory.newConsumer(event.getSource(), useSharedState);
break;
+ }
case ACTION_SHOW_OVERVIEW_FROM_ALT_TAB:
mConsumer.onShowOverviewFromAltTab();
mConsumer.onQuickScrubStart();
break;
- case ACTION_QUICK_STEP:
- mConsumer.onQuickStep(event);
- break;
- case ACTION_COMMAND:
- mConsumer.onCommand(event.getSource());
- break;
- case ACTION_SWITCH_CONSUMER:
- synchronized (mConsumerParamsLock) {
- int index = event.getSource();
- mConsumer = (TouchConsumer) mConsumerParams[index].get();
- mConsumerParams[index] = null;
- }
- break;
default:
Log.e(TAG, "Invalid virtual event: " + event.getAction());
}
@@ -151,46 +134,26 @@
queueVirtualAction(ACTION_QUICK_SCRUB_END, 0);
}
- public void onQuickStep(MotionEvent event) {
- event.setAction(ACTION_QUICK_STEP);
- queue(event);
+ public void onNewGesture(@HitTarget int downHitTarget) {
+ queueVirtualAction(ACTION_NEW_GESTURE, downHitTarget);
}
- public void reset() {
- queueVirtualAction(ACTION_RESET, 0);
- }
-
- public void onCommand(int command) {
- queueVirtualAction(ACTION_COMMAND, command);
- }
-
- public void switchConsumer(Supplier<TouchConsumer> consumer) {
- int index = -1;
- synchronized (mConsumerParamsLock) {
- // Find a null index
- for (int i = 0; i < mConsumerParams.length; i++) {
- if (mConsumerParams[i] == null) {
- index = i;
- break;
- }
- }
- if (index < 0) {
- index = mConsumerParams.length;
- final Supplier[] newValues = new Supplier[index + 1];
- System.arraycopy(mConsumerParams, 0, newValues, 0, index);
- mConsumerParams = newValues;
- }
- mConsumerParams[index] = consumer;
+ /**
+ * To be called by the consumer when it's no longer active.
+ */
+ public void onConsumerInactive(TouchConsumer caller) {
+ if (mConsumer == caller) {
+ mConsumer = TouchConsumer.NO_OP;
}
- queueVirtualAction(ACTION_SWITCH_CONSUMER, index);
- }
-
- public TouchConsumer getConsumer() {
- return mConsumer;
}
public void dispose() {
mDispatcher.dispose();
mReceiver.dispose();
}
+
+ public interface ConsumerFactory {
+
+ TouchConsumer newConsumer(@HitTarget int downHitTarget, boolean useSharedState);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 5801c10..fa8eceb 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -25,7 +25,6 @@
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
@@ -37,7 +36,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
-import android.util.SparseArray;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
@@ -45,24 +43,23 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
-import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget;
import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.RecentsAnimationListenerSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RecentsAnimationListener;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
/**
* Touch consumer for handling events originating from an activity other than Launcher
@@ -73,44 +70,47 @@
public static final String DOWN_EVT = "OtherActivityTouchConsumer.DOWN";
private static final String UP_EVT = "OtherActivityTouchConsumer.UP";
- private final SparseArray<RecentsAnimationState> mAnimationStates = new SparseArray<>();
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
private final Intent mHomeIntent;
private final ActivityControlHelper mActivityControlHelper;
- private final MainThreadExecutor mMainThreadExecutor;
private final OverviewCallbacks mOverviewCallbacks;
private final TaskOverlayFactory mTaskOverlayFactory;
private final TouchInteractionLog mTouchInteractionLog;
private final InputConsumerController mInputConsumer;
+ private final SwipeSharedState mSwipeSharedState;
+
+ private final int mDisplayRotation;
+ private final Rect mStableInsets = new Rect();
private final MotionEventQueue mEventQueue;
private final MotionPauseDetector mMotionPauseDetector;
private VelocityTracker mVelocityTracker;
+ private WindowTransformSwipeHandler mInteractionHandler;
+
private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
- private boolean mPassedInitialSlop;
- // Used for non-deferred gestures to determine when to start dragging
- private int mQuickStepDragSlop;
- private float mStartDisplacement;
- private WindowTransformSwipeHandler mInteractionHandler;
- private int mDisplayRotation;
- private Rect mStableInsets = new Rect();
- private boolean mCanGestureBeContinued;
- private boolean mIsGoingToLauncher;
- private RecentsAnimationState mRecentsAnimationState;
+ private final float mDragSlop;
+ private final float mTouchSlop;
+
+ // Slop used to check when we start moving window.
+ private boolean mPassedDragSlop;
+ // Slop used to determine when we say that the gesture has started.
+ private boolean mPassedTouchSlop;
+
+ // TODO: Start displacement should have both x and y
+ private float mStartDisplacement;
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
- MainThreadExecutor mainThreadExecutor,
@HitTarget int downHitTarget, OverviewCallbacks overviewCallbacks,
TaskOverlayFactory taskOverlayFactory, InputConsumerController inputConsumer,
TouchInteractionLog touchInteractionLog, MotionEventQueue eventQueue,
- @Nullable RecentsAnimationState recentsAnimationStateToReuse) {
+ SwipeSharedState swipeSharedState) {
super(base);
mRunningTask = runningTaskInfo;
@@ -122,14 +122,22 @@
mVelocityTracker = VelocityTracker.obtain();
mActivityControlHelper = activityControl;
- mMainThreadExecutor = mainThreadExecutor;
mIsDeferredDownTarget = activityControl.deferStartingActivity(downHitTarget);
mOverviewCallbacks = overviewCallbacks;
mTaskOverlayFactory = taskOverlayFactory;
mTouchInteractionLog = touchInteractionLog;
mTouchInteractionLog.setTouchConsumer(this);
mInputConsumer = inputConsumer;
- mRecentsAnimationState = recentsAnimationStateToReuse;
+ mSwipeSharedState = swipeSharedState;
+
+ Display display = getSystemService(WindowManager.class).getDefaultDisplay();
+ mDisplayRotation = display.getRotation();
+ WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
+
+ mDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
+ mTouchSlop = NavigationBarCompat.getQuickStepTouchSlopPx();
+ // If active listener isn't null, we are continuing the previous gesture.
+ mPassedTouchSlop = mPassedDragSlop = mSwipeSharedState.getActiveListener() != null;
}
@Override
@@ -156,9 +164,6 @@
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
- // If mRecentsAnimationState != null, we are continuing the previous gesture.
- mPassedInitialSlop = mRecentsAnimationState != null;
- mQuickStepDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
@@ -166,9 +171,6 @@
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
- Display display = getSystemService(WindowManager.class).getDefaultDisplay();
- mDisplayRotation = display.getRotation();
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
RaceConditionTracker.onEvent(DOWN_EVT, EXIT);
break;
}
@@ -192,18 +194,38 @@
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacement = getDisplacement(ev);
- if (!mPassedInitialSlop) {
+
+ if (!mPassedDragSlop) {
if (!mIsDeferredDownTarget) {
// Normal gesture, ensure we pass the drag slop before we start tracking
// the gesture
- if (Math.abs(displacement) > mQuickStepDragSlop) {
- mPassedInitialSlop = true;
+ if (Math.abs(displacement) > mDragSlop) {
+ mPassedDragSlop = true;
mStartDisplacement = displacement;
}
}
}
- if (mPassedInitialSlop && mInteractionHandler != null) {
+ if (!mPassedTouchSlop) {
+ if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) >=
+ mTouchSlop) {
+ mPassedTouchSlop = true;
+
+ mTouchInteractionLog.startQuickStep();
+ if (mIsDeferredDownTarget) {
+ // Deferred gesture, start the animation and gesture tracking once
+ // we pass the actual touch slop
+ startTouchTrackingForWindowAnimation(ev.getEventTime());
+ }
+ if (!mPassedDragSlop) {
+ mPassedDragSlop = true;
+ mStartDisplacement = displacement;
+ }
+ notifyGestureStarted();
+ }
+ }
+
+ if (mPassedDragSlop && mInteractionHandler != null) {
// Move
dispatchMotion(ev, displacement - mStartDisplacement, null);
@@ -262,30 +284,23 @@
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
mTouchInteractionLog.startRecentsAnimation();
- // Create the shared handler
- boolean reuseOldAnimState = mRecentsAnimationState != null;
- if (reuseOldAnimState) {
- mRecentsAnimationState.changeParent(this);
- } else {
- mRecentsAnimationState = new RecentsAnimationState(this);
- }
+ RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener();
final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
- mRecentsAnimationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper,
- reuseOldAnimState, mInputConsumer, mTouchInteractionLog);
+ mRunningTask, this, touchTimeMs, mActivityControlHelper,
+ listenerSet != null, mInputConsumer, mTouchInteractionLog);
// Preload the plan
mRecentsModel.getTasks(null);
mInteractionHandler = handler;
- handler.setGestureEndCallback(mEventQueue::reset);
+ handler.setGestureEndCallback(this::onInteractionGestureFinished);
mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged);
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
- if (reuseOldAnimState) {
- handler.onRecentsAnimationStart(mRecentsAnimationState.mController,
- mRecentsAnimationState.mTargets, mRecentsAnimationState.mHomeContentInsets,
- mRecentsAnimationState.mMinimizedHomeBounds);
+ if (listenerSet != null) {
+ listenerSet.addListener(handler);
+ mSwipeSharedState.applyActiveRecentsAnimationState(handler);
} else {
AssistDataReceiver assistDataReceiver = !mTaskOverlayFactory.needAssist() ? null :
new AssistDataReceiver() {
@@ -300,18 +315,13 @@
}
};
+ RecentsAnimationListenerSet newListenerSet =
+ mSwipeSharedState.newRecentsAnimationListenerSet();
+ newListenerSet.addListener(handler);
BackgroundExecutor.get().submit(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
- mHomeIntent, assistDataReceiver, mRecentsAnimationState, null, null));
- }
-
- }
-
- @Override
- public void onCommand(int command) {
- RecentsAnimationState state = mAnimationStates.get(command);
- if (state != null) {
- state.execute();
+ mHomeIntent, assistDataReceiver, newListenerSet,
+ null, null));
}
}
@@ -320,7 +330,7 @@
* the animation can still be running.
*/
private void finishTouchTracking(MotionEvent ev) {
- if (mPassedInitialSlop && mInteractionHandler != null) {
+ if (mPassedDragSlop && mInteractionHandler != null) {
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
@@ -335,7 +345,8 @@
} else {
// Since we start touch tracking on DOWN, we may reach this state without actually
// starting the gesture. In that case, just cleanup immediately.
- reset();
+ onConsumerAboutToBeSwitched();
+ onInteractionGestureFinished();
// Also clean up in case the system has handled the UP and canceled the animation before
// we had a chance to start the recents animation. In such a case, we will not receive
@@ -347,25 +358,45 @@
}
@Override
- public void reset() {
- // Clean up the old interaction handler
+ public void onConsumerAboutToBeSwitched() {
+ Preconditions.assertUIThread();
if (mInteractionHandler != null) {
- final WindowTransformSwipeHandler handler = mInteractionHandler;
- mInteractionHandler = null;
- WindowTransformSwipeHandler.GestureEndTarget endTarget = handler.mGestureEndTarget;
- mIsGoingToLauncher = endTarget != null && endTarget.isLauncher;
- mCanGestureBeContinued = endTarget != null && endTarget.canBeContinued;
- mMainThreadExecutor.execute(mCanGestureBeContinued ? handler::cancel : handler::reset);
+ // The consumer is being switched while we are active. Set up the shared state to be
+ // used by the next animation
+ removeListener();
+ GestureEndTarget endTarget = mInteractionHandler.mGestureEndTarget;
+ mSwipeSharedState.canGestureBeContinued = endTarget != null && endTarget.canBeContinued;
+ mSwipeSharedState.goingToLauncher = endTarget != null && endTarget.isLauncher;
+ if (mSwipeSharedState.canGestureBeContinued) {
+ mInteractionHandler.cancel();
+ } else {
+ mInteractionHandler.reset();
+ }
+ }
+ }
+
+ @UiThread
+ private void onInteractionGestureFinished() {
+ Preconditions.assertUIThread();
+ removeListener();
+ mInteractionHandler = null;
+ mEventQueue.onConsumerInactive(this);
+ }
+
+ private void removeListener() {
+ RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener();
+ if (listenerSet != null) {
+ listenerSet.removeListener(mInteractionHandler);
}
}
@Override
public void onQuickScrubStart() {
- if (!mPassedInitialSlop && mIsDeferredDownTarget && mInteractionHandler == null) {
+ if (!mPassedDragSlop && mIsDeferredDownTarget && mInteractionHandler == null) {
// If we deferred starting the window animation on touch down, then
// start tracking now
startTouchTrackingForWindowAnimation(SystemClock.uptimeMillis());
- mPassedInitialSlop = true;
+ mPassedDragSlop = true;
}
mTouchInteractionLog.startQuickScrub();
@@ -391,21 +422,6 @@
}
}
- @Override
- public void onQuickStep(MotionEvent ev) {
- mTouchInteractionLog.startQuickStep();
- if (mIsDeferredDownTarget) {
- // Deferred gesture, start the animation and gesture tracking once we pass the actual
- // touch slop
- startTouchTrackingForWindowAnimation(ev.getEventTime());
- }
- if (!mPassedInitialSlop) {
- mPassedInitialSlop = true;
- mStartDisplacement = getDisplacement(ev);
- }
- notifyGestureStarted();
- }
-
private float getDisplacement(MotionEvent ev) {
float eventX = ev.getX();
float eventY = ev.getY();
@@ -419,81 +435,7 @@
}
@Override
- public boolean forceToLauncherConsumer() {
- return mIsGoingToLauncher;
- }
-
- @Override
- public @Nullable RecentsAnimationState getRecentsAnimationStateToReuse() {
- return mCanGestureBeContinued ? mRecentsAnimationState : null;
- }
-
- @Override
- public boolean deferNextEventToMainThread() {
- // TODO: Consider also check if the eventQueue is using mainThread of not.
+ public boolean isActive() {
return mInteractionHandler != null;
}
-
- public static class RecentsAnimationState implements RecentsAnimationListener {
-
- private static final String ANIMATION_START_EVT = "RecentsAnimationState.onAnimationStart";
- private final int id;
-
- private OtherActivityTouchConsumer mParent;
-
- private RecentsAnimationControllerCompat mController;
- private RemoteAnimationTargetSet mTargets;
- private Rect mHomeContentInsets;
- private Rect mMinimizedHomeBounds;
- private boolean mCancelled;
-
- public RecentsAnimationState(OtherActivityTouchConsumer parent) {
- mParent = parent;
- id = mParent.mAnimationStates.size();
- mParent.mAnimationStates.put(id, this);
- }
-
- @Override
- public void onAnimationStart(
- RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
- RaceConditionTracker.onEvent(ANIMATION_START_EVT, ENTER);
- mController = controller;
- mTargets = new RemoteAnimationTargetSet(apps, MODE_CLOSING);
- mHomeContentInsets = homeContentInsets;
- mMinimizedHomeBounds = minimizedHomeBounds;
- mParent.mEventQueue.onCommand(id);
- RaceConditionTracker.onEvent(ANIMATION_START_EVT, EXIT);
- }
-
- @Override
- public void onAnimationCanceled() {
- mCancelled = true;
- mParent.mEventQueue.onCommand(id);
- }
-
- public void execute() {
- WindowTransformSwipeHandler handler = mParent.mInteractionHandler;
- if (handler == null || handler.id != id) {
- if (!mCancelled && mController != null) {
- TraceHelper.endSection("RecentsController", "Finishing no handler");
- mController.finish(false /* toHome */);
- }
- } else if (mCancelled) {
- TraceHelper.endSection("RecentsController",
- "Cancelled: " + handler);
- handler.onRecentsAnimationCanceled();
- } else {
- TraceHelper.partitionSection("RecentsController", "Received");
- handler.onRecentsAnimationStart(mController, mTargets,
- mHomeContentInsets, mMinimizedHomeBounds);
- }
- }
-
- public void changeParent(OtherActivityTouchConsumer newParent) {
- mParent = newParent;
- mParent.mAnimationStates.put(id, this);
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 27f1399..eaa3ad4 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -64,8 +64,6 @@
private final Handler mUiHandler;
private final Handler mBgHandler;
- private boolean mSwipeGestureInitializing = false;
-
// These are updated on the background thread
private ISystemUiProxy mISystemUiProxy;
private boolean mSwipeUpEnabled = true;
@@ -177,15 +175,6 @@
}
}
- @WorkerThread
- public void setSwipeGestureInitializing(boolean swipeGestureInitializing) {
- mSwipeGestureInitializing = swipeGestureInitializing;
- }
-
- public boolean swipeGestureInitializing() {
- return mSwipeGestureInitializing;
- }
-
public void notifySwipeUpSettingChanged(boolean swipeUpEnabled) {
mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, swipeUpEnabled ? 1 : 0, 0).
diff --git a/quickstep/src/com/android/quickstep/OverviewTouchConsumer.java b/quickstep/src/com/android/quickstep/OverviewTouchConsumer.java
new file mode 100644
index 0000000..2638f23
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewTouchConsumer.java
@@ -0,0 +1,247 @@
+/*
+ * 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;
+
+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_INDEX_SHIFT;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+/**
+ * Touch consumer for handling touch on the recents/Launcher activity.
+ */
+public class OverviewTouchConsumer<T extends BaseDraggingActivity>
+ implements TouchConsumer {
+
+ private static final String TAG = "OverviewTouchConsumer";
+
+ private final ActivityControlHelper<T> mActivityHelper;
+ private final T mActivity;
+ private final BaseDragLayer mTarget;
+ private final int[] mLocationOnScreen = new int[2];
+ private final PointF mDownPos = new PointF();
+ private final int mTouchSlop;
+ private final QuickScrubController mQuickScrubController;
+ private final TouchInteractionLog mTouchInteractionLog;
+
+ private final boolean mStartingInActivityBounds;
+
+ private boolean mTrackingStarted = false;
+ private boolean mInvalidated = false;
+
+ private float mLastProgress = 0;
+ private boolean mStartPending = false;
+ private boolean mEndPending = false;
+ private boolean mWaitForWindowAvailable;
+
+ OverviewTouchConsumer(ActivityControlHelper<T> activityHelper, T activity,
+ boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog,
+ boolean waitForWindowAvailable) {
+ mActivityHelper = activityHelper;
+ mActivity = activity;
+ mTarget = activity.getDragLayer();
+ mTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
+ mStartingInActivityBounds = startingInActivityBounds;
+
+ mQuickScrubController = mActivity.<RecentsView>getOverviewPanel()
+ .getQuickScrubController();
+ mTouchInteractionLog = touchInteractionLog;
+ mTouchInteractionLog.setTouchConsumer(this);
+
+ mWaitForWindowAvailable = waitForWindowAvailable;
+ }
+
+ @Override
+ public void accept(MotionEvent ev) {
+ if (mInvalidated) {
+ return;
+ }
+ mTouchInteractionLog.addMotionEvent(ev);
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ if (mStartingInActivityBounds) {
+ startTouchTracking(ev, false /* updateLocationOffset */,
+ false /* closeActiveWindows */);
+ return;
+ }
+ mTrackingStarted = false;
+ mDownPos.set(ev.getX(), ev.getY());
+ } else if (!mTrackingStarted) {
+ switch (action) {
+ case ACTION_CANCEL:
+ case ACTION_UP:
+ startTouchTracking(ev, true /* updateLocationOffset */,
+ false /* closeActiveWindows */);
+ break;
+ case ACTION_MOVE: {
+ float displacement = mActivity.getDeviceProfile().isLandscape ?
+ ev.getX() - mDownPos.x : ev.getY() - mDownPos.y;
+ if (Math.abs(displacement) >= mTouchSlop) {
+ // Start tracking only when mTouchSlop is crossed.
+ startTouchTracking(ev, true /* updateLocationOffset */,
+ true /* closeActiveWindows */);
+ }
+ }
+ }
+ }
+
+ if (mTrackingStarted) {
+ sendEvent(ev);
+ }
+
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mInvalidated = true;
+ }
+ }
+
+ private void startTouchTracking(MotionEvent ev, boolean updateLocationOffset,
+ boolean closeActiveWindows) {
+ if (updateLocationOffset) {
+ mTarget.getLocationOnScreen(mLocationOnScreen);
+ }
+
+ // Send down touch event
+ MotionEvent down = MotionEvent.obtainNoHistory(ev);
+ down.setAction(ACTION_DOWN);
+ sendEvent(down);
+
+ mTrackingStarted = true;
+ // Send pointer down for remaining pointers.
+ int pointerCount = ev.getPointerCount();
+ for (int i = 1; i < pointerCount; i++) {
+ down.setAction(ACTION_POINTER_DOWN | (i << ACTION_POINTER_INDEX_SHIFT));
+ sendEvent(down);
+ }
+
+ down.recycle();
+
+ if (closeActiveWindows) {
+ OverviewCallbacks.get(mActivity).closeAllWindows();
+ ActivityManagerWrapper.getInstance()
+ .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ mTouchInteractionLog.startQuickStep();
+ }
+ }
+
+ private void sendEvent(MotionEvent ev) {
+ if (!mTarget.verifyTouchDispatch(this, ev)) {
+ mInvalidated = true;
+ return;
+ }
+ int flags = ev.getEdgeFlags();
+ ev.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
+ ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
+ if (!mTrackingStarted) {
+ mTarget.onInterceptTouchEvent(ev);
+ }
+ mTarget.onTouchEvent(ev);
+ ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
+ ev.setEdgeFlags(flags);
+ }
+
+ @Override
+ public void onQuickScrubStart() {
+ if (mInvalidated) {
+ return;
+ }
+ mTouchInteractionLog.startQuickScrub();
+ if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+ mInvalidated = true;
+ mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
+ return;
+ }
+ OverviewCallbacks.get(mActivity).closeAllWindows();
+ ActivityManagerWrapper.getInstance()
+ .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+
+ mStartPending = true;
+ Runnable action = () -> {
+ if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+ mInvalidated = true;
+ mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
+ return;
+ }
+ mActivityHelper.onQuickInteractionStart(mActivity, null, true,
+ mTouchInteractionLog);
+ mQuickScrubController.onQuickScrubProgress(mLastProgress);
+ mStartPending = false;
+
+ if (mEndPending) {
+ mQuickScrubController.onQuickScrubEnd();
+ mEndPending = false;
+ }
+ };
+
+ if (mWaitForWindowAvailable) {
+ mActivityHelper.executeOnWindowAvailable(mActivity, action);
+ } else {
+ action.run();
+ }
+ }
+
+ @Override
+ public void onQuickScrubEnd() {
+ mTouchInteractionLog.endQuickScrub("onQuickScrubEnd");
+ if (mInvalidated) {
+ return;
+ }
+ if (mStartPending) {
+ mEndPending = true;
+ } else {
+ mQuickScrubController.onQuickScrubEnd();
+ }
+ }
+
+ @Override
+ public void onQuickScrubProgress(float progress) {
+ mTouchInteractionLog.setQuickScrubProgress(progress);
+ mLastProgress = progress;
+ if (mInvalidated || mStartPending) {
+ return;
+ }
+ mQuickScrubController.onQuickScrubProgress(progress);
+ }
+
+ public static TouchConsumer newInstance(ActivityControlHelper activityHelper,
+ boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog) {
+ return newInstance(activityHelper, startingInActivityBounds, touchInteractionLog,
+ true /* waitForWindowAvailable */);
+ }
+
+ public static TouchConsumer newInstance(ActivityControlHelper activityHelper,
+ boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog,
+ boolean waitForWindowAvailable) {
+ BaseDraggingActivity activity = activityHelper.getCreatedActivity();
+ if (activity == null) {
+ return TouchConsumer.NO_OP;
+ }
+ return new OverviewTouchConsumer(activityHelper, activity, startingInActivityBounds,
+ touchInteractionLog, waitForWindowAvailable);
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index db0150e..ab5fce1 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -267,6 +267,10 @@
return mWaitingForTaskLaunch;
}
+ public boolean hasFinishedTransitionToQuickScrub() {
+ return mFinishedTransitionToQuickScrub;
+ }
+
/**
* Attempts to go to normal overview or back to home, so UI doesn't prevent user interaction.
*/
diff --git a/quickstep/src/com/android/quickstep/SwipeSharedState.java b/quickstep/src/com/android/quickstep/SwipeSharedState.java
new file mode 100644
index 0000000..15914ba
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SwipeSharedState.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.util.RecentsAnimationListenerSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
+
+/**
+ * Utility class used to store state information shared across multiple transitions.
+ */
+public class SwipeSharedState implements SwipeAnimationListener {
+
+ private RecentsAnimationListenerSet mRecentsAnimationListener;
+ private SwipeAnimationTargetSet mLastAnimationTarget;
+ private boolean mLastAnimationCancelled = false;
+
+ public boolean canGestureBeContinued;
+ public boolean goingToLauncher;
+
+ @Override
+ public final void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
+ mLastAnimationTarget = targetSet;
+ mLastAnimationCancelled = false;
+ }
+
+ @Override
+ public final void onRecentsAnimationCanceled() {
+ mLastAnimationTarget = null;
+ mLastAnimationCancelled = true;
+ }
+
+ private void clearListenerState() {
+ if (mRecentsAnimationListener != null) {
+ mRecentsAnimationListener.removeListener(this);
+ }
+ mRecentsAnimationListener = null;
+ mLastAnimationTarget = null;
+ mLastAnimationCancelled = false;
+ }
+
+ public RecentsAnimationListenerSet newRecentsAnimationListenerSet() {
+ Preconditions.assertUIThread();
+ clearListenerState();
+ mRecentsAnimationListener = new RecentsAnimationListenerSet();
+ mRecentsAnimationListener.addListener(this);
+ return mRecentsAnimationListener;
+ }
+
+ public RecentsAnimationListenerSet getActiveListener() {
+ return mRecentsAnimationListener;
+ }
+
+ public void applyActiveRecentsAnimationState(SwipeAnimationListener listener) {
+ if (mLastAnimationTarget != null) {
+ listener.onRecentsAnimationStart(mLastAnimationTarget);
+ } else if (mLastAnimationCancelled) {
+ listener.onRecentsAnimationCanceled();
+ }
+ }
+
+ public void clearAllState() {
+ clearListenerState();
+ canGestureBeContinued = false;
+ goingToLauncher = false;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index ef37595..d9b1fcf 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -20,9 +20,6 @@
import android.view.MotionEvent;
import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
-
-import com.android.quickstep.OtherActivityTouchConsumer.RecentsAnimationState;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,32 +40,20 @@
int INTERACTION_NORMAL = 0;
int INTERACTION_QUICK_SCRUB = 1;
- default void reset() { }
-
default void onQuickScrubStart() { }
default void onQuickScrubEnd() { }
default void onQuickScrubProgress(float progress) { }
- default void onQuickStep(MotionEvent ev) { }
+ default void onShowOverviewFromAltTab() {}
- default void onCommand(int command) { }
-
- default boolean deferNextEventToMainThread() {
- return false;
- }
-
- default boolean forceToLauncherConsumer() {
+ default boolean isActive() {
return false;
}
/**
- * When continuing a gesture, return the current non-null animation state that hasn't finished.
+ * Called by the event queue when the consumer is about to be switched to a new consumer.
*/
- default @Nullable RecentsAnimationState getRecentsAnimationStateToReuse() {
- return null;
- }
-
- default void onShowOverviewFromAltTab() {}
+ default void onConsumerAboutToBeSwitched() { }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 0f52deb..276ba05 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -17,35 +17,27 @@
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_INDEX_SHIFT;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
import android.content.Intent;
-import android.graphics.PointF;
+import android.graphics.Region;
import android.os.Build;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.OtherActivityTouchConsumer.RecentsAnimationState;
-import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -61,6 +53,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
+ public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor();
+
private static final SparseArray<String> sMotionEventNames;
static {
@@ -76,52 +70,43 @@
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
- @Override
+ public void onActiveNavBarRegionChanges(Region region) { }
+
+ public void onInitialize(Bundle params) { }
+
public void onPreMotionEvent(@HitTarget int downHitTarget) {
mTouchInteractionLog.prepareForNewGesture();
TraceHelper.beginSection("SysUiBinder");
- setupTouchConsumer(downHitTarget);
+ mEventQueue.onNewGesture(downHitTarget);
TraceHelper.partitionSection("SysUiBinder", "Down target " + downHitTarget);
}
- @Override
public void onMotionEvent(MotionEvent ev) {
mEventQueue.queue(ev);
int action = ev.getActionMasked();
- if (action == ACTION_DOWN) {
- mOverviewInteractionState.setSwipeGestureInitializing(true);
- } else if (action == ACTION_UP || action == ACTION_CANCEL) {
- mOverviewInteractionState.setSwipeGestureInitializing(false);
- }
-
String name = sMotionEventNames.get(action);
if (name != null){
TraceHelper.partitionSection("SysUiBinder", name);
}
}
- @Override
public void onBind(ISystemUiProxy iSystemUiProxy) {
mISystemUiProxy = iSystemUiProxy;
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
}
- @Override
public void onQuickScrubStart() {
mEventQueue.onQuickScrubStart();
- mOverviewInteractionState.setSwipeGestureInitializing(false);
TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
}
- @Override
public void onQuickScrubProgress(float progress) {
mEventQueue.onQuickScrubProgress(progress);
}
- @Override
public void onQuickScrubEnd() {
mEventQueue.onQuickScrubEnd();
TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
@@ -135,7 +120,7 @@
@Override
public void onOverviewShown(boolean triggeredFromAltTab) {
if (triggeredFromAltTab) {
- setupTouchConsumer(HIT_TARGET_NONE);
+ mEventQueue.onNewGesture(HIT_TARGET_NONE);
mEventQueue.onOverviewShownFromAltTab();
} else {
mOverviewCommandHelper.onOverviewShown();
@@ -150,12 +135,7 @@
}
}
- @Override
- public void onQuickStep(MotionEvent motionEvent) {
- mEventQueue.onQuickStep(motionEvent);
- mOverviewInteractionState.setSwipeGestureInitializing(false);
- TraceHelper.endSection("SysUiBinder", "onQuickStep");
- }
+ public void onQuickStep(MotionEvent motionEvent) { }
@Override
public void onTip(int actionType, int viewType) {
@@ -172,7 +152,6 @@
private ActivityManagerWrapper mAM;
private RecentsModel mRecentsModel;
private MotionEventQueue mEventQueue;
- private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy;
private OverviewCommandHelper mOverviewCommandHelper;
private OverviewComponentObserver mOverviewComponentObserver;
@@ -181,20 +160,22 @@
private TaskOverlayFactory mTaskOverlayFactory;
private TouchInteractionLog mTouchInteractionLog;
private InputConsumerController mInputConsumer;
+ private SwipeSharedState mSwipeSharedState;
@Override
public void onCreate() {
super.onCreate();
mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.INSTANCE.get(this);
- mMainThreadExecutor = new MainThreadExecutor();
mOverviewComponentObserver = new OverviewComponentObserver(this);
mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver);
- mEventQueue = new MotionEventQueue(Looper.myLooper(), Choreographer.getInstance());
+ mEventQueue = new MotionEventQueue(Looper.myLooper(), Choreographer.getInstance(),
+ this::newConsumer);
mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
mOverviewCallbacks = OverviewCallbacks.get(this);
mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this);
mTouchInteractionLog = new TouchInteractionLog();
+ mSwipeSharedState = new SwipeSharedState();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
mInputConsumer.registerInputConsumer();
@@ -219,27 +200,15 @@
return mMyBinder;
}
- private void setupTouchConsumer(@HitTarget int downHitTarget) {
- mEventQueue.reset();
- TouchConsumer oldConsumer = mEventQueue.getConsumer();
- if (oldConsumer.deferNextEventToMainThread()) {
- mEventQueue.switchConsumer(() -> getCurrentTouchConsumer(downHitTarget,
- oldConsumer.forceToLauncherConsumer(),
- oldConsumer.getRecentsAnimationStateToReuse()));
-
- } else {
- TouchConsumer consumer = getCurrentTouchConsumer(downHitTarget, false, null);
- mEventQueue.switchConsumer(() -> consumer);
- }
- }
-
- private TouchConsumer getCurrentTouchConsumer(@HitTarget int downHitTarget,
- boolean forceToLauncher, RecentsAnimationState recentsAnimationStateToReuse) {
+ private TouchConsumer newConsumer(@HitTarget int downHitTarget, boolean useSharedState) {
RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
+ if (!useSharedState) {
+ mSwipeSharedState.clearAllState();
+ }
- if (runningTaskInfo == null && !forceToLauncher) {
+ if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) {
return TouchConsumer.NO_OP;
- } else if (forceToLauncher ||
+ } else if (mSwipeSharedState.goingToLauncher ||
mOverviewComponentObserver.getActivityControlHelper().isResumed()) {
return OverviewTouchConsumer.newInstance(
mOverviewComponentObserver.getActivityControlHelper(), false,
@@ -252,10 +221,10 @@
} else {
return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
mOverviewComponentObserver.getOverviewIntent(),
- mOverviewComponentObserver.getActivityControlHelper(), mMainThreadExecutor,
+ mOverviewComponentObserver.getActivityControlHelper(),
downHitTarget, mOverviewCallbacks,
mTaskOverlayFactory, mInputConsumer, mTouchInteractionLog, mEventQueue,
- recentsAnimationStateToReuse);
+ mSwipeSharedState);
}
}
@@ -263,212 +232,4 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mTouchInteractionLog.dump(pw);
}
-
- public static class OverviewTouchConsumer<T extends BaseDraggingActivity>
- implements TouchConsumer {
-
- private final ActivityControlHelper<T> mActivityHelper;
- private final T mActivity;
- private final BaseDragLayer mTarget;
- private final int[] mLocationOnScreen = new int[2];
- private final PointF mDownPos = new PointF();
- private final int mTouchSlop;
- private final QuickScrubController mQuickScrubController;
- private final TouchInteractionLog mTouchInteractionLog;
-
- private final boolean mStartingInActivityBounds;
-
- private boolean mTrackingStarted = false;
- private boolean mInvalidated = false;
-
- private float mLastProgress = 0;
- private boolean mStartPending = false;
- private boolean mEndPending = false;
- private boolean mWaitForWindowAvailable;
-
- OverviewTouchConsumer(ActivityControlHelper<T> activityHelper, T activity,
- boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog,
- boolean waitForWindowAvailable) {
- mActivityHelper = activityHelper;
- mActivity = activity;
- mTarget = activity.getDragLayer();
- mTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
- mStartingInActivityBounds = startingInActivityBounds;
-
- mQuickScrubController = mActivity.<RecentsView>getOverviewPanel()
- .getQuickScrubController();
- mTouchInteractionLog = touchInteractionLog;
- mTouchInteractionLog.setTouchConsumer(this);
-
- mWaitForWindowAvailable = waitForWindowAvailable;
- }
-
- @Override
- public void accept(MotionEvent ev) {
- if (mInvalidated) {
- return;
- }
- mTouchInteractionLog.addMotionEvent(ev);
- int action = ev.getActionMasked();
- if (action == ACTION_DOWN) {
- if (mStartingInActivityBounds) {
- startTouchTracking(ev, false /* updateLocationOffset */);
- return;
- }
- mTrackingStarted = false;
- mDownPos.set(ev.getX(), ev.getY());
- } else if (!mTrackingStarted) {
- switch (action) {
- case ACTION_CANCEL:
- case ACTION_UP:
- startTouchTracking(ev, true /* updateLocationOffset */);
- break;
- case ACTION_MOVE: {
- float displacement = mActivity.getDeviceProfile().isLandscape ?
- ev.getX() - mDownPos.x : ev.getY() - mDownPos.y;
- if (Math.abs(displacement) >= mTouchSlop) {
- // Start tracking only when mTouchSlop is crossed.
- startTouchTracking(ev, true /* updateLocationOffset */);
- }
- }
- }
- }
-
- if (mTrackingStarted) {
- sendEvent(ev);
- }
-
- if (action == ACTION_UP || action == ACTION_CANCEL) {
- mInvalidated = true;
- }
- }
-
- private void startTouchTracking(MotionEvent ev, boolean updateLocationOffset) {
- if (updateLocationOffset) {
- mTarget.getLocationOnScreen(mLocationOnScreen);
- }
-
- // Send down touch event
- MotionEvent down = MotionEvent.obtainNoHistory(ev);
- down.setAction(ACTION_DOWN);
- sendEvent(down);
-
- mTrackingStarted = true;
- // Send pointer down for remaining pointers.
- int pointerCount = ev.getPointerCount();
- for (int i = 1; i < pointerCount; i++) {
- down.setAction(ACTION_POINTER_DOWN | (i << ACTION_POINTER_INDEX_SHIFT));
- sendEvent(down);
- }
-
- down.recycle();
- }
-
- private void sendEvent(MotionEvent ev) {
- if (!mTarget.verifyTouchDispatch(this, ev)) {
- mInvalidated = true;
- return;
- }
- int flags = ev.getEdgeFlags();
- ev.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
- ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
- if (!mTrackingStarted) {
- mTarget.onInterceptTouchEvent(ev);
- }
- mTarget.onTouchEvent(ev);
- ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
- ev.setEdgeFlags(flags);
- }
-
- @Override
- public void onQuickStep(MotionEvent ev) {
- if (mInvalidated) {
- return;
- }
- OverviewCallbacks.get(mActivity).closeAllWindows();
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
- mTouchInteractionLog.startQuickStep();
- }
-
- @Override
- public void onQuickScrubStart() {
- if (mInvalidated) {
- return;
- }
- mTouchInteractionLog.startQuickScrub();
- if (!mQuickScrubController.prepareQuickScrub(TAG)) {
- mInvalidated = true;
- mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
- return;
- }
- OverviewCallbacks.get(mActivity).closeAllWindows();
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-
- mStartPending = true;
- Runnable action = () -> {
- if (!mQuickScrubController.prepareQuickScrub(TAG)) {
- mInvalidated = true;
- mTouchInteractionLog.endQuickScrub("onQuickScrubStart");
- return;
- }
- mActivityHelper.onQuickInteractionStart(mActivity, null, true,
- mTouchInteractionLog);
- mQuickScrubController.onQuickScrubProgress(mLastProgress);
- mStartPending = false;
-
- if (mEndPending) {
- mQuickScrubController.onQuickScrubEnd();
- mEndPending = false;
- }
- };
-
- if (mWaitForWindowAvailable) {
- mActivityHelper.executeOnWindowAvailable(mActivity, action);
- } else {
- action.run();
- }
- }
-
- @Override
- public void onQuickScrubEnd() {
- mTouchInteractionLog.endQuickScrub("onQuickScrubEnd");
- if (mInvalidated) {
- return;
- }
- if (mStartPending) {
- mEndPending = true;
- } else {
- mQuickScrubController.onQuickScrubEnd();
- }
- }
-
- @Override
- public void onQuickScrubProgress(float progress) {
- mTouchInteractionLog.setQuickScrubProgress(progress);
- mLastProgress = progress;
- if (mInvalidated || mStartPending) {
- return;
- }
- mQuickScrubController.onQuickScrubProgress(progress);
- }
-
- public static TouchConsumer newInstance(ActivityControlHelper activityHelper,
- boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog) {
- return newInstance(activityHelper, startingInActivityBounds, touchInteractionLog,
- true /* waitForWindowAvailable */);
- }
-
- public static TouchConsumer newInstance(ActivityControlHelper activityHelper,
- boolean startingInActivityBounds, TouchInteractionLog touchInteractionLog,
- boolean waitForWindowAvailable) {
- BaseDraggingActivity activity = activityHelper.getCreatedActivity();
- if (activity == null) {
- return TouchConsumer.NO_OP;
- }
- return new OverviewTouchConsumer(activityHelper, activity, startingInActivityBounds,
- touchInteractionLog, waitForWindowAvailable);
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 0e9ddee..b0f055c 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -34,6 +34,7 @@
import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_FROM_APP_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
+import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK;
@@ -94,9 +95,10 @@
import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
-import com.android.quickstep.TouchInteractionService.OverviewTouchConsumer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
import com.android.quickstep.util.TransformedRect;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -113,7 +115,8 @@
import java.util.function.BiFunction;
@TargetApi(Build.VERSION_CODES.O)
-public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
+public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
+ implements SwipeAnimationListener {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
// Launcher UI related states
@@ -248,14 +251,8 @@
// To avoid UI jump when gesture is started, we offset the animation by the threshold.
private float mShiftAtGestureStart = 0;
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ private final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler();
- // An increasing identifier per single instance of OtherActivityTouchConsumer. Generally one
- // instance of OtherActivityTouchConsumer will only have one swipe handle, but sometimes we can
- // end up with multiple handlers if we get recents command in the middle of a swipe gesture.
- // This is used to match the corresponding activity manager callbacks in
- // OtherActivityTouchConsumer
- public final int id;
private final Context mContext;
private final ActivityControlHelper<T> mActivityControlHelper;
private final ActivityInitListener mActivityInitListener;
@@ -296,10 +293,9 @@
private Bundle mAssistData;
- WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context,
+ WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context,
long touchTimeMs, ActivityControlHelper<T> controller, boolean continuingLastGesture,
InputConsumerController inputConsumer, TouchInteractionLog touchInteractionLog) {
- this.id = id;
mContext = context;
mRunningTaskInfo = runningTaskInfo;
mRunningTaskId = runningTaskInfo.id;
@@ -703,7 +699,9 @@
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- if (mRecentsAnimationWrapper.getController() != null && mLayoutListener != null) {
+ if (mRecentsAnimationWrapper.getController() != null && mLayoutListener != null &&
+ (mInteractionType == INTERACTION_NORMAL
+ || !mQuickScrubController.hasFinishedTransitionToQuickScrub())) {
mLayoutListener.open();
mLayoutListener.update(mCurrentShift.value > 1, mLongSwipeMode,
mClipAnimationHelper.getCurrentRectWithInsets(),
@@ -747,19 +745,18 @@
? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart));
}
- @UiThread
- public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
+ @Override
+ public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
- RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
+ RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
- if (minimizedHomeBounds != null && runningTaskTarget != null) {
+ if (targetSet.minimizedHomeBounds != null && runningTaskTarget != null) {
overviewStackBounds = mActivityControlHelper
- .getOverviewWindowBounds(minimizedHomeBounds, runningTaskTarget);
- dp = dp.getMultiWindowProfile(mContext,
- new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
- dp.updateInsets(homeContentInsets);
+ .getOverviewWindowBounds(targetSet.minimizedHomeBounds, runningTaskTarget);
+ dp = dp.getMultiWindowProfile(mContext, new Point(
+ targetSet.minimizedHomeBounds.width(), targetSet.minimizedHomeBounds.height()));
+ dp.updateInsets(targetSet.homeContentInsets);
} else {
if (mActivity != null) {
int loc[] = new int[2];
@@ -772,7 +769,7 @@
}
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
- dp.updateInsets(homeContentInsets);
+ dp.updateInsets(targetSet.homeContentInsets);
}
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
@@ -782,14 +779,14 @@
mClipAnimationHelper.prepareAnimation(false /* isOpening */);
initTransitionEndpoints(dp);
- mRecentsAnimationWrapper.setController(controller, targets);
- mTouchInteractionLog.startRecentsAnimationCallback(targets.apps.length);
+ mRecentsAnimationWrapper.setController(targetSet.controller, targetSet);
+ mTouchInteractionLog.startRecentsAnimationCallback(targetSet.apps.length);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
mPassedOverviewThreshold = false;
}
- @UiThread
+ @Override
public void onRecentsAnimationCanceled() {
mRecentsAnimationWrapper.setController(null, null);
mActivityInitListener.unregister();
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java b/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java
new file mode 100644
index 0000000..686e74d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RecentsAnimationListenerSet.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util;
+
+import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
+
+import android.graphics.Rect;
+import android.util.ArraySet;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.util.Set;
+
+import androidx.annotation.UiThread;
+
+/**
+ * Wrapper around {@link RecentsAnimationListener} which delegates callbacks to multiple listeners
+ * on the main thread
+ */
+public class RecentsAnimationListenerSet implements RecentsAnimationListener {
+
+ private final Set<SwipeAnimationListener> mListeners = new ArraySet<>();
+
+ @UiThread
+ public void addListener(SwipeAnimationListener listener) {
+ Preconditions.assertUIThread();
+ mListeners.add(listener);
+ }
+
+ @UiThread
+ public void removeListener(SwipeAnimationListener listener) {
+ Preconditions.assertUIThread();
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public final void onAnimationStart(RecentsAnimationControllerCompat controller,
+ RemoteAnimationTargetCompat[] targets, Rect homeContentInsets,
+ Rect minimizedHomeBounds) {
+ SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, targets,
+ homeContentInsets, minimizedHomeBounds);
+ Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> {
+ for (SwipeAnimationListener listener : getListeners()) {
+ listener.onRecentsAnimationStart(targetSet);
+ }
+ });
+ }
+
+ @Override
+ public final void onAnimationCanceled() {
+ Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> {
+ for (SwipeAnimationListener listener : getListeners()) {
+ listener.onRecentsAnimationCanceled();
+ }
+ });
+ }
+
+ private SwipeAnimationListener[] getListeners() {
+ return mListeners.toArray(new SwipeAnimationListener[mListeners.size()]);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
new file mode 100644
index 0000000..4f02acf
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util;
+
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.graphics.Rect;
+
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+/**
+ * Extension of {@link RemoteAnimationTargetSet} with additional information about swipe
+ * up animation
+ */
+public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
+
+ public final RecentsAnimationControllerCompat controller;
+ public final Rect homeContentInsets;
+ public final Rect minimizedHomeBounds;
+
+ public SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller,
+ RemoteAnimationTargetCompat[] targets, Rect homeContentInsets,
+ Rect minimizedHomeBounds) {
+ super(targets, MODE_CLOSING);
+ this.controller = controller;
+ this.homeContentInsets = homeContentInsets;
+ this.minimizedHomeBounds = minimizedHomeBounds;
+ }
+
+
+ public interface SwipeAnimationListener {
+
+ void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet);
+
+ void onRecentsAnimationCanceled();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index bbcd425..cbd6b2f 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -78,6 +78,12 @@
public void initialize(Task task, InitializeCallback callback) {
mTask = task;
+
+ if (task.key.userId != UserHandle.myUserId()) {
+ callback.call(1, task.titleDescription);
+ return;
+ }
+
Utilities.THREAD_POOL_EXECUTOR.execute(() -> {
long appUsageLimitTimeMs = -1;
long appRemainingTimeMs = -1;
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 5c8f53c..ba4aadc 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -216,7 +216,11 @@
int offsetY = (int) (mTaskHeight * taskView.getScaleY() * getScaleY()
- mTempRect.height());
if (((mCurrentPage != 0) || mightNeedToRefill) && offsetX > 0) {
- mTempRect.right += offsetX;
+ if (mTempRect.left - offsetX < 0) {
+ mTempRect.left -= offsetX;
+ } else {
+ mTempRect.right += offsetX;
+ }
}
if (mightNeedToRefill && offsetY > 0) {
mTempRect.top -= offsetY;
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 7cab18d..e75527e 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -133,9 +133,6 @@
return mIsOpen;
}
- protected void onWidgetsBound() {
- }
-
protected abstract boolean isOfType(@FloatingViewType int type);
/** @return Whether the back is consumed. If false, Launcher will handle the back as well. */
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 73fba4e..cf16759 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -145,7 +145,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.function.Predicate;
import androidx.annotation.Nullable;
@@ -260,7 +259,7 @@
private final Handler mHandler = new Handler();
- private final Runnable mLogOnDelayedResume = this::logOnDelayedResume;
+ private final Runnable mHandleDeferredResume = this::handleDeferredResume;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -783,11 +782,13 @@
RaceConditionTracker.onEvent(ON_START_EVT, EXIT);
}
- private void logOnDelayedResume() {
+ private void handleDeferredResume() {
if (hasBeenResumed()) {
getUserEventDispatcher().logActionCommand(Action.Command.RESUME,
mStateManager.getState().containerType, -1);
getUserEventDispatcher().startSession();
+
+ UiFactory.onLauncherStateOrResumeChanged(this);
}
}
@@ -798,8 +799,8 @@
super.onResume();
TraceHelper.partitionSection("ON_RESUME", "superCall");
- mHandler.removeCallbacks(mLogOnDelayedResume);
- Utilities.postAsyncCallback(mHandler, mLogOnDelayedResume);
+ mHandler.removeCallbacks(mHandleDeferredResume);
+ Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
setOnResumeCallback(null);
// Process any items that were added while Launcher was away.
@@ -813,7 +814,6 @@
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
- UiFactory.onLauncherStateOrResumeChanged(this);
TraceHelper.endSection("ON_RESUME");
RaceConditionTracker.onEvent(ON_RESUME_EVT, EXIT);
@@ -1122,11 +1122,6 @@
public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
mWorkspace.updateNotificationDots(updatedDots);
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
-
- PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this);
- if (popup != null) {
- popup.updateNotificationHeader(updatedDots);
- }
}
@Override
@@ -2247,10 +2242,6 @@
@Override
public void bindAllWidgets(final ArrayList<WidgetListRowEntry> allWidgets) {
mPopupDataProvider.setAllWidgets(allWidgets);
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
- if (topView != null) {
- topView.onWidgetsBound();
- }
}
/**
diff --git a/src/com/android/launcher3/dot/DotInfo.java b/src/com/android/launcher3/dot/DotInfo.java
index 15b2a3b..4ff0539 100644
--- a/src/com/android/launcher3/dot/DotInfo.java
+++ b/src/com/android/launcher3/dot/DotInfo.java
@@ -18,7 +18,6 @@
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationKeyData;
-import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.List;
@@ -30,14 +29,11 @@
public static final int MAX_COUNT = 999;
- /** Used to link this DotInfo to icons on the workspace and all apps */
- private PackageUserKey mPackageUserKey;
-
/**
* The keys of the notifications that this dot represents. These keys can later be
* used to retrieve {@link NotificationInfo}'s.
*/
- private List<NotificationKeyData> mNotificationKeys;
+ private final List<NotificationKeyData> mNotificationKeys = new ArrayList<>();
/**
* The current sum of the counts in {@link #mNotificationKeys},
@@ -45,11 +41,6 @@
*/
private int mTotalCount;
- public DotInfo(PackageUserKey packageUserKey) {
- mPackageUserKey = packageUserKey;
- mNotificationKeys = new ArrayList<>();
- }
-
/**
* Returns whether the notification was added or its count changed.
*/
diff --git a/src/com/android/launcher3/dot/FolderDotInfo.java b/src/com/android/launcher3/dot/FolderDotInfo.java
index b5eb8cd..54800a0 100644
--- a/src/com/android/launcher3/dot/FolderDotInfo.java
+++ b/src/com/android/launcher3/dot/FolderDotInfo.java
@@ -30,10 +30,6 @@
private int mNumNotifications;
- public FolderDotInfo() {
- super(null);
- }
-
public void addDotInfo(DotInfo dotToAdd) {
if (dotToAdd == null) {
return;
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 9b23f3f..b0af4c6 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -61,6 +61,7 @@
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
import com.android.launcher3.notification.NotificationKeyData;
+import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
@@ -72,7 +73,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Predicate;
/**
@@ -80,7 +80,7 @@
*/
public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
DragController.DragListener, View.OnLongClickListener,
- View.OnTouchListener {
+ View.OnTouchListener, PopupDataChangeListener {
private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
@@ -115,6 +115,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mLauncher.getPopupDataProvider().setChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLauncher.getPopupDataProvider().setChangeListener(null);
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mInterceptTouchDown.set(ev.getX(), ev.getY());
@@ -352,7 +364,7 @@
}
@Override
- protected void onWidgetsBound() {
+ public void onWidgetsBound() {
ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
SystemShortcut widgetInfo = new SystemShortcut.Widgets();
View.OnClickListener onClickListener = widgetInfo.getOnClickListener(mLauncher, itemInfo);
@@ -464,7 +476,8 @@
/**
* Updates the notification header if the original icon's dot updated.
*/
- public void updateNotificationHeader(Predicate<PackageUserKey> updatedDots) {
+ @Override
+ public void onNotificationDotsUpdated(Predicate<PackageUserKey> updatedDots) {
ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
PackageUserKey packageUser = PackageUserKey.fromItemInfo(itemInfo);
if (updatedDots.test(packageUser)) {
@@ -481,6 +494,7 @@
}
}
+ @Override
public void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
if (mNotificationItemView == null) {
return;
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f4da858..2d301ac 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -22,7 +22,6 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.Utilities;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.notification.NotificationKeyData;
@@ -38,6 +37,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
import androidx.annotation.NonNull;
@@ -58,10 +58,17 @@
/** Maps packages to their Widgets */
private ArrayList<WidgetListRowEntry> mAllWidgets = new ArrayList<>();
+ private PopupDataChangeListener mChangeListener = PopupDataChangeListener.INSTANCE;
+
public PopupDataProvider(Launcher launcher) {
mLauncher = launcher;
}
+ private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
+ mLauncher.updateNotificationDots(updatedDots);
+ mChangeListener.onNotificationDotsUpdated(updatedDots);
+ }
+
@Override
public void onNotificationPosted(PackageUserKey postedPackageUserKey,
NotificationKeyData notificationKey, boolean shouldBeFilteredOut) {
@@ -69,7 +76,7 @@
boolean dotShouldBeRefreshed;
if (dotInfo == null) {
if (!shouldBeFilteredOut) {
- DotInfo newDotInfo = new DotInfo(postedPackageUserKey);
+ DotInfo newDotInfo = new DotInfo();
newDotInfo.addOrUpdateNotificationKey(notificationKey);
mPackageUserToDotInfos.put(postedPackageUserKey, newDotInfo);
dotShouldBeRefreshed = true;
@@ -85,7 +92,7 @@
}
}
if (dotShouldBeRefreshed) {
- mLauncher.updateNotificationDots(t -> postedPackageUserKey.equals(t));
+ updateNotificationDots(t -> postedPackageUserKey.equals(t));
}
}
@@ -97,7 +104,7 @@
if (oldDotInfo.getNotificationKeys().size() == 0) {
mPackageUserToDotInfos.remove(removedPackageUserKey);
}
- mLauncher.updateNotificationDots(t -> removedPackageUserKey.equals(t));
+ updateNotificationDots(t -> removedPackageUserKey.equals(t));
trimNotifications(mPackageUserToDotInfos);
}
}
@@ -112,7 +119,7 @@
PackageUserKey packageUserKey = PackageUserKey.fromNotification(notification);
DotInfo dotInfo = mPackageUserToDotInfos.get(packageUserKey);
if (dotInfo == null) {
- dotInfo = new DotInfo(packageUserKey);
+ dotInfo = new DotInfo();
mPackageUserToDotInfos.put(packageUserKey, dotInfo);
}
dotInfo.addOrUpdateNotificationKey(NotificationKeyData.fromNotification(notification));
@@ -133,16 +140,13 @@
}
if (!updatedDots.isEmpty()) {
- mLauncher.updateNotificationDots(updatedDots::containsKey);
+ updateNotificationDots(updatedDots::containsKey);
}
trimNotifications(updatedDots);
}
private void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
- PopupContainerWithArrow openContainer = PopupContainerWithArrow.getOpen(mLauncher);
- if (openContainer != null) {
- openContainer.trimNotifications(updatedDots);
- }
+ mChangeListener.trimNotifications(updatedDots);
}
public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
@@ -194,6 +198,11 @@
public void setAllWidgets(ArrayList<WidgetListRowEntry> allWidgets) {
mAllWidgets = allWidgets;
+ mChangeListener.onWidgetsBound();
+ }
+
+ public void setChangeListener(PopupDataChangeListener listener) {
+ mChangeListener = listener == null ? PopupDataChangeListener.INSTANCE : listener;
}
public ArrayList<WidgetListRowEntry> getAllWidgets() {
@@ -216,4 +225,15 @@
}
return null;
}
+
+ public interface PopupDataChangeListener {
+
+ PopupDataChangeListener INSTANCE = new PopupDataChangeListener() { };
+
+ default void onNotificationDotsUpdated(Predicate<PackageUserKey> updatedDots) { }
+
+ default void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) { }
+
+ default void onWidgetsBound() { }
+ }
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 508695b..df82661 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -34,6 +34,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -47,7 +48,8 @@
* Base class for various widgets popup
*/
abstract class BaseWidgetSheet extends AbstractSlideInView
- implements OnClickListener, OnLongClickListener, DragSource {
+ implements OnClickListener, OnLongClickListener, DragSource,
+ PopupDataProvider.PopupDataChangeListener {
/* Touch handling related member variables. */
@@ -61,6 +63,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mLauncher.getPopupDataProvider().setChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLauncher.getPopupDataProvider().setChangeListener(null);
+ }
+
+ @Override
public final void onClick(View v) {
// Let the user know that they have to long press to add a widget
if (mWidgetInstructionToast != null) {
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 4bd6234..05368fa 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -76,7 +76,7 @@
}
@Override
- protected void onWidgetsBound() {
+ public void onWidgetsBound() {
List<WidgetItem> widgets = mLauncher.getPopupDataProvider().getWidgetsForPackageUser(
new PackageUserKey(
mOriginalItemInfo.getTargetComponent().getPackageName(),
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index 1112686..ec06d1e 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -155,7 +155,7 @@
}
@Override
- protected void onWidgetsBound() {
+ public void onWidgetsBound() {
mAdapter.setWidgets(mLauncher.getPopupDataProvider().getAllWidgets());
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index b050993..6b76012 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -266,6 +266,16 @@
event -> true,
"Pressing Home didn't produce any events");
mDevice.waitForIdle();
+
+ // Temporarily press home twice as the first click sometimes gets ignored (b/124239413)
+ executeAndWaitForEvent(
+ () -> {
+ log("LauncherInstrumentation.pressHome before clicking");
+ getSystemUiObject("home").click();
+ },
+ event -> true,
+ "Pressing Home didn't produce any events");
+ mDevice.waitForIdle();
return getWorkspace();
}
@@ -350,7 +360,7 @@
return new AllAppsFromOverview(this);
}
- private void waitUntilGone(String resId) {
+ void waitUntilGone(String resId) {
assertTrue("Unexpected launcher object visible: " + resId,
mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
WAIT_TIME_MS));
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index f055c0c..587c712 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -116,6 +116,7 @@
final Point dest = new Point(
mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
app.getObject().drag(dest, ICON_DRAG_SPEED);
+ mLauncher.waitUntilGone("drop_target_bar");
verifyActiveContainer();
}