/* * 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.fallback.FallbackRecentsView.ZOOM_PROGRESS; 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.fallback.FallbackRecentsView; 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 { 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 callback) { if (activityVisible) { return (transitionLength) -> { }; } FallbackRecentsView rv = activity.getOverviewPanel(); rv.setContentAlpha(0); rv.getClearAllButton().setVisibilityAlpha(0); rv.setDisallowScrollToClearAll(true); boolean fromState = !animateActivity; rv.setInOverviewState(fromState); 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) { AnimatorSet animatorSet = new AnimatorSet(); if (isAnimatingToRecents) { ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1); anim.setDuration(transitionLength).setInterpolator(LINEAR); animatorSet.play(anim); } ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0); anim.setDuration(transitionLength).setInterpolator(LINEAR); animatorSet.play(anim); AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(animatorSet, transitionLength); // Since we are changing the start position of the UI, reapply the state, at the end controller.setEndAction(() -> { boolean endState = true; rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5 ? endState : fromState); }); callback.accept(controller); } }; } @Override public ActivityInitListener createActivityInitListener( BiPredicate 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; } @Override public void onLaunchTaskFailed(RecentsActivity activity) { // TODO: probably go back to overview instead. activity.getOverviewPanel().startHome(); } }