Handling swipe up on a third-party launcher

Bug: 78125098
Change-Id: Iba4247987825bf9ce16d3494200bfea889c931e2
This commit is contained in:
Sunny Goyal
2018-04-17 17:12:08 -07:00
parent d39b8755b5
commit 6dedc222be
7 changed files with 153 additions and 112 deletions
@@ -27,7 +27,6 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.view.View;
@@ -40,15 +39,16 @@ import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ViewOnDrawExecutor;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.views.LauncherLayoutListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
/**
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
@@ -67,19 +67,14 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
void executeOnWindowAvailable(T activity, Runnable action);
void executeOnNextDraw(T activity, TaskView targetView, Runnable action);
void onTransitionCancelled(T activity, boolean activityVisible);
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
void onSwipeUpComplete(T activity);
void prepareRecentsUI(T activity, boolean activityVisible);
AnimatorPlaybackController createControllerForVisibleActivity(T activity);
AnimatorPlaybackController createControllerForHiddenActivity(T activity, int transitionLength);
AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
Consumer<AnimatorPlaybackController> callback);
ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
@@ -130,20 +125,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
}
@Override
public void executeOnNextDraw(Launcher activity, TaskView targetView, Runnable action) {
ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
@Override
public void onViewDetachedFromWindow(View v) {
if (!isCompleted()) {
runAllTasks();
}
}
};
executor.attachTo(activity, targetView, false /* waitForLoadAnimation */);
executor.execute(action);
}
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect);
@@ -169,7 +150,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
@Override
public void prepareRecentsUI(Launcher activity, boolean activityVisible) {
public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
Consumer<AnimatorPlaybackController> callback) {
LauncherState startState = activity.getStateManager().getState();
if (startState.disableRestore) {
startState = activity.getStateManager().getRestState();
@@ -185,37 +167,41 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
// Optimization, hide the all apps view to prevent layout while initializing
activity.getAppsView().getContentView().setVisibility(View.GONE);
}
return (transitionLength) ->
createActivityController(activity, activityVisible, transitionLength, callback);
}
@Override
public AnimatorPlaybackController createControllerForVisibleActivity(Launcher activity) {
DeviceProfile dp = activity.getDeviceProfile();
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
return activity.getStateManager().createAnimationToNewWorkspace(OVERVIEW, accuracy);
}
private void createActivityController(Launcher activity, boolean wasVisible,
long transitionLength, Consumer<AnimatorPlaybackController> callback) {
if (wasVisible) {
DeviceProfile dp = activity.getDeviceProfile();
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
callback.accept(activity.getStateManager()
.createAnimationToNewWorkspace(OVERVIEW, accuracy));
return;
}
if (activity.getDeviceProfile().isVerticalBarLayout()) {
return;
}
@Override
public AnimatorPlaybackController createControllerForHiddenActivity(
Launcher activity, int transitionLength) {
AllAppsTransitionController controller = activity.getAllAppsController();
AnimatorSet anim = new AnimatorSet();
if (activity.getDeviceProfile().isVerticalBarLayout()) {
// TODO:
} else {
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
float endProgress = OVERVIEW.getVerticalProgress(activity);
float startProgress = endProgress + progressDelta;
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
controller, ALL_APPS_PROGRESS, startProgress, endProgress);
shiftAnim.setInterpolator(LINEAR);
anim.play(shiftAnim);
}
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
float endProgress = OVERVIEW.getVerticalProgress(activity);
float startProgress = endProgress + progressDelta;
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
controller, ALL_APPS_PROGRESS, startProgress, endProgress);
shiftAnim.setInterpolator(LINEAR);
anim.play(shiftAnim);
anim.setDuration(transitionLength * 2);
activity.getStateManager().setCurrentAnimation(anim);
return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2));
}
@Override
@@ -294,13 +280,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
action.run();
}
@Override
public void executeOnNextDraw(RecentsActivity activity, TaskView targetView,
Runnable action) {
// TODO:
new Handler(Looper.getMainLooper()).post(action);
}
@Override
public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
// TODO:
@@ -324,23 +303,43 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
@Override
public void prepareRecentsUI(RecentsActivity activity, boolean activityVisible) {
// TODO:
}
public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
Consumer<AnimatorPlaybackController> callback) {
if (activityVisible) {
return (transitionLength) -> { };
}
@Override
public AnimatorPlaybackController createControllerForVisibleActivity(
RecentsActivity activity) {
DeviceProfile dp = activity.getDeviceProfile();
return createControllerForHiddenActivity(activity, Math.max(dp.widthPx, dp.heightPx));
}
RecentsViewContainer rv = activity.getOverviewPanelContainer();
rv.setContentAlpha(0);
@Override
public AnimatorPlaybackController createControllerForHiddenActivity(
RecentsActivity activity, int transitionLength) {
// We do not animate anything. Create a empty controller
AnimatorSet anim = new AnimatorSet();
return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
return new AnimationFactory() {
boolean isAnimatingHome = false;
@Override
public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) {
isAnimatingHome = targets != null && targets.isAnimatingHome();
if (!isAnimatingHome) {
rv.setContentAlpha(1);
}
createActivityController(getSwipeUpDestinationAndLength(
activity.getDeviceProfile(), activity, new Rect()));
}
@Override
public void createActivityController(long transitionLength) {
if (!isAnimatingHome) {
return;
}
ObjectAnimator anim = ObjectAnimator
.ofFloat(rv, RecentsViewContainer.CONTENT_ALPHA, 0, 1);
anim.setDuration(transitionLength).setInterpolator(LINEAR);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(anim);
callback.accept(AnimatorPlaybackController.wrap(animatorSet, transitionLength));
}
};
}
@Override
@@ -423,4 +422,11 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
Context context, Handler handler, long duration);
}
interface AnimationFactory {
default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { }
void createActivityController(long transitionLength);
}
}
@@ -26,6 +26,7 @@ import static com.android.systemui.shared.system.PackageManagerWrapper
.ACTION_PREFERRED_ACTIVITY_CHANGED;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -36,6 +37,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ResolveInfo;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.os.Build;
import android.os.PatternMatcher;
@@ -49,6 +51,7 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.AnimationFactory;
import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper;
import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
import com.android.quickstep.util.ClipAnimationHelper;
@@ -59,6 +62,7 @@ import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
import java.util.ArrayList;
@@ -254,15 +258,17 @@ public class OverviewCommandHelper {
private boolean onActivityReady(T activity, Boolean wasVisible) {
activity.<RecentsView>getOverviewPanel().setCurrentTask(mRunningTaskId);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
mHelper.prepareRecentsUI(activity, wasVisible);
AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible,
(controller) -> {
controller.dispatchOnStart();
ValueAnimator anim = controller.getAnimationPlayer()
.setDuration(RECENTS_LAUNCH_DURATION);
anim.setInterpolator(FAST_OUT_SLOW_IN);
anim.start();
});
factory.onRemoteAnimationReceived(null);
if (wasVisible) {
AnimatorPlaybackController controller =
mHelper.createControllerForVisibleActivity(activity);
controller.dispatchOnStart();
ValueAnimator anim =
controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
anim.setInterpolator(FAST_OUT_SLOW_IN);
anim.start();
factory.createActivityController(RECENTS_LAUNCH_DURATION);
}
mActivity = activity;
return false;
@@ -283,7 +289,6 @@ public class OverviewCommandHelper {
RemoteAnimationTargetSet targetSet =
new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING);
// Use the top closing app to determine the insets for the animation
RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
if (runningTaskTarget == null) {
@@ -313,6 +318,22 @@ public class OverviewCommandHelper {
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
valueAnimator.addUpdateListener((v) ->
clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue()));
if (targetSet.isAnimatingHome()) {
// If we are animating home, fade in the opening targets
RemoteAnimationTargetSet openingSet =
new RemoteAnimationTargetSet(targetCompats, MODE_OPENING);
TransactionCompat transaction = new TransactionCompat();
valueAnimator.addUpdateListener((v) -> {
for (RemoteAnimationTargetCompat app : openingSet.apps) {
transaction.setAlpha(app.leash, (float) v.getAnimatedValue());
transaction.show(app.leash);
}
transaction.setEarlyWakeup();
transaction.apply();
});
}
anim.play(valueAnimator);
return anim;
}
@@ -51,6 +51,7 @@ import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -65,6 +66,7 @@ public class RecentsActivity extends BaseDraggingActivity {
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
private RecentsViewContainer mOverviewPanelContainer;
private Configuration mOldConfig;
@@ -78,6 +80,7 @@ public class RecentsActivity extends BaseDraggingActivity {
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
mRecentsRootView.setup();
@@ -153,6 +156,10 @@ public class RecentsActivity extends BaseDraggingActivity {
return (T) mFallbackRecentsView;
}
public RecentsViewContainer getOverviewPanelContainer() {
return mOverviewPanelContainer;
}
@Override
public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
return null;
@@ -210,6 +217,9 @@ public class RecentsActivity extends BaseDraggingActivity {
@Override
protected void onStart() {
// Set the alpha to 1 before calling super, as it may get set back to 0 due to
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
UiFactory.onStart(this);
mFallbackRecentsView.resetTaskVisuals();
@@ -63,6 +63,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.AnimationFactory;
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
import com.android.quickstep.util.ClipAnimationHelper;
@@ -164,6 +165,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private LayoutListener mLayoutListener;
private RecentsView mRecentsView;
private QuickScrubController mQuickScrubController;
private AnimationFactory mAnimationFactory = (t) -> { };
private Runnable mLauncherDrawnCallback;
@@ -212,11 +214,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
this::launcherFrameDrawn);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
this::onGestureStartedWithLauncher);
this::notifyGestureStartedAsync);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
| STATE_GESTURE_CANCELLED,
this::resetStateForAnimationCancel);
mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
this::sendRemoteAnimationsToAnimationFactory);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_SCALED_CONTROLLER_APP,
this::resumeLastTask);
@@ -321,7 +325,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
return;
}
mActivityControlHelper.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible);
mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
if (mWasLauncherAlreadyVisible) {
@@ -377,9 +382,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mLauncherFrameDrawnTime = SystemClock.uptimeMillis();
}
private void sendRemoteAnimationsToAnimationFactory() {
mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationWrapper.targetSet);
}
private void initializeLauncherAnimationController() {
mLayoutListener.setHandler(this);
onLauncherLayoutChanged();
buildAnimationController();
final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs;
SysuiEventLogger.writeDummyRecentsTransition(transitionDelay);
@@ -418,15 +427,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
/**
* Called by {@link #mLayoutListener} when launcher layout changes
*/
public void onLauncherLayoutChanged() {
public void buildAnimationController() {
initTransitionEndpoints(mActivity.getDeviceProfile());
mAnimationFactory.createActivityController(mTransitionDragLength);
}
if (!mWasLauncherAlreadyVisible) {
mLauncherTransitionController = mActivityControlHelper
.createControllerForHiddenActivity(mActivity, mTransitionDragLength);
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
@WorkerThread
@@ -546,17 +555,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
}
}
private void onGestureStartedWithLauncher() {
notifyGestureStartedAsync();
if (mWasLauncherAlreadyVisible) {
mLauncherTransitionController = mActivityControlHelper
.createControllerForVisibleActivity(mActivity);
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
}
@WorkerThread
public void onGestureEnded(float endVelocity) {
Resources res = mContext.getResources();
@@ -25,7 +25,6 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
@@ -111,14 +110,17 @@ public class ClipAnimationHelper {
mClipRect.bottom = (int)
(mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
TransactionCompat transaction = new TransactionCompat();
for (RemoteAnimationTargetCompat app : targetSet.apps) {
mTmpMatrix.postTranslate(app.position.x, app.position.y);
transaction.setMatrix(app.leash, mTmpMatrix)
.setWindowCrop(app.leash, mClipRect);
if (app.isNotInRecents) {
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
mTmpMatrix.postTranslate(app.position.x, app.position.y);
transaction.setMatrix(app.leash, mTmpMatrix)
.setWindowCrop(app.leash, mClipRect);
}
if (app.isNotInRecents
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
transaction.setAlpha(app.leash, 1 - progress);
}
transaction.show(app.leash);
@@ -24,23 +24,18 @@ import java.util.ArrayList;
*/
public class RemoteAnimationTargetSet {
public final boolean allTransparent;
public final RemoteAnimationTargetCompat[] apps;
public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) {
boolean allTransparent = true;
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
if (apps != null) {
for (RemoteAnimationTargetCompat target : apps) {
if (target.mode == targetMode) {
allTransparent &= target.isTranslucent;
filteredApps.add(target);
}
}
}
this.allTransparent = allTransparent;
this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]);
}
@@ -52,4 +47,13 @@ public class RemoteAnimationTargetSet {
}
return null;
}
public boolean isAnimatingHome() {
for (RemoteAnimationTargetCompat target : apps) {
if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
return true;
}
}
return false;
}
}
@@ -54,7 +54,7 @@ public class LauncherLayoutListener extends AbstractFloatingView
@Override
public void setInsets(Rect insets) {
if (mHandler != null) {
mHandler.onLauncherLayoutChanged();
mHandler.buildAnimationController();
}
}