Merge "Ensuring that we finish the last transition before starting a new one." into ub-launcher3-master
This commit is contained in:
commit
7eee62b313
|
@ -77,6 +77,12 @@ public class AnimatedFloat {
|
|||
}
|
||||
}
|
||||
|
||||
public void finishAnimation() {
|
||||
if (mValueAnimator != null && mValueAnimator.isRunning()) {
|
||||
mValueAnimator.end();
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectAnimator getCurrentAnimation() {
|
||||
return mValueAnimator;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.android.quickstep.TouchConsumer.InteractionType;
|
|||
public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
protected boolean mIsGoingToHome;
|
||||
|
||||
public void setGestureEndCallback(Runnable gestureEndCallback) {
|
||||
mGestureEndCallback = gestureEndCallback;
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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 android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.view.Choreographer;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
|
||||
/**
|
||||
* A TouchConsumer which defers all events on the UIThread until the consumer is created.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class DeferredTouchConsumer implements TouchConsumer {
|
||||
|
||||
private final VelocityTracker mVelocityTracker;
|
||||
private final DeferredTouchProvider mTouchProvider;
|
||||
|
||||
private MotionEventQueue mMyQueue;
|
||||
private TouchConsumer mTarget;
|
||||
|
||||
public DeferredTouchConsumer(DeferredTouchProvider touchProvider) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mTouchProvider = touchProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MotionEvent event) {
|
||||
mTarget.accept(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mTarget.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTouchTracking(int interactionType) {
|
||||
mTarget.updateTouchTracking(interactionType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuickScrubEnd() {
|
||||
mTarget.onQuickScrubEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuickScrubProgress(float progress) {
|
||||
mTarget.onQuickScrubProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcessMotionEvent(MotionEvent ev) {
|
||||
mVelocityTracker.addMovement(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
|
||||
mMyQueue = queue;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deferInit() {
|
||||
mTarget = mTouchProvider.createTouchConsumer(mVelocityTracker);
|
||||
mTarget.getIntrimChoreographer(mMyQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean forceToLauncherConsumer() {
|
||||
return mTarget.forceToLauncherConsumer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deferNextEventToMainThread() {
|
||||
// If our target is still null, defer the next target as well
|
||||
TouchConsumer target = mTarget;
|
||||
return target == null ? true : target.deferNextEventToMainThread();
|
||||
}
|
||||
|
||||
public interface DeferredTouchProvider {
|
||||
|
||||
TouchConsumer createTouchConsumer(VelocityTracker tracker);
|
||||
}
|
||||
}
|
|
@ -53,6 +53,8 @@ public class MotionEventQueue {
|
|||
ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
|
||||
private static final int ACTION_RESET =
|
||||
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
|
||||
private static final int ACTION_DEFER_INIT =
|
||||
ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
|
||||
|
||||
private final EventArray mEmptyArray = new EventArray();
|
||||
private final Object mExecutionLock = new Object();
|
||||
|
@ -76,10 +78,10 @@ public class MotionEventQueue {
|
|||
public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
|
||||
mMainChoreographer = choreographer;
|
||||
mConsumer = consumer;
|
||||
|
||||
mCurrentChoreographer = mMainChoreographer;
|
||||
mCurrentRunnable = mMainFrameCallback;
|
||||
setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
|
||||
|
||||
setInterimChoreographer(consumer.getIntrimChoreographer(this));
|
||||
}
|
||||
|
||||
public void setInterimChoreographer(Choreographer choreographer) {
|
||||
|
@ -156,6 +158,9 @@ public class MotionEventQueue {
|
|||
case ACTION_RESET:
|
||||
mConsumer.reset();
|
||||
break;
|
||||
case ACTION_DEFER_INIT:
|
||||
mConsumer.deferInit();
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid virtual event: " + event.getAction());
|
||||
}
|
||||
|
@ -204,6 +209,14 @@ public class MotionEventQueue {
|
|||
queueVirtualAction(ACTION_RESET, 0);
|
||||
}
|
||||
|
||||
public void deferInit() {
|
||||
queueVirtualAction(ACTION_DEFER_INIT, 0);
|
||||
}
|
||||
|
||||
public TouchConsumer getConsumer() {
|
||||
return mConsumer;
|
||||
}
|
||||
|
||||
private static class EventArray extends ArrayList<MotionEvent> {
|
||||
|
||||
public int lastEventAction = ACTION_CANCEL;
|
||||
|
|
|
@ -319,13 +319,14 @@ public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler i
|
|||
|
||||
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
|
||||
private void animateToProgress(float progress, long duration) {
|
||||
mIsGoingToHome = Float.compare(progress, 1) == 0;
|
||||
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
|
||||
anim.setInterpolator(Interpolators.SCROLL);
|
||||
anim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
|
||||
? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
|
||||
mStateCallback.setState(mIsGoingToHome
|
||||
? STATE_SCALED_SNAPSHOT_RECENTS : STATE_SCALED_SNAPSHOT_APP);
|
||||
}
|
||||
});
|
||||
anim.start();
|
||||
|
|
|
@ -25,9 +25,9 @@ import static android.view.MotionEvent.INVALID_POINTER_ID;
|
|||
import static com.android.quickstep.RemoteRunnable.executeSafely;
|
||||
import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
|
||||
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
|
||||
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
|
||||
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
|
@ -39,6 +39,7 @@ import android.graphics.Color;
|
|||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
@ -70,6 +71,7 @@ import java.util.concurrent.TimeUnit;
|
|||
/**
|
||||
* Touch consumer for handling events originating from an activity other than Launcher
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
|
||||
private static final String TAG = "ActivityTouchConsumer";
|
||||
|
||||
|
@ -97,16 +99,17 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
|
|||
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private MotionEventQueue mEventQueue;
|
||||
private boolean mIsGoingToHome;
|
||||
|
||||
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
|
||||
RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
|
||||
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
|
||||
@HitTarget int downHitTarget) {
|
||||
@HitTarget int downHitTarget, VelocityTracker velocityTracker) {
|
||||
super(base);
|
||||
mRunningTask = runningTaskInfo;
|
||||
mRecentsModel = recentsModel;
|
||||
mHomeIntent = homeIntent;
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
mVelocityTracker = velocityTracker;
|
||||
mISystemUiProxy = systemUiProxy;
|
||||
mMainThreadExecutor = mainThreadExecutor;
|
||||
mBackgroundThreadChoreographer = backgroundThreadChoreographer;
|
||||
|
@ -374,6 +377,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
|
|||
if (mInteractionHandler != null) {
|
||||
final BaseSwipeInteractionHandler handler = mInteractionHandler;
|
||||
mInteractionHandler = null;
|
||||
mIsGoingToHome = handler.mIsGoingToHome;
|
||||
mMainThreadExecutor.execute(handler::reset);
|
||||
}
|
||||
}
|
||||
|
@ -428,4 +432,15 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean forceToLauncherConsumer() {
|
||||
return mIsGoingToHome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deferNextEventToMainThread() {
|
||||
// TODO: Consider also check if the eventQueue is using mainThread of not.
|
||||
return mInteractionHandler != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ import android.support.annotation.IntDef;
|
|||
import android.view.Choreographer;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -64,4 +62,14 @@ public interface TouchConsumer extends Consumer<MotionEvent> {
|
|||
default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void deferInit() { }
|
||||
|
||||
default boolean deferNextEventToMainThread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean forceToLauncherConsumer() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import android.util.Log;
|
|||
import android.util.SparseArray;
|
||||
import android.view.Choreographer;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
|
@ -161,7 +162,6 @@ public class TouchInteractionService extends Service {
|
|||
|
||||
private Choreographer mMainThreadChoreographer;
|
||||
private Choreographer mBackgroundThreadChoreographer;
|
||||
private MotionEventQueue mNoOpEventQueue;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
@ -171,8 +171,7 @@ public class TouchInteractionService extends Service {
|
|||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mOverviewCommandHelper = new OverviewCommandHelper(this);
|
||||
mMainThreadChoreographer = Choreographer.getInstance();
|
||||
mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
|
||||
mEventQueue = mNoOpEventQueue;
|
||||
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
|
||||
|
||||
sConnected = true;
|
||||
|
||||
|
@ -194,31 +193,45 @@ public class TouchInteractionService extends Service {
|
|||
}
|
||||
|
||||
private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
|
||||
mEventQueue.reset();
|
||||
TouchConsumer oldConsumer = mEventQueue.getConsumer();
|
||||
if (oldConsumer.deferNextEventToMainThread()) {
|
||||
mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
|
||||
new DeferredTouchConsumer((v) -> getCurrentTouchConsumer(downHitTarget,
|
||||
oldConsumer.forceToLauncherConsumer(), v)));
|
||||
mEventQueue.deferInit();
|
||||
} else {
|
||||
mEventQueue = new MotionEventQueue(
|
||||
mMainThreadChoreographer, getCurrentTouchConsumer(downHitTarget, false, null));
|
||||
}
|
||||
}
|
||||
|
||||
private TouchConsumer getCurrentTouchConsumer(
|
||||
@HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) {
|
||||
RunningTaskInfo runningTaskInfo = mAM.getRunningTask();
|
||||
|
||||
mEventQueue.reset();
|
||||
|
||||
if (runningTaskInfo == null) {
|
||||
mEventQueue = mNoOpEventQueue;
|
||||
} else if (runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
|
||||
mEventQueue = getLauncherEventQueue();
|
||||
if (runningTaskInfo == null && !forceToLauncher) {
|
||||
return mNoOpTouchConsumer;
|
||||
} else if (forceToLauncher ||
|
||||
runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
|
||||
return getLauncherConsumer();
|
||||
} else {
|
||||
mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
|
||||
new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
|
||||
if (tracker == null) {
|
||||
tracker = VelocityTracker.obtain();
|
||||
}
|
||||
return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
|
||||
mOverviewCommandHelper.homeIntent, mISystemUiProxy, mMainThreadExecutor,
|
||||
mBackgroundThreadChoreographer, downHitTarget));
|
||||
mBackgroundThreadChoreographer, downHitTarget, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
private MotionEventQueue getLauncherEventQueue() {
|
||||
private TouchConsumer getLauncherConsumer() {
|
||||
Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
|
||||
if (launcher == null) {
|
||||
return mNoOpEventQueue;
|
||||
return mNoOpTouchConsumer;
|
||||
}
|
||||
|
||||
View target = launcher.getDragLayer();
|
||||
return new MotionEventQueue(mMainThreadChoreographer,
|
||||
new LauncherTouchConsumer(launcher, target));
|
||||
return new LauncherTouchConsumer(launcher, target);
|
||||
}
|
||||
|
||||
private static class LauncherTouchConsumer implements TouchConsumer {
|
||||
|
|
|
@ -725,13 +725,14 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
|
|||
|
||||
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
|
||||
private void animateToProgress(float progress, long duration) {
|
||||
mIsGoingToHome = Float.compare(progress, 1) == 0;
|
||||
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
|
||||
anim.setInterpolator(Interpolators.SCROLL);
|
||||
anim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
|
||||
? STATE_SCALED_CONTROLLER_APP : STATE_SCALED_CONTROLLER_RECENTS);
|
||||
setStateOnUiThread(mIsGoingToHome ?
|
||||
STATE_SCALED_CONTROLLER_RECENTS : STATE_SCALED_CONTROLLER_APP);
|
||||
}
|
||||
});
|
||||
anim.start();
|
||||
|
@ -752,7 +753,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
|
|||
}
|
||||
|
||||
private void invalidateHandler() {
|
||||
mCurrentShift.cancelAnimation();
|
||||
mCurrentShift.finishAnimation();
|
||||
|
||||
if (mGestureEndCallback != null) {
|
||||
mGestureEndCallback.run();
|
||||
|
|
|
@ -333,6 +333,10 @@ public class LauncherStateManager {
|
|||
}
|
||||
|
||||
public void moveToRestState() {
|
||||
if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
|
||||
// The user is doing something. Lets not mess it up
|
||||
return;
|
||||
}
|
||||
if (mState.disableRestore) {
|
||||
goToState(getRestState());
|
||||
// Reset history
|
||||
|
|
Loading…
Reference in New Issue