a04e746e84
When ending in recents, we reapply the state - therefore, it's important to make sure we are in OverviewState before onSwipeUpComplete(). This is done by mLauncherTransitionController, which sets OverviewState on end. We already force mLauncherTransitionController to end before calling onSwipeUpComplete(), but in this case we were calling cancel() and setting mLauncherTransitionController = null, which meant we could never call end() on it. Instead, we should always call end() if we set it to null. Also ensure mLauncherTransitionController is created even if the gesture is completed, if an existing controller isn't already running. This can happen if you swipe up quickly enough that we get onGestureEnd before launcher is drawn, and in that case we still want the launcher component to animate once its ready. This is even more important for 2-button mode, because again, we rely on mLauncherTransitionController to set the state to OverviewState before we reapply it. Finally, clarified some methods by renaming "swipeUp" to "swipeUpToRecents". Bug: 132757019 Change-Id: Ieb24a4f36a39780e5d64d7bc312791608db474d1
210 lines
7.4 KiB
Java
210 lines
7.4 KiB
Java
/*
|
|
* 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 com.android.launcher3.anim.Interpolators.LINEAR;
|
|
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
|
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorSet;
|
|
import android.animation.ObjectAnimator;
|
|
import android.content.Context;
|
|
import android.graphics.Rect;
|
|
import android.graphics.RectF;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.android.launcher3.DeviceProfile;
|
|
import com.android.launcher3.anim.AnimationSuccessListener;
|
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
|
import com.android.quickstep.util.LayoutUtils;
|
|
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
|
import com.android.quickstep.views.RecentsView;
|
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
|
|
|
import java.util.function.BiPredicate;
|
|
import java.util.function.Consumer;
|
|
|
|
/**
|
|
* {@link ActivityControlHelper} for recents when the default launcher is different than the
|
|
* currently running one and apps should interact with the {@link RecentsActivity} as opposed
|
|
* to the in-launcher one.
|
|
*/
|
|
public final class FallbackActivityControllerHelper implements
|
|
ActivityControlHelper<RecentsActivity> {
|
|
|
|
public FallbackActivityControllerHelper() { }
|
|
|
|
@Override
|
|
public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
|
|
// TODO:
|
|
}
|
|
|
|
@Override
|
|
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
|
|
LayoutUtils.calculateFallbackTaskSize(context, dp, outRect);
|
|
if (dp.isVerticalBarLayout()
|
|
&& SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
|
|
Rect targetInsets = dp.getInsets();
|
|
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
|
|
return dp.hotseatBarSizePx + hotseatInset;
|
|
} else {
|
|
return dp.heightPx - outRect.bottom;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSwipeUpToRecentsComplete(RecentsActivity activity) {
|
|
RecentsView recentsView = activity.getOverviewPanel();
|
|
recentsView.getClearAllButton().setVisibilityAlpha(1);
|
|
recentsView.setDisallowScrollToClearAll(false);
|
|
}
|
|
|
|
@Override
|
|
public void onAssistantVisibilityChanged(float visibility) {
|
|
// TODO:
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public HomeAnimationFactory prepareHomeUI(RecentsActivity activity) {
|
|
RecentsView recentsView = activity.getOverviewPanel();
|
|
|
|
return new HomeAnimationFactory() {
|
|
@NonNull
|
|
@Override
|
|
public RectF getWindowTargetRect() {
|
|
float centerX = recentsView.getPivotX();
|
|
float centerY = recentsView.getPivotY();
|
|
return new RectF(centerX, centerY, centerX, centerY);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public AnimatorPlaybackController createActivityAnimationToHome() {
|
|
Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
|
|
anim.addListener(new AnimationSuccessListener() {
|
|
@Override
|
|
public void onAnimationSuccess(Animator animator) {
|
|
recentsView.startHome();
|
|
}
|
|
});
|
|
AnimatorSet animatorSet = new AnimatorSet();
|
|
animatorSet.play(anim);
|
|
long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight());
|
|
return AnimatorPlaybackController.wrap(animatorSet, accuracy);
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
|
|
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
|
|
if (activityVisible) {
|
|
return (transitionLength) -> { };
|
|
}
|
|
|
|
RecentsView rv = activity.getOverviewPanel();
|
|
rv.setContentAlpha(0);
|
|
rv.getClearAllButton().setVisibilityAlpha(0);
|
|
rv.setDisallowScrollToClearAll(true);
|
|
|
|
return new AnimationFactory() {
|
|
|
|
boolean isAnimatingToRecents = false;
|
|
|
|
@Override
|
|
public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) {
|
|
isAnimatingToRecents = targets != null && targets.isAnimatingHome();
|
|
if (!isAnimatingToRecents) {
|
|
rv.setContentAlpha(1);
|
|
}
|
|
createActivityController(getSwipeUpDestinationAndLength(
|
|
activity.getDeviceProfile(), activity, new Rect()));
|
|
}
|
|
|
|
@Override
|
|
public void createActivityController(long transitionLength) {
|
|
if (!isAnimatingToRecents) {
|
|
return;
|
|
}
|
|
|
|
ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
|
|
anim.setDuration(transitionLength).setInterpolator(LINEAR);
|
|
AnimatorSet animatorSet = new AnimatorSet();
|
|
animatorSet.play(anim);
|
|
callback.accept(AnimatorPlaybackController.wrap(animatorSet, transitionLength));
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public ActivityInitListener createActivityInitListener(
|
|
BiPredicate<RecentsActivity, Boolean> onInitListener) {
|
|
return new RecentsActivityTracker(onInitListener);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public RecentsActivity getCreatedActivity() {
|
|
return RecentsActivityTracker.getCurrentActivity();
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public RecentsView getVisibleRecentsView() {
|
|
RecentsActivity activity = getCreatedActivity();
|
|
if (activity != null && activity.hasWindowFocus()) {
|
|
return activity.getOverviewPanel();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
|
|
// TODO: Remove this once b/77875376 is fixed
|
|
return target.sourceContainerBounds;
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldMinimizeSplitScreen() {
|
|
// TODO: Remove this once b/77875376 is fixed
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getContainerType() {
|
|
RecentsActivity activity = getCreatedActivity();
|
|
boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
|
|
return visible
|
|
? LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER
|
|
: LauncherLogProto.ContainerType.APP;
|
|
}
|
|
|
|
@Override
|
|
public boolean isInLiveTileMode() {
|
|
return false;
|
|
}
|
|
}
|