• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE;
20 
21 import static com.android.app.animation.Interpolators.ACCELERATE_2;
22 import static com.android.app.animation.Interpolators.LINEAR;
23 import static com.android.app.animation.Interpolators.ZOOM_OUT;
24 import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
25 import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE;
26 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
27 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
28 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
29 import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY;
30 import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
31 import static com.android.launcher3.LauncherState.FLAG_HOTSEAT_INACCESSIBLE;
32 import static com.android.launcher3.LauncherState.HINT_STATE;
33 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
34 import static com.android.launcher3.LauncherState.NORMAL;
35 import static com.android.launcher3.LauncherState.WORKSPACE_PAGE_INDICATOR;
36 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
37 import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
38 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
39 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
40 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
41 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
42 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
43 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_PAGE_TRANSLATE_X;
44 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
45 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
46 import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
47 
48 import android.animation.ValueAnimator;
49 import android.util.FloatProperty;
50 import android.view.View;
51 import android.view.animation.Interpolator;
52 
53 import com.android.launcher3.LauncherState.PageAlphaProvider;
54 import com.android.launcher3.LauncherState.PageTranslationProvider;
55 import com.android.launcher3.LauncherState.ScaleAndTranslation;
56 import com.android.launcher3.anim.AnimatedFloat;
57 import com.android.launcher3.anim.PendingAnimation;
58 import com.android.launcher3.anim.PropertySetter;
59 import com.android.launcher3.anim.SpringAnimationBuilder;
60 import com.android.launcher3.graphics.Scrim;
61 import com.android.launcher3.graphics.SysUiScrim;
62 import com.android.launcher3.states.EditModeState;
63 import com.android.launcher3.states.SpringLoadedState;
64 import com.android.launcher3.states.StateAnimationConfig;
65 import com.android.launcher3.util.DynamicResource;
66 import com.android.systemui.plugins.ResourceProvider;
67 
68 /**
69  * Manages the animations between each of the workspace states.
70  */
71 public class WorkspaceStateTransitionAnimation {
72 
73     private static final float FIRST_PAGE_PINNED_WIDGET_DISABLED_ALPHA = 0.3f;
74 
75     private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY =
76             WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
77 
78     private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
79             HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
80 
81     private final Launcher mLauncher;
82     private final Workspace<?> mWorkspace;
83 
84     private float mNewScale;
85 
WorkspaceStateTransitionAnimation(Launcher launcher, Workspace<?> workspace)86     public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace<?> workspace) {
87         mLauncher = launcher;
88         mWorkspace = workspace;
89     }
90 
setState(LauncherState toState)91     public void setState(LauncherState toState) {
92         setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
93     }
94 
95     /**
96      * @see com.android.launcher3.statemanager.StateManager.StateHandler#setStateWithAnimation
97      */
setStateWithAnimation( LauncherState toState, StateAnimationConfig config, PendingAnimation animation)98     public void setStateWithAnimation(
99             LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
100         setWorkspaceProperty(toState, animation, config);
101     }
102 
getFinalScale()103     public float getFinalScale() {
104         return mNewScale;
105     }
106 
107     /**
108      * Starts a transition animation for the workspace.
109      */
setWorkspaceProperty(LauncherState state, PropertySetter propertySetter, StateAnimationConfig config)110     private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
111             StateAnimationConfig config) {
112         ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
113         ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
114                 mLauncher);
115         mNewScale = scaleAndTranslation.scale;
116         PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
117         final int childCount = mWorkspace.getChildCount();
118         for (int i = 0; i < childCount; i++) {
119             applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
120                     propertySetter, config);
121         }
122 
123         int elements = state.getVisibleElements(mLauncher);
124         Hotseat hotseat = mWorkspace.getHotseat();
125         Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
126         LauncherState fromState = mLauncher.getStateManager().getState();
127 
128         boolean shouldSpring = propertySetter instanceof PendingAnimation
129                 && fromState == HINT_STATE && state == NORMAL;
130         if (shouldSpring) {
131             ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
132                     mWorkspace, mNewScale, WORKSPACE_SCALE_PROPERTY));
133         } else {
134             propertySetter.setFloat(mWorkspace, WORKSPACE_SCALE_PROPERTY, mNewScale,
135                     scaleInterpolator);
136         }
137 
138         mWorkspace.setPivotToScaleWithSelf(hotseat);
139         float hotseatScale = hotseatScaleAndTranslation.scale;
140         if (shouldSpring) {
141             PendingAnimation pa = (PendingAnimation) propertySetter;
142             pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale,
143                     HOTSEAT_SCALE_PROPERTY));
144         } else {
145             Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
146                     scaleInterpolator);
147             propertySetter.setFloat(hotseat, HOTSEAT_SCALE_PROPERTY, hotseatScale,
148                     hotseatScaleInterpolator);
149         }
150 
151         Interpolator workspaceFadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
152                 pageAlphaProvider.interpolator);
153         float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
154         propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
155                 workspacePageIndicatorAlpha, workspaceFadeInterpolator);
156         Interpolator hotseatFadeInterpolator = config.getInterpolator(ANIM_HOTSEAT_FADE,
157                 workspaceFadeInterpolator);
158         float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
159         propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, hotseatFadeInterpolator);
160 
161         // Update the accessibility flags for hotseat based on launcher state.
162         hotseat.setImportantForAccessibility(
163                 state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
164                         ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
165                         : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
166 
167         Interpolator translationInterpolator =
168                 config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
169         propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X,
170                 scaleAndTranslation.translationX, translationInterpolator);
171         propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
172                 scaleAndTranslation.translationY, translationInterpolator);
173         PageTranslationProvider pageTranslationProvider = state.getWorkspacePageTranslationProvider(
174                 mLauncher);
175         for (int i = 0; i < childCount; i++) {
176             applyPageTranslation((CellLayout) mWorkspace.getChildAt(i), i, pageTranslationProvider,
177                     propertySetter, config);
178         }
179 
180         Interpolator hotseatTranslationInterpolator = config.getInterpolator(
181                 ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
182         propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y,
183                 hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
184         propertySetter.setFloat(mWorkspace.getPageIndicator(), VIEW_TRANSLATE_Y,
185                 hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
186 
187         if (!config.hasAnimationFlag(SKIP_SCRIM)) {
188             setScrim(propertySetter, state, config);
189         }
190     }
191 
setScrim(PropertySetter propertySetter, LauncherState state, StateAnimationConfig config)192     public void setScrim(PropertySetter propertySetter, LauncherState state,
193             StateAnimationConfig config) {
194         Scrim workspaceDragScrim = mLauncher.getDragLayer().getWorkspaceDragScrim();
195         propertySetter.setFloat(workspaceDragScrim, SCRIM_PROGRESS,
196                 state.getWorkspaceBackgroundAlpha(mLauncher), LINEAR);
197 
198         SysUiScrim sysUiScrim = mLauncher.getRootView().getSysUiScrim();
199         propertySetter.setFloat(sysUiScrim.getSysUIProgress(), AnimatedFloat.VALUE,
200                 state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
201 
202         propertySetter.setViewBackgroundColor(mLauncher.getScrimView(),
203                 state.getWorkspaceScrimColor(mLauncher),
204                 config.getInterpolator(ANIM_SCRIM_FADE, ACCELERATE_2));
205     }
206 
applyChildState(LauncherState state, CellLayout cl, int childIndex)207     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
208         applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
209                 NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
210     }
211 
applyChildState(LauncherState state, CellLayout cl, int childIndex, PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter, StateAnimationConfig config)212     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
213             PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
214             StateAnimationConfig config) {
215         float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
216         float springLoadedProgress =
217                 (state instanceof  SpringLoadedState || state instanceof EditModeState) ? 1f : 0f;
218         propertySetter.setFloat(cl,
219                 CellLayout.SPRING_LOADED_PROGRESS, springLoadedProgress, ZOOM_OUT);
220         Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
221                 pageAlphaProvider.interpolator);
222         propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
223                 pageAlpha, fadeInterpolator);
224     }
225 
applyPageTranslation(CellLayout cellLayout, int childIndex, PageTranslationProvider pageTranslationProvider, PropertySetter propertySetter, StateAnimationConfig config)226     private void applyPageTranslation(CellLayout cellLayout, int childIndex,
227             PageTranslationProvider pageTranslationProvider, PropertySetter propertySetter,
228             StateAnimationConfig config) {
229         float pageTranslation = pageTranslationProvider.getPageTranslation(childIndex);
230         Interpolator translationInterpolator = config.getInterpolator(
231                 ANIM_WORKSPACE_PAGE_TRANSLATE_X, pageTranslationProvider.interpolator);
232         propertySetter.setFloat(cellLayout, VIEW_TRANSLATE_X, pageTranslation,
233                 translationInterpolator);
234     }
235 
236     /**
237      * Returns a spring based animator for the scale property of {@param workspace}.
238      */
getWorkspaceSpringScaleAnimator(Launcher launcher, Workspace<?> workspace, float scale)239     public static ValueAnimator getWorkspaceSpringScaleAnimator(Launcher launcher,
240             Workspace<?> workspace, float scale) {
241         return getSpringScaleAnimator(launcher, workspace, scale, WORKSPACE_SCALE_PROPERTY);
242     }
243 
244     /**
245      * Returns a spring based animator for the scale property of {@param v}.
246      */
getSpringScaleAnimator(Launcher launcher, T v, float scale, FloatProperty<T> property)247     public static <T extends View> ValueAnimator getSpringScaleAnimator(Launcher launcher, T v,
248             float scale, FloatProperty<T> property) {
249         ResourceProvider rp = DynamicResource.provider(launcher);
250         float damping = rp.getFloat(R.dimen.hint_scale_damping_ratio);
251         float stiffness = rp.getFloat(R.dimen.hint_scale_stiffness);
252         float velocityPxPerS = rp.getDimension(R.dimen.hint_scale_velocity_dp_per_s);
253 
254         return new SpringAnimationBuilder(v.getContext())
255                 .setStiffness(stiffness)
256                 .setDampingRatio(damping)
257                 .setMinimumVisibleChange(MIN_VISIBLE_CHANGE_SCALE)
258                 .setEndValue(scale)
259                 .setStartValue(property.get(v))
260                 .setStartVelocity(velocityPxPerS)
261                 .build(v, property);
262 
263     }
264 }