• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.launcher3.uioverrides;
17 
18 import static com.android.app.animation.Interpolators.LINEAR;
19 import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
20 import static com.android.launcher3.LauncherState.OVERVIEW;
21 import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
22 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
23 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
24 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
25 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
26 import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
27 import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
28 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
29 import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
30 import static com.android.wm.shell.Flags.enableSplitContextual;
31 
32 import android.animation.AnimatorSet;
33 import android.annotation.TargetApi;
34 import android.os.Build;
35 import android.util.FloatProperty;
36 import android.util.Log;
37 import android.util.Pair;
38 
39 import androidx.annotation.NonNull;
40 
41 import com.android.launcher3.LauncherState;
42 import com.android.launcher3.Utilities;
43 import com.android.launcher3.anim.AnimatedFloat;
44 import com.android.launcher3.anim.AnimatorListeners;
45 import com.android.launcher3.anim.PendingAnimation;
46 import com.android.launcher3.anim.PropertySetter;
47 import com.android.launcher3.states.StateAnimationConfig;
48 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
49 import com.android.quickstep.util.AnimUtils;
50 import com.android.quickstep.util.SplitAnimationTimings;
51 import com.android.quickstep.views.ClearAllButton;
52 import com.android.quickstep.views.LauncherRecentsView;
53 import com.android.quickstep.views.RecentsView;
54 
55 /**
56  * State handler for handling UI changes for {@link LauncherRecentsView}. In addition to managing
57  * the basic view properties, this class also manages changes in the task visuals.
58  */
59 @TargetApi(Build.VERSION_CODES.O)
60 public final class RecentsViewStateController extends
61         BaseRecentsViewStateController<LauncherRecentsView> {
62 
RecentsViewStateController(QuickstepLauncher launcher)63     public RecentsViewStateController(QuickstepLauncher launcher) {
64         super(launcher);
65     }
66 
67     @Override
setState(@onNull LauncherState state)68     public void setState(@NonNull LauncherState state) {
69         super.setState(state);
70         if (state.isRecentsViewVisible) {
71             mRecentsView.updateEmptyMessage();
72         } else {
73             mRecentsView.resetTaskVisuals();
74         }
75         setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
76         mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
77         // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
78         // DepthController to prevent optimizations which might occlude the layers behind
79         mLauncher.getDepthController().setHasContentBehindLauncher(state.isRecentsViewVisible);
80 
81         PendingAnimation builder =
82                 new PendingAnimation(state.getTransitionDuration(mLauncher, true));
83 
84         handleSplitSelectionState(state, builder, /* animate */false);
85     }
86 
87     @Override
setStateWithAnimationInternal(@onNull LauncherState toState, @NonNull StateAnimationConfig config, @NonNull PendingAnimation builder)88     void setStateWithAnimationInternal(@NonNull LauncherState toState,
89             @NonNull StateAnimationConfig config, @NonNull PendingAnimation builder) {
90         super.setStateWithAnimationInternal(toState, config, builder);
91 
92         if (toState.isRecentsViewVisible) {
93             // While animating into recents, update the visible task data as needed
94             builder.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL));
95             mRecentsView.updateEmptyMessage();
96             // TODO(b/246283207): Remove logging once root cause of flake detected.
97             if (Utilities.isRunningInTestHarness()) {
98                 Log.d("b/246283207", "RecentsView#setStateWithAnimationInternal getCurrentPage(): "
99                                 + mRecentsView.getCurrentPage()
100                                 + ", getScrollForPage(getCurrentPage())): "
101                                 + mRecentsView.getScrollForPage(mRecentsView.getCurrentPage()));
102             }
103         } else {
104             builder.addListener(
105                     AnimatorListeners.forSuccessCallback(mRecentsView::resetTaskVisuals));
106         }
107         // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
108         // DepthController to prevent optimizations which might occlude the layers behind
109         builder.addListener(AnimatorListeners.forSuccessCallback(() ->
110                 mLauncher.getDepthController().setHasContentBehindLauncher(
111                         toState.isRecentsViewVisible)));
112 
113         handleSplitSelectionState(toState, builder, /* animate */true);
114 
115         setAlphas(builder, config, toState);
116         builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
117                 toState.getOverviewFullscreenProgress(), LINEAR);
118     }
119 
120     /**
121      * Create or dismiss split screen select animations.
122      * @param builder if null then this will run the split select animations right away, otherwise
123      *                will add animations to builder.
124      */
handleSplitSelectionState(@onNull LauncherState toState, @NonNull PendingAnimation builder, boolean animate)125     private void handleSplitSelectionState(@NonNull LauncherState toState,
126             @NonNull PendingAnimation builder, boolean animate) {
127         boolean goingToOverviewFromWorkspaceContextual = enableSplitContextual() &&
128                 toState == OVERVIEW && mLauncher.isSplitSelectionActive();
129         if (toState != OVERVIEW_SPLIT_SELECT && !goingToOverviewFromWorkspaceContextual) {
130             // Not going to split
131             return;
132         }
133 
134         // Create transition animations to split select
135         RecentsPagedOrientationHandler orientationHandler =
136                 ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
137         Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
138                 orientationHandler.getSplitSelectTaskOffset(
139                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
140                         mLauncher.getDeviceProfile());
141 
142         SplitAnimationTimings timings =
143                 AnimUtils.getDeviceOverviewToSplitTimings(mLauncher.getDeviceProfile().isTablet);
144         if (!goingToOverviewFromWorkspaceContextual) {
145             // This animation is already done for the contextual case, don't redo it
146             mRecentsView.createSplitSelectInitAnimation(builder,
147                     toState.getTransitionDuration(mLauncher, true /* isToState */));
148         }
149         // Shift tasks vertically downward to get out of placeholder view
150         builder.setFloat(mRecentsView, taskViewsFloat.first,
151                 toState.getSplitSelectTranslation(mLauncher),
152                 timings.getGridSlidePrimaryInterpolator());
153         // Zero out horizontal translation
154         builder.setFloat(mRecentsView, taskViewsFloat.second,
155                 0,
156                 timings.getGridSlideSecondaryInterpolator());
157 
158         if (!animate) {
159             AnimatorSet as = builder.buildAnim();
160             as.start();
161             as.end();
162         }
163     }
164 
setAlphas(PropertySetter propertySetter, StateAnimationConfig config, LauncherState state)165     private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
166             LauncherState state) {
167         float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
168         propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
169                 clearAllButtonAlpha, LINEAR);
170         float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
171         propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
172                 AnimatedFloat.VALUE, overviewButtonAlpha, config.getInterpolator(
173                         ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
174     }
175 
176     @Override
getTaskModalnessProperty()177     FloatProperty<RecentsView> getTaskModalnessProperty() {
178         return TASK_MODALNESS;
179     }
180 
181     @Override
getContentAlphaProperty()182     FloatProperty<RecentsView> getContentAlphaProperty() {
183         return CONTENT_ALPHA;
184     }
185 }
186