1 /* 2 * Copyright (C) 2019 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 17 package com.android.launcher3.uioverrides; 18 19 import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME; 20 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT; 21 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; 22 import static com.android.launcher3.anim.Interpolators.INSTANT; 23 import static com.android.launcher3.anim.Interpolators.LINEAR; 24 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; 25 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL; 26 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; 27 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN; 28 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE; 29 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; 30 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; 31 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; 32 import static com.android.quickstep.views.FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN; 33 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET; 34 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; 35 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; 36 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION; 37 import static com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA; 38 39 import android.graphics.Rect; 40 import android.graphics.RectF; 41 import android.util.FloatProperty; 42 import android.view.animation.Interpolator; 43 44 import androidx.annotation.NonNull; 45 46 import com.android.launcher3.LauncherState; 47 import com.android.launcher3.Utilities; 48 import com.android.launcher3.anim.PendingAnimation; 49 import com.android.launcher3.dragndrop.DragLayer; 50 import com.android.launcher3.statemanager.StateManager.StateHandler; 51 import com.android.launcher3.states.StateAnimationConfig; 52 import com.android.quickstep.views.FloatingTaskView; 53 import com.android.quickstep.views.RecentsView; 54 55 /** 56 * State handler for recents view. Manages UI changes and animations for recents view based off the 57 * current {@link LauncherState}. 58 * 59 * @param <T> the recents view 60 */ 61 public abstract class BaseRecentsViewStateController<T extends RecentsView> 62 implements StateHandler<LauncherState> { 63 protected final T mRecentsView; 64 protected final QuickstepLauncher mLauncher; 65 BaseRecentsViewStateController(@onNull QuickstepLauncher launcher)66 public BaseRecentsViewStateController(@NonNull QuickstepLauncher launcher) { 67 mLauncher = launcher; 68 mRecentsView = launcher.getOverviewPanel(); 69 } 70 71 @Override setState(@onNull LauncherState state)72 public void setState(@NonNull LauncherState state) { 73 float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher); 74 RECENTS_SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]); 75 ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, scaleAndOffset[1]); 76 TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f); 77 78 getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0); 79 getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness()); 80 RECENTS_GRID_PROGRESS.set(mRecentsView, 81 state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f); 82 TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, state.showTaskThumbnailSplash() ? 1f : 0f); 83 } 84 85 @Override setStateWithAnimation(LauncherState toState, StateAnimationConfig config, PendingAnimation builder)86 public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, 87 PendingAnimation builder) { 88 if (config.hasAnimationFlag(SKIP_OVERVIEW)) { 89 return; 90 } 91 setStateWithAnimationInternal(toState, config, builder); 92 builder.addEndListener(success -> { 93 if (!success) { 94 mRecentsView.reset(); 95 } 96 }); 97 } 98 99 /** 100 * Core logic for animating the recents view UI. 101 * 102 * @param toState state to animate to 103 * @param config current animation config 104 * @param setter animator set builder 105 */ setStateWithAnimationInternal(@onNull final LauncherState toState, @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter)106 void setStateWithAnimationInternal(@NonNull final LauncherState toState, 107 @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) { 108 float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher); 109 setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0], 110 config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR)); 111 setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], 112 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR)); 113 setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f, 114 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); 115 116 if (mRecentsView.isSplitSelectionActive()) { 117 // TODO (b/238651489): Refactor state management to avoid need for double check 118 FloatingTaskView floatingTask = mRecentsView.getFirstFloatingTaskView(); 119 if (floatingTask != null) { 120 // We are in split selection state currently, transitioning to another state 121 DragLayer dragLayer = mLauncher.getDragLayer(); 122 RectF onScreenRectF = new RectF(); 123 Utilities.getBoundsForViewInDragLayer(mLauncher.getDragLayer(), floatingTask, 124 new Rect(0, 0, floatingTask.getWidth(), floatingTask.getHeight()), 125 false, null, onScreenRectF); 126 // Get the part of the floatingTask that intersects with the DragLayer (i.e. the 127 // on-screen portion) 128 onScreenRectF.intersect( 129 dragLayer.getLeft(), 130 dragLayer.getTop(), 131 dragLayer.getRight(), 132 dragLayer.getBottom() 133 ); 134 135 setter.setFloat( 136 mRecentsView.getFirstFloatingTaskView(), 137 PRIMARY_TRANSLATE_OFFSCREEN, 138 mRecentsView.getPagedOrientationHandler() 139 .getFloatingTaskOffscreenTranslationTarget( 140 floatingTask, 141 onScreenRectF, 142 floatingTask.getStagePosition(), 143 mLauncher.getDeviceProfile() 144 ), 145 config.getInterpolator( 146 ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN, 147 LINEAR 148 )); 149 setter.setViewAlpha( 150 mRecentsView.getSplitInstructionsView(), 151 0, 152 config.getInterpolator( 153 ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE, 154 LINEAR 155 ) 156 ); 157 } 158 } 159 160 setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0, 161 config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); 162 163 setter.setFloat( 164 mRecentsView, getTaskModalnessProperty(), 165 toState.getOverviewModalness(), 166 config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR)); 167 168 LauncherState fromState = mLauncher.getStateManager().getState(); 169 setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA, 170 toState.showTaskThumbnailSplash() ? 1f : 0f, 171 !toState.showTaskThumbnailSplash() && fromState == QUICK_SWITCH_FROM_HOME 172 ? LINEAR : INSTANT); 173 174 boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()); 175 Interpolator gridProgressInterpolator = showAsGrid 176 ? fromState == QUICK_SWITCH_FROM_HOME ? LINEAR : INSTANT 177 : FINAL_FRAME; 178 setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f, 179 gridProgressInterpolator); 180 } 181 getTaskModalnessProperty()182 abstract FloatProperty getTaskModalnessProperty(); 183 184 /** 185 * Get property for content alpha for the recents view. 186 * 187 * @return the float property for the view's content alpha 188 */ getContentAlphaProperty()189 abstract FloatProperty getContentAlphaProperty(); 190 } 191