Combine RecentsViewStateController with base class
- BaseRecentsViewStateController is only inherited by RecentsViewStateController, remove the base class to simplify code - Also converted RecentsViewStateController to Kotlin and remove a bunch of warnings Fix: 387267938 Test: presubmit and manual Flag: EXEMPT refactor Change-Id: I18e9c2b186a64a0af39230cb41e3b3f4949107d5
This commit is contained in:
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* 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.launcher3.uioverrides;
|
||||
|
||||
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
|
||||
import static com.android.app.animation.Interpolators.AGGRESSIVE_EASE_IN_OUT;
|
||||
import static com.android.app.animation.Interpolators.FINAL_FRAME;
|
||||
import static com.android.app.animation.Interpolators.INSTANT;
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile;
|
||||
import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
|
||||
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
|
||||
import static com.android.quickstep.views.RecentsView.DESKTOP_CAROUSEL_DETACH_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA;
|
||||
|
||||
import android.util.FloatProperty;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* State handler for recents view. Manages UI changes and animations for recents view based off the
|
||||
* current {@link LauncherState}.
|
||||
*
|
||||
* @param <T> the recents view
|
||||
*/
|
||||
public abstract class BaseRecentsViewStateController<T extends RecentsView>
|
||||
implements StateHandler<LauncherState> {
|
||||
protected final T mRecentsView;
|
||||
protected final QuickstepLauncher mLauncher;
|
||||
|
||||
public BaseRecentsViewStateController(@NonNull QuickstepLauncher launcher) {
|
||||
mLauncher = launcher;
|
||||
mRecentsView = launcher.getOverviewPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@NonNull LauncherState state) {
|
||||
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher);
|
||||
RECENTS_SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]);
|
||||
ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, scaleAndOffset[1]);
|
||||
TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
|
||||
|
||||
getContentAlphaProperty().set(mRecentsView, state.isRecentsViewVisible ? 1f : 0);
|
||||
getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
|
||||
RECENTS_GRID_PROGRESS.set(mRecentsView,
|
||||
state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
|
||||
TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, state.showTaskThumbnailSplash() ? 1f : 0f);
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
DESKTOP_CAROUSEL_DETACH_PROGRESS.set(mRecentsView,
|
||||
state.detachDesktopCarousel() ? 1f : 0f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
|
||||
PendingAnimation builder) {
|
||||
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
|
||||
return;
|
||||
}
|
||||
setStateWithAnimationInternal(toState, config, builder);
|
||||
builder.addEndListener(success -> {
|
||||
if (!success && !toState.isRecentsViewVisible) {
|
||||
mRecentsView.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logic for animating the recents view UI.
|
||||
*
|
||||
* @param toState state to animate to
|
||||
* @param config current animation config
|
||||
* @param setter animator set builder
|
||||
*/
|
||||
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
|
||||
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
|
||||
float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher);
|
||||
setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
|
||||
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
|
||||
setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1],
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
|
||||
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
|
||||
|
||||
boolean exitingOverview =
|
||||
!FeatureFlags.enableSplitContextually() && !toState.isRecentsViewVisible;
|
||||
if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
|
||||
setter.add(mRecentsView.getSplitSelectController().getSplitAnimationController()
|
||||
.createPlaceholderDismissAnim(mLauncher, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
|
||||
setter.getDuration()));
|
||||
setter.setViewAlpha(
|
||||
mRecentsView.getSplitInstructionsView(),
|
||||
0,
|
||||
config.getInterpolator(
|
||||
ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
|
||||
LINEAR
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
setter.setFloat(mRecentsView, getContentAlphaProperty(),
|
||||
toState.isRecentsViewVisible ? 1 : 0,
|
||||
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
|
||||
|
||||
setter.setFloat(
|
||||
mRecentsView, getTaskModalnessProperty(),
|
||||
toState.getOverviewModalness(),
|
||||
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
|
||||
|
||||
LauncherState fromState = mLauncher.getStateManager().getState();
|
||||
setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
|
||||
toState.showTaskThumbnailSplash() ? 1f : 0f,
|
||||
getOverviewInterpolator(fromState, toState));
|
||||
|
||||
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS,
|
||||
toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f,
|
||||
getOverviewInterpolator(fromState, toState));
|
||||
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
setter.setFloat(mRecentsView, DESKTOP_CAROUSEL_DETACH_PROGRESS,
|
||||
toState.detachDesktopCarousel() ? 1f : 0f,
|
||||
getOverviewInterpolator(fromState, toState));
|
||||
}
|
||||
}
|
||||
|
||||
private Interpolator getOverviewInterpolator(LauncherState fromState, LauncherState toState) {
|
||||
return fromState == QUICK_SWITCH_FROM_HOME
|
||||
? ACCELERATE_DECELERATE
|
||||
: toState.isRecentsViewVisible ? INSTANT : FINAL_FRAME;
|
||||
}
|
||||
|
||||
abstract FloatProperty getTaskModalnessProperty();
|
||||
|
||||
/**
|
||||
* Get property for content alpha for the recents view.
|
||||
*
|
||||
* @return the float property for the view's content alpha
|
||||
*/
|
||||
abstract FloatProperty getContentAlphaProperty();
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.launcher3.uioverrides;
|
||||
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
|
||||
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
|
||||
import static com.android.wm.shell.Flags.enableSplitContextual;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatedFloat;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
|
||||
import com.android.quickstep.util.AnimUtils;
|
||||
import com.android.quickstep.util.SplitAnimationTimings;
|
||||
import com.android.quickstep.views.ClearAllButton;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
* State handler for handling UI changes for {@link LauncherRecentsView}. In addition to managing
|
||||
* the basic view properties, this class also manages changes in the task visuals.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public final class RecentsViewStateController extends
|
||||
BaseRecentsViewStateController<LauncherRecentsView> {
|
||||
|
||||
public RecentsViewStateController(QuickstepLauncher launcher) {
|
||||
super(launcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@NonNull LauncherState state) {
|
||||
super.setState(state);
|
||||
if (state.isRecentsViewVisible) {
|
||||
mRecentsView.updateEmptyMessage();
|
||||
} else {
|
||||
mRecentsView.resetTaskVisuals();
|
||||
}
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
|
||||
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
|
||||
// In Overview, we may be layering app surfaces behind Launcher, so we need to notify
|
||||
// DepthController to prevent optimizations which might occlude the layers behind
|
||||
mLauncher.getDepthController().setHasContentBehindLauncher(state.isRecentsViewVisible);
|
||||
|
||||
PendingAnimation builder =
|
||||
new PendingAnimation(state.getTransitionDuration(mLauncher, true));
|
||||
|
||||
handleSplitSelectionState(state, builder, /* animate */false);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setStateWithAnimationInternal(@NonNull LauncherState toState,
|
||||
@NonNull StateAnimationConfig config, @NonNull PendingAnimation builder) {
|
||||
super.setStateWithAnimationInternal(toState, config, builder);
|
||||
|
||||
if (toState.isRecentsViewVisible) {
|
||||
// While animating into recents, update the visible task data as needed
|
||||
builder.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL));
|
||||
mRecentsView.updateEmptyMessage();
|
||||
// TODO(b/246283207): Remove logging once root cause of flake detected.
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
Log.d("b/246283207", "RecentsView#setStateWithAnimationInternal getCurrentPage(): "
|
||||
+ mRecentsView.getCurrentPage()
|
||||
+ ", getScrollForPage(getCurrentPage())): "
|
||||
+ mRecentsView.getScrollForPage(mRecentsView.getCurrentPage()));
|
||||
}
|
||||
} else {
|
||||
builder.addListener(
|
||||
AnimatorListeners.forSuccessCallback(mRecentsView::resetTaskVisuals));
|
||||
}
|
||||
// In Overview, we may be layering app surfaces behind Launcher, so we need to notify
|
||||
// DepthController to prevent optimizations which might occlude the layers behind
|
||||
builder.addListener(AnimatorListeners.forSuccessCallback(() ->
|
||||
mLauncher.getDepthController().setHasContentBehindLauncher(
|
||||
toState.isRecentsViewVisible)));
|
||||
|
||||
handleSplitSelectionState(toState, builder, /* animate */true);
|
||||
|
||||
setAlphas(builder, config, toState);
|
||||
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
|
||||
toState.getOverviewFullscreenProgress(), LINEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or dismiss split screen select animations.
|
||||
* @param builder if null then this will run the split select animations right away, otherwise
|
||||
* will add animations to builder.
|
||||
*/
|
||||
private void handleSplitSelectionState(@NonNull LauncherState toState,
|
||||
@NonNull PendingAnimation builder, boolean animate) {
|
||||
boolean goingToOverviewFromWorkspaceContextual = enableSplitContextual() &&
|
||||
toState == OVERVIEW && mLauncher.isSplitSelectionActive();
|
||||
if (toState != OVERVIEW_SPLIT_SELECT && !goingToOverviewFromWorkspaceContextual) {
|
||||
// Not going to split
|
||||
return;
|
||||
}
|
||||
|
||||
// Create transition animations to split select
|
||||
RecentsPagedOrientationHandler orientationHandler =
|
||||
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
|
||||
Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
|
||||
orientationHandler.getSplitSelectTaskOffset(
|
||||
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
|
||||
mLauncher.getDeviceProfile());
|
||||
|
||||
SplitAnimationTimings timings =
|
||||
AnimUtils.getDeviceOverviewToSplitTimings(mLauncher.getDeviceProfile().isTablet);
|
||||
if (!goingToOverviewFromWorkspaceContextual) {
|
||||
// This animation is already done for the contextual case, don't redo it
|
||||
mRecentsView.createSplitSelectInitAnimation(builder,
|
||||
toState.getTransitionDuration(mLauncher, true /* isToState */));
|
||||
}
|
||||
// Shift tasks vertically downward to get out of placeholder view
|
||||
builder.setFloat(mRecentsView, taskViewsFloat.first,
|
||||
toState.getSplitSelectTranslation(mLauncher),
|
||||
timings.getGridSlidePrimaryInterpolator());
|
||||
// Zero out horizontal translation
|
||||
builder.setFloat(mRecentsView, taskViewsFloat.second,
|
||||
0,
|
||||
timings.getGridSlideSecondaryInterpolator());
|
||||
|
||||
mRecentsView.handleDesktopTaskInSplitSelectState(builder,
|
||||
timings.getDesktopTaskFadeInterpolator());
|
||||
|
||||
if (!animate) {
|
||||
AnimatorSet as = builder.buildAnim();
|
||||
as.start();
|
||||
as.end();
|
||||
}
|
||||
}
|
||||
|
||||
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
|
||||
LauncherState state) {
|
||||
float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
|
||||
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha, LINEAR);
|
||||
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
|
||||
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
|
||||
AnimatedFloat.VALUE, overviewButtonAlpha, config.getInterpolator(
|
||||
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
|
||||
}
|
||||
|
||||
@Override
|
||||
FloatProperty<RecentsView> getTaskModalnessProperty() {
|
||||
return TASK_MODALNESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
FloatProperty<RecentsView> getContentAlphaProperty() {
|
||||
return CONTENT_ALPHA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.launcher3.uioverrides
|
||||
|
||||
import com.android.app.animation.Interpolators.ACCELERATE_DECELERATE
|
||||
import com.android.app.animation.Interpolators.AGGRESSIVE_EASE_IN_OUT
|
||||
import com.android.app.animation.Interpolators.FINAL_FRAME
|
||||
import com.android.app.animation.Interpolators.INSTANT
|
||||
import com.android.app.animation.Interpolators.LINEAR
|
||||
import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
|
||||
import com.android.launcher3.LauncherState
|
||||
import com.android.launcher3.anim.AnimatedFloat
|
||||
import com.android.launcher3.anim.AnimatorListeners.forSuccessCallback
|
||||
import com.android.launcher3.anim.PendingAnimation
|
||||
import com.android.launcher3.anim.PropertySetter
|
||||
import com.android.launcher3.config.FeatureFlags.enableSplitContextually
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
|
||||
import com.android.launcher3.statemanager.StateManager.StateHandler
|
||||
import com.android.launcher3.states.StateAnimationConfig
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X
|
||||
import com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y
|
||||
import com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW
|
||||
import com.android.quickstep.util.AnimUtils
|
||||
import com.android.quickstep.views.ClearAllButton
|
||||
import com.android.quickstep.views.RecentsView
|
||||
import com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET
|
||||
import com.android.quickstep.views.RecentsView.CONTENT_ALPHA
|
||||
import com.android.quickstep.views.RecentsView.DESKTOP_CAROUSEL_DETACH_PROGRESS
|
||||
import com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS
|
||||
import com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS
|
||||
import com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY
|
||||
import com.android.quickstep.views.RecentsView.TASK_MODALNESS
|
||||
import com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION
|
||||
import com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION
|
||||
import com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION
|
||||
import com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA
|
||||
import com.android.quickstep.views.TaskView.Companion.FLAG_UPDATE_ALL
|
||||
import com.android.wm.shell.Flags.enableSplitContextual
|
||||
|
||||
/**
|
||||
* State handler for handling UI changes for [com.android.quickstep.views.LauncherRecentsView]. In
|
||||
* addition to managing the basic view properties, this class also manages changes in the task
|
||||
* visuals.
|
||||
*/
|
||||
class RecentsViewStateController(private val launcher: QuickstepLauncher) :
|
||||
StateHandler<LauncherState> {
|
||||
private val recentsView: RecentsView<*, *> = launcher.getOverviewPanel()
|
||||
|
||||
override fun setState(state: LauncherState) {
|
||||
val scaleAndOffset = state.getOverviewScaleAndOffset(launcher)
|
||||
RECENTS_SCALE_PROPERTY.set(recentsView, scaleAndOffset[0])
|
||||
ADJACENT_PAGE_HORIZONTAL_OFFSET.set(recentsView, scaleAndOffset[1])
|
||||
TASK_SECONDARY_TRANSLATION.set(recentsView, 0f)
|
||||
|
||||
CONTENT_ALPHA.set(recentsView, if (state.isRecentsViewVisible) 1f else 0f)
|
||||
TASK_MODALNESS.set(recentsView, state.overviewModalness)
|
||||
RECENTS_GRID_PROGRESS.set(
|
||||
recentsView,
|
||||
if (state.displayOverviewTasksAsGrid(launcher.deviceProfile)) 1f else 0f,
|
||||
)
|
||||
TASK_THUMBNAIL_SPLASH_ALPHA.set(
|
||||
recentsView,
|
||||
if (state.showTaskThumbnailSplash()) 1f else 0f,
|
||||
)
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
DESKTOP_CAROUSEL_DETACH_PROGRESS.set(
|
||||
recentsView,
|
||||
if (state.detachDesktopCarousel()) 1f else 0f,
|
||||
)
|
||||
}
|
||||
|
||||
if (state.isRecentsViewVisible) {
|
||||
recentsView.updateEmptyMessage()
|
||||
} else {
|
||||
recentsView.resetTaskVisuals()
|
||||
}
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, StateAnimationConfig(), state)
|
||||
recentsView.setFullscreenProgress(state.overviewFullscreenProgress)
|
||||
// In Overview, we may be layering app surfaces behind Launcher, so we need to notify
|
||||
// DepthController to prevent optimizations which might occlude the layers behind
|
||||
launcher.depthController.setHasContentBehindLauncher(state.isRecentsViewVisible)
|
||||
|
||||
val builder = PendingAnimation(state.getTransitionDuration(launcher, true).toLong())
|
||||
handleSplitSelectionState(state, builder, animate = false)
|
||||
}
|
||||
|
||||
override fun setStateWithAnimation(
|
||||
toState: LauncherState,
|
||||
config: StateAnimationConfig,
|
||||
builder: PendingAnimation,
|
||||
) {
|
||||
if (config.hasAnimationFlag(SKIP_OVERVIEW)) return
|
||||
|
||||
val scaleAndOffset = toState.getOverviewScaleAndOffset(launcher)
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
RECENTS_SCALE_PROPERTY,
|
||||
scaleAndOffset[0],
|
||||
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR),
|
||||
)
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
ADJACENT_PAGE_HORIZONTAL_OFFSET,
|
||||
scaleAndOffset[1],
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR),
|
||||
)
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
TASK_SECONDARY_TRANSLATION,
|
||||
0f,
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR),
|
||||
)
|
||||
|
||||
val exitingOverview = !enableSplitContextually() && !toState.isRecentsViewVisible
|
||||
if (recentsView.isSplitSelectionActive && exitingOverview) {
|
||||
builder.add(
|
||||
recentsView.splitSelectController.splitAnimationController
|
||||
.createPlaceholderDismissAnim(
|
||||
launcher,
|
||||
LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
|
||||
builder.duration,
|
||||
)
|
||||
)
|
||||
builder.setViewAlpha(
|
||||
recentsView.splitInstructionsView,
|
||||
0f,
|
||||
config.getInterpolator(ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE, LINEAR),
|
||||
)
|
||||
}
|
||||
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
CONTENT_ALPHA,
|
||||
if (toState.isRecentsViewVisible) 1f else 0f,
|
||||
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT),
|
||||
)
|
||||
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
TASK_MODALNESS,
|
||||
toState.overviewModalness,
|
||||
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR),
|
||||
)
|
||||
|
||||
val fromState = launcher.stateManager.state
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
TASK_THUMBNAIL_SPLASH_ALPHA,
|
||||
if (toState.showTaskThumbnailSplash()) 1f else 0f,
|
||||
getOverviewInterpolator(fromState, toState),
|
||||
)
|
||||
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
RECENTS_GRID_PROGRESS,
|
||||
if (toState.displayOverviewTasksAsGrid(launcher.deviceProfile)) 1f else 0f,
|
||||
getOverviewInterpolator(fromState, toState),
|
||||
)
|
||||
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
DESKTOP_CAROUSEL_DETACH_PROGRESS,
|
||||
if (toState.detachDesktopCarousel()) 1f else 0f,
|
||||
getOverviewInterpolator(fromState, toState),
|
||||
)
|
||||
}
|
||||
|
||||
if (toState.isRecentsViewVisible) {
|
||||
// While animating into recents, update the visible task data as needed
|
||||
builder.addOnFrameCallback { recentsView.loadVisibleTaskData(FLAG_UPDATE_ALL) }
|
||||
recentsView.updateEmptyMessage()
|
||||
} else {
|
||||
builder.addListener(forSuccessCallback { recentsView.resetTaskVisuals() })
|
||||
}
|
||||
// In Overview, we may be layering app surfaces behind Launcher, so we need to notify
|
||||
// DepthController to prevent optimizations which might occlude the layers behind
|
||||
builder.addListener(
|
||||
forSuccessCallback {
|
||||
launcher.depthController.setHasContentBehindLauncher(toState.isRecentsViewVisible)
|
||||
}
|
||||
)
|
||||
|
||||
handleSplitSelectionState(toState, builder, animate = true)
|
||||
|
||||
setAlphas(builder, config, toState)
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
FULLSCREEN_PROGRESS,
|
||||
toState.overviewFullscreenProgress,
|
||||
LINEAR,
|
||||
)
|
||||
|
||||
builder.addEndListener { success: Boolean ->
|
||||
if (!success && !toState.isRecentsViewVisible) {
|
||||
recentsView.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or dismiss split screen select animations.
|
||||
*
|
||||
* @param builder if null then this will run the split select animations right away, otherwise
|
||||
* will add animations to builder.
|
||||
*/
|
||||
private fun handleSplitSelectionState(
|
||||
toState: LauncherState,
|
||||
builder: PendingAnimation,
|
||||
animate: Boolean,
|
||||
) {
|
||||
val goingToOverviewFromWorkspaceContextual =
|
||||
enableSplitContextual() &&
|
||||
toState == LauncherState.OVERVIEW &&
|
||||
launcher.isSplitSelectionActive
|
||||
if (
|
||||
toState != LauncherState.OVERVIEW_SPLIT_SELECT &&
|
||||
!goingToOverviewFromWorkspaceContextual
|
||||
) {
|
||||
// Not going to split
|
||||
return
|
||||
}
|
||||
|
||||
// Create transition animations to split select
|
||||
val orientationHandler = recentsView.pagedOrientationHandler
|
||||
val taskViewsFloat =
|
||||
orientationHandler.getSplitSelectTaskOffset(
|
||||
TASK_PRIMARY_SPLIT_TRANSLATION,
|
||||
TASK_SECONDARY_SPLIT_TRANSLATION,
|
||||
launcher.deviceProfile,
|
||||
)
|
||||
|
||||
val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet)
|
||||
if (!goingToOverviewFromWorkspaceContextual) {
|
||||
// This animation is already done for the contextual case, don't redo it
|
||||
recentsView.createSplitSelectInitAnimation(
|
||||
builder,
|
||||
toState.getTransitionDuration(launcher, true),
|
||||
)
|
||||
}
|
||||
// Shift tasks vertically downward to get out of placeholder view
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
taskViewsFloat.first,
|
||||
toState.getSplitSelectTranslation(launcher),
|
||||
timings.gridSlidePrimaryInterpolator,
|
||||
)
|
||||
// Zero out horizontal translation
|
||||
builder.setFloat(
|
||||
recentsView,
|
||||
taskViewsFloat.second,
|
||||
0f,
|
||||
timings.gridSlideSecondaryInterpolator,
|
||||
)
|
||||
|
||||
recentsView.handleDesktopTaskInSplitSelectState(
|
||||
builder,
|
||||
timings.desktopTaskFadeInterpolator,
|
||||
)
|
||||
|
||||
if (!animate) {
|
||||
builder.buildAnim().apply {
|
||||
start()
|
||||
end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAlphas(
|
||||
propertySetter: PropertySetter,
|
||||
config: StateAnimationConfig,
|
||||
state: LauncherState,
|
||||
) {
|
||||
val clearAllButtonAlpha =
|
||||
if (state.areElementsVisible(launcher, LauncherState.CLEAR_ALL_BUTTON)) 1f else 0f
|
||||
propertySetter.setFloat(
|
||||
recentsView.clearAllButton,
|
||||
ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha,
|
||||
LINEAR,
|
||||
)
|
||||
val overviewButtonAlpha =
|
||||
if (state.areElementsVisible(launcher, LauncherState.OVERVIEW_ACTIONS)) 1f else 0f
|
||||
propertySetter.setFloat(
|
||||
launcher.actionsView.visibilityAlpha,
|
||||
AnimatedFloat.VALUE,
|
||||
overviewButtonAlpha,
|
||||
config.getInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, LINEAR),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getOverviewInterpolator(fromState: LauncherState, toState: LauncherState) =
|
||||
when {
|
||||
fromState == LauncherState.QUICK_SWITCH_FROM_HOME -> ACCELERATE_DECELERATE
|
||||
toState.isRecentsViewVisible -> INSTANT
|
||||
else -> FINAL_FRAME
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
|
||||
setter.add(pa.buildAnim());
|
||||
}
|
||||
|
||||
Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
|
||||
Pair<FloatProperty<RecentsView<?, ?>>, FloatProperty<RecentsView<?, ?>>> taskViewsFloat =
|
||||
mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
|
||||
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
|
||||
mRecentsViewContainer.getDeviceProfile());
|
||||
|
||||
@@ -269,8 +269,8 @@ public abstract class RecentsView<
|
||||
private static final String TAG = "RecentsView";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static final FloatProperty<RecentsView> CONTENT_ALPHA =
|
||||
new FloatProperty<RecentsView>("contentAlpha") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> CONTENT_ALPHA =
|
||||
new FloatProperty<>("contentAlpha") {
|
||||
@Override
|
||||
public void setValue(RecentsView view, float v) {
|
||||
view.setContentAlpha(v);
|
||||
@@ -282,8 +282,8 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> FULLSCREEN_PROGRESS =
|
||||
new FloatProperty<RecentsView>("fullscreenProgress") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> FULLSCREEN_PROGRESS =
|
||||
new FloatProperty<>("fullscreenProgress") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setFullscreenProgress(v);
|
||||
@@ -295,8 +295,8 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> TASK_MODALNESS =
|
||||
new FloatProperty<RecentsView>("taskModalness") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> TASK_MODALNESS =
|
||||
new FloatProperty<>("taskModalness") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setTaskModalness(v);
|
||||
@@ -308,8 +308,8 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> ADJACENT_PAGE_HORIZONTAL_OFFSET =
|
||||
new FloatProperty<RecentsView>("adjacentPageHorizontalOffset") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> ADJACENT_PAGE_HORIZONTAL_OFFSET =
|
||||
new FloatProperty<>("adjacentPageHorizontalOffset") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
if (recentsView.mAdjacentPageHorizontalOffset != v) {
|
||||
@@ -324,8 +324,8 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> RUNNING_TASK_ATTACH_ALPHA =
|
||||
new FloatProperty<RecentsView>("runningTaskAttachAlpha") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> RUNNING_TASK_ATTACH_ALPHA =
|
||||
new FloatProperty<>("runningTaskAttachAlpha") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.mRunningTaskAttachAlpha = v;
|
||||
@@ -349,8 +349,8 @@ public abstract class RecentsView<
|
||||
* Can be used to tint the color of the RecentsView to simulate a scrim that can views
|
||||
* excluded from. Really should be a proper scrim.
|
||||
*/
|
||||
private static final FloatProperty<RecentsView> COLOR_TINT =
|
||||
new FloatProperty<RecentsView>("colorTint") {
|
||||
private static final FloatProperty<RecentsView<?, ?>> COLOR_TINT =
|
||||
new FloatProperty<>("colorTint") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setColorTint(v);
|
||||
@@ -368,8 +368,8 @@ public abstract class RecentsView<
|
||||
* more specific, we'd want to create a similar FloatProperty just for a TaskView's
|
||||
* offsetX/Y property
|
||||
*/
|
||||
public static final FloatProperty<RecentsView> TASK_SECONDARY_TRANSLATION =
|
||||
new FloatProperty<RecentsView>("taskSecondaryTranslation") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> TASK_SECONDARY_TRANSLATION =
|
||||
new FloatProperty<>("taskSecondaryTranslation") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setTaskViewsResistanceTranslation(v);
|
||||
@@ -387,8 +387,8 @@ public abstract class RecentsView<
|
||||
* more specific, we'd want to create a similar FloatProperty just for a TaskView's
|
||||
* offsetX/Y property
|
||||
*/
|
||||
public static final FloatProperty<RecentsView> TASK_PRIMARY_SPLIT_TRANSLATION =
|
||||
new FloatProperty<RecentsView>("taskPrimarySplitTranslation") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> TASK_PRIMARY_SPLIT_TRANSLATION =
|
||||
new FloatProperty<>("taskPrimarySplitTranslation") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setTaskViewsPrimarySplitTranslation(v);
|
||||
@@ -400,8 +400,8 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> TASK_SECONDARY_SPLIT_TRANSLATION =
|
||||
new FloatProperty<RecentsView>("taskSecondarySplitTranslation") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> TASK_SECONDARY_SPLIT_TRANSLATION =
|
||||
new FloatProperty<>("taskSecondarySplitTranslation") {
|
||||
@Override
|
||||
public void setValue(RecentsView recentsView, float v) {
|
||||
recentsView.setTaskViewsSecondarySplitTranslation(v);
|
||||
@@ -414,8 +414,8 @@ public abstract class RecentsView<
|
||||
};
|
||||
|
||||
/** Same as normal SCALE_PROPERTY, but also updates page offsets that depend on this scale. */
|
||||
public static final FloatProperty<RecentsView> RECENTS_SCALE_PROPERTY =
|
||||
new FloatProperty<RecentsView>("recentsScale") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> RECENTS_SCALE_PROPERTY =
|
||||
new FloatProperty<>("recentsScale") {
|
||||
@Override
|
||||
public void setValue(RecentsView view, float scale) {
|
||||
view.setScaleX(scale);
|
||||
@@ -444,8 +444,8 @@ public abstract class RecentsView<
|
||||
* Progress of Recents view from carousel layout to grid layout. If Recents is not shown as a
|
||||
* grid, then the value remains 0.
|
||||
*/
|
||||
public static final FloatProperty<RecentsView> RECENTS_GRID_PROGRESS =
|
||||
new FloatProperty<RecentsView>("recentsGrid") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> RECENTS_GRID_PROGRESS =
|
||||
new FloatProperty<>("recentsGrid") {
|
||||
@Override
|
||||
public void setValue(RecentsView view, float gridProgress) {
|
||||
view.setGridProgress(gridProgress);
|
||||
@@ -457,7 +457,7 @@ public abstract class RecentsView<
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<RecentsView> DESKTOP_CAROUSEL_DETACH_PROGRESS =
|
||||
public static final FloatProperty<RecentsView<?, ?>> DESKTOP_CAROUSEL_DETACH_PROGRESS =
|
||||
new FloatProperty<>("desktopCarouselDetachProgress") {
|
||||
@Override
|
||||
public void setValue(RecentsView view, float offset) {
|
||||
@@ -476,8 +476,8 @@ public abstract class RecentsView<
|
||||
* Alpha of the task thumbnail splash, where being in BackgroundAppState has a value of 1, and
|
||||
* being in any other state has a value of 0.
|
||||
*/
|
||||
public static final FloatProperty<RecentsView> TASK_THUMBNAIL_SPLASH_ALPHA =
|
||||
new FloatProperty<RecentsView>("taskThumbnailSplashAlpha") {
|
||||
public static final FloatProperty<RecentsView<?, ?>> TASK_THUMBNAIL_SPLASH_ALPHA =
|
||||
new FloatProperty<>("taskThumbnailSplashAlpha") {
|
||||
@Override
|
||||
public void setValue(RecentsView view, float taskThumbnailSplashAlpha) {
|
||||
view.setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha);
|
||||
@@ -5484,7 +5484,7 @@ public abstract class RecentsView<
|
||||
firstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
|
||||
|
||||
RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
|
||||
Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
|
||||
Pair<FloatProperty<RecentsView<?, ?>>, FloatProperty<RecentsView<?, ?>>> taskViewsFloat =
|
||||
orientationHandler.getSplitSelectTaskOffset(
|
||||
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
|
||||
mContainer.getDeviceProfile());
|
||||
|
||||
Reference in New Issue
Block a user