1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.quickstep.fallback; 17 18 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; 19 import static com.android.launcher3.anim.Interpolators.INSTANT; 20 import static com.android.launcher3.anim.Interpolators.LINEAR; 21 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL; 22 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; 23 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; 24 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; 25 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE; 26 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; 27 import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT; 28 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET; 29 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; 30 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; 31 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; 32 import static com.android.quickstep.views.RecentsView.TASK_MODALNESS; 33 import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION; 34 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION; 35 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION; 36 import static com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA; 37 import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL; 38 39 import android.util.FloatProperty; 40 import android.util.Pair; 41 42 import androidx.annotation.NonNull; 43 44 import com.android.launcher3.anim.PendingAnimation; 45 import com.android.launcher3.anim.PropertySetter; 46 import com.android.launcher3.statemanager.StateManager.StateHandler; 47 import com.android.launcher3.states.StateAnimationConfig; 48 import com.android.launcher3.util.MultiPropertyFactory; 49 import com.android.quickstep.RecentsActivity; 50 import com.android.quickstep.views.ClearAllButton; 51 52 /** 53 * State controller for fallback recents activity 54 */ 55 public class FallbackRecentsStateController implements StateHandler<RecentsState> { 56 57 private final StateAnimationConfig mNoConfig = new StateAnimationConfig(); 58 private final RecentsActivity mActivity; 59 private final FallbackRecentsView mRecentsView; 60 FallbackRecentsStateController(RecentsActivity activity)61 public FallbackRecentsStateController(RecentsActivity activity) { 62 mActivity = activity; 63 mRecentsView = activity.getOverviewPanel(); 64 } 65 66 @Override setState(RecentsState state)67 public void setState(RecentsState state) { 68 mRecentsView.updateEmptyMessage(); 69 mRecentsView.resetTaskVisuals(); 70 setProperties(state, mNoConfig, PropertySetter.NO_ANIM_PROPERTY_SETTER); 71 } 72 73 @Override setStateWithAnimation(RecentsState toState, StateAnimationConfig config, PendingAnimation setter)74 public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config, 75 PendingAnimation setter) { 76 if (config.hasAnimationFlag(SKIP_OVERVIEW)) { 77 return; 78 } 79 // While animating into recents, update the visible task data as needed 80 setter.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL)); 81 setter.addEndListener(success -> { 82 if (!success) { 83 mRecentsView.reset(); 84 } 85 }); 86 mRecentsView.updateEmptyMessage(); 87 88 setProperties(toState, config, setter); 89 } 90 setProperties(RecentsState state, StateAnimationConfig config, PropertySetter setter)91 private void setProperties(RecentsState state, StateAnimationConfig config, 92 PropertySetter setter) { 93 float clearAllButtonAlpha = state.hasClearAllButton() ? 1 : 0; 94 setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA, 95 clearAllButtonAlpha, LINEAR); 96 float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0; 97 setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(), 98 MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR); 99 100 float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity); 101 setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0], 102 config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR)); 103 setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], 104 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR)); 105 setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f, 106 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); 107 108 setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(), 109 config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR)); 110 setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR); 111 boolean showAsGrid = state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()); 112 setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f, 113 showAsGrid ? INSTANT : FINAL_FRAME); 114 setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA, 115 state.showTaskThumbnailSplash() ? 1f : 0f, INSTANT); 116 117 setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity), 118 config.getInterpolator(ANIM_SCRIM_FADE, LINEAR)); 119 120 RecentsState currentState = mActivity.getStateManager().getState(); 121 if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) { 122 int duration = state.getTransitionDuration(mActivity, true /* isToState */); 123 // TODO (b/246851887): Pass in setter as a NO_ANIM PendingAnimation instead 124 PendingAnimation pa = new PendingAnimation(duration); 125 mRecentsView.createSplitSelectInitAnimation(pa, duration); 126 setter.add(pa.buildAnim()); 127 } 128 129 Pair<FloatProperty, FloatProperty> taskViewsFloat = 130 mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset( 131 TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION, 132 mActivity.getDeviceProfile()); 133 setter.setFloat(mRecentsView, taskViewsFloat.first, isSplitSelectionState(state) 134 ? mRecentsView.getSplitSelectTranslation() : 0, LINEAR); 135 setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR); 136 } 137 138 /** 139 * @return true if {@param toState} is {@link RecentsState#OVERVIEW_SPLIT_SELECT} 140 */ isSplitSelectionState(@onNull RecentsState toState)141 private boolean isSplitSelectionState(@NonNull RecentsState toState) { 142 return toState == OVERVIEW_SPLIT_SELECT; 143 } 144 } 145