blob: 8edec40d24a7b4eb88666610605497cbf5f68de2 [file] [log] [blame]
Winson Chungdc61c4d2015-04-20 18:26:57 -07001/*
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
17package com.android.launcher3;
18
Sunny Goyalaeb16432017-10-16 11:46:41 -070019import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
20import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
21
Winson Chungdc61c4d2015-04-20 18:26:57 -070022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
24import android.animation.AnimatorSet;
Sunny Goyal4f3e9382015-06-05 00:13:25 -070025import android.animation.ObjectAnimator;
Winson Chungdc61c4d2015-04-20 18:26:57 -070026import android.animation.TimeInterpolator;
27import android.animation.ValueAnimator;
28import android.content.Context;
29import android.content.res.Resources;
Sunny Goyalaeb16432017-10-16 11:46:41 -070030import android.util.Property;
Winson Chungdc61c4d2015-04-20 18:26:57 -070031import android.view.View;
32import android.view.accessibility.AccessibilityManager;
Sunny Goyal1d08f702015-05-04 15:50:25 -070033
Sunny Goyal3e3f44c2017-10-23 17:14:52 -070034import com.android.launcher3.LauncherStateManager.AnimationConfig;
Sunny Goyalb5e65c82016-10-26 18:32:38 -070035import com.android.launcher3.anim.AnimationLayerSet;
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -070036import com.android.launcher3.anim.Interpolators;
Winson Chungdc61c4d2015-04-20 18:26:57 -070037
Winson Chungdc61c4d2015-04-20 18:26:57 -070038/**
39 * A convenience class to update a view's visibility state after an alpha animation.
40 */
41class AlphaUpdateListener extends AnimatorListenerAdapter implements ValueAnimator.AnimatorUpdateListener {
42 private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
43
44 private View mView;
45 private boolean mAccessibilityEnabled;
Hyunyoung Songeac1dac2016-06-21 16:37:13 -070046 private boolean mCanceled = false;
Winson Chungdc61c4d2015-04-20 18:26:57 -070047
48 public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
49 mView = v;
50 mAccessibilityEnabled = accessibilityEnabled;
51 }
52
53 @Override
54 public void onAnimationUpdate(ValueAnimator arg0) {
55 updateVisibility(mView, mAccessibilityEnabled);
56 }
57
58 public static void updateVisibility(View view, boolean accessibilityEnabled) {
59 // We want to avoid the extra layout pass by setting the views to GONE unless
60 // accessibility is on, in which case not setting them to GONE causes a glitch.
61 int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
62 if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
63 view.setVisibility(invisibleState);
64 } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
65 && view.getVisibility() != View.VISIBLE) {
66 view.setVisibility(View.VISIBLE);
67 }
68 }
69
70 @Override
Hyunyoung Songeac1dac2016-06-21 16:37:13 -070071 public void onAnimationCancel(Animator animation) {
72 mCanceled = true;
73 }
74
75 @Override
Winson Chungdc61c4d2015-04-20 18:26:57 -070076 public void onAnimationEnd(Animator arg0) {
Hyunyoung Songeac1dac2016-06-21 16:37:13 -070077 if (mCanceled) return;
Winson Chungdc61c4d2015-04-20 18:26:57 -070078 updateVisibility(mView, mAccessibilityEnabled);
79 }
80
81 @Override
82 public void onAnimationStart(Animator arg0) {
83 // We want the views to be visible for animation, so fade-in/out is visible
84 mView.setVisibility(View.VISIBLE);
85 }
86}
87
88/**
Winson Chungdc61c4d2015-04-20 18:26:57 -070089 * Manages the animations between each of the workspace states.
90 */
91public class WorkspaceStateTransitionAnimation {
92
Sunny Goyalc4fa8c32017-11-07 12:23:58 -080093 public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
Winson Chungdc61c4d2015-04-20 18:26:57 -070094
Sunny Goyalaeb16432017-10-16 11:46:41 -070095 public final int mWorkspaceScrimAlpha;
Winson Chungdc61c4d2015-04-20 18:26:57 -070096
Sunny Goyalaeb16432017-10-16 11:46:41 -070097 private final Launcher mLauncher;
98 private final Workspace mWorkspace;
Winson Chungdc61c4d2015-04-20 18:26:57 -070099
Sunny Goyalaeb16432017-10-16 11:46:41 -0700100 private final boolean mWorkspaceFadeInAdjacentScreens;
Winson Chungdc61c4d2015-04-20 18:26:57 -0700101
Sunny Goyalaeb16432017-10-16 11:46:41 -0700102 private float mNewScale;
Winson Chungdc61c4d2015-04-20 18:26:57 -0700103
104 public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
105 mLauncher = launcher;
106 mWorkspace = workspace;
107
Adam Cohen2e6da152015-05-06 11:42:25 -0700108 DeviceProfile grid = mLauncher.getDeviceProfile();
Winson Chungdc61c4d2015-04-20 18:26:57 -0700109 Resources res = launcher.getResources();
Sunny Goyalaeb16432017-10-16 11:46:41 -0700110 mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha);
Winson Chungdc61c4d2015-04-20 18:26:57 -0700111 mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
112 }
113
Sunny Goyal4c7f2152017-10-17 17:17:16 -0700114 public void setState(LauncherState toState) {
Sunny Goyalaeb16432017-10-16 11:46:41 -0700115 setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER);
Sunny Goyalce5a7e52015-07-08 15:44:27 -0700116 }
117
Sunny Goyalea609262017-10-25 15:47:38 -0700118 public void setStateWithAnimation(LauncherState toState, AnimatorSet anim,
119 AnimationLayerSet layerViews, AnimationConfig config) {
Sunny Goyal4c7f2152017-10-17 17:17:16 -0700120 AnimatedPropertySetter propertySetter =
Sunny Goyalea609262017-10-25 15:47:38 -0700121 new AnimatedPropertySetter(config.duration, layerViews, anim);
Sunny Goyal4c7f2152017-10-17 17:17:16 -0700122 setWorkspaceProperty(toState, propertySetter);
Winson Chungdc61c4d2015-04-20 18:26:57 -0700123 }
124
125 public float getFinalScale() {
126 return mNewScale;
127 }
128
129 /**
130 * Starts a transition animation for the workspace.
131 */
Sunny Goyal4c7f2152017-10-17 17:17:16 -0700132 private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter) {
Sunny Goyalc99cb172017-10-19 16:15:09 -0700133 float[] scaleAndTranslationY = state.getWorkspaceScaleAndTranslation(mLauncher);
Sunny Goyal2104c302017-10-23 15:04:10 -0700134 mNewScale = scaleAndTranslationY[0];
Sunny Goyalc99cb172017-10-19 16:15:09 -0700135 final float finalWorkspaceTranslationY = scaleAndTranslationY[1];
Winson Chungdc61c4d2015-04-20 18:26:57 -0700136
Sunny Goyalce5a7e52015-07-08 15:44:27 -0700137 int toPage = mWorkspace.getPageNearestToCenterOfScreen();
Sunny Goyalaeb16432017-10-16 11:46:41 -0700138 final int childCount = mWorkspace.getChildCount();
Winson Chungdc61c4d2015-04-20 18:26:57 -0700139 for (int i = 0; i < childCount; i++) {
Sunny Goyal4d519f22017-10-24 10:32:40 -0700140 applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, toPage,
141 propertySetter);
Winson Chungdc61c4d2015-04-20 18:26:57 -0700142 }
143
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700144 propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_IN);
Sunny Goyalaeb16432017-10-16 11:46:41 -0700145 propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700146 finalWorkspaceTranslationY, Interpolators.ZOOM_IN);
Jon Miranda7f522a22017-07-28 11:56:47 -0700147
Sunny Goyalaeb16432017-10-16 11:46:41 -0700148 // Set scrim
149 propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA,
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700150 state.hasScrim ? mWorkspaceScrimAlpha : 0, Interpolators.DEACCEL_1_5);
Sunny Goyalaeb16432017-10-16 11:46:41 -0700151 }
152
Sunny Goyal4d519f22017-10-24 10:32:40 -0700153 public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
154 applyChildState(state, cl, childIndex, mWorkspace.getPageNearestToCenterOfScreen(),
155 NO_ANIM_PROPERTY_SETTER);
156 }
157
158 private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
159 int centerPage, PropertySetter propertySetter) {
160 propertySetter.setInt(cl.getScrimBackground(),
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700161 DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN);
Sunny Goyal4d519f22017-10-24 10:32:40 -0700162
163 // Only animate the page alpha when we actually fade pages
164 if (mWorkspaceFadeInAdjacentScreens) {
165 float finalAlpha = state == LauncherState.NORMAL && childIndex != centerPage ? 0 : 1f;
166 propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700167 finalAlpha, Interpolators.ZOOM_IN);
Sunny Goyal4d519f22017-10-24 10:32:40 -0700168 }
169 }
170
Sunny Goyalc4fa8c32017-11-07 12:23:58 -0800171 public static class PropertySetter {
Sunny Goyalaeb16432017-10-16 11:46:41 -0700172
173 public void setViewAlpha(Animator anim, View view, float alpha) {
174 if (anim != null) {
175 anim.end();
176 return;
Jon Miranda7f522a22017-07-28 11:56:47 -0700177 }
Sunny Goyalaeb16432017-10-16 11:46:41 -0700178 view.setAlpha(alpha);
179 AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view));
180 }
Jon Miranda7f522a22017-07-28 11:56:47 -0700181
Sunny Goyalaeb16432017-10-16 11:46:41 -0700182 public <T> void setFloat(T target, Property<T, Float> property, float value,
183 TimeInterpolator interpolator) {
184 property.set(target, value);
185 }
Winson Chungdc61c4d2015-04-20 18:26:57 -0700186
Sunny Goyalaeb16432017-10-16 11:46:41 -0700187 public <T> void setInt(T target, Property<T, Integer> property, int value,
188 TimeInterpolator interpolator) {
189 property.set(target, value);
190 }
Winson Chungdc61c4d2015-04-20 18:26:57 -0700191
Sunny Goyalaeb16432017-10-16 11:46:41 -0700192 protected boolean isAccessibilityEnabled(View v) {
193 AccessibilityManager am = (AccessibilityManager)
194 v.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
195 return am.isEnabled();
Winson Chungdc61c4d2015-04-20 18:26:57 -0700196 }
Winson Chungdc61c4d2015-04-20 18:26:57 -0700197 }
198
Sunny Goyalc4fa8c32017-11-07 12:23:58 -0800199 public static class AnimatedPropertySetter extends PropertySetter {
Hyunyoung Song7eea78a2015-06-23 15:02:33 -0700200
Sunny Goyalaeb16432017-10-16 11:46:41 -0700201 private final long mDuration;
202 private final AnimationLayerSet mLayerViews;
203 private final AnimatorSet mStateAnimator;
Hyunyoung Song5796b032015-06-19 18:03:35 -0700204
Sunny Goyalc4fa8c32017-11-07 12:23:58 -0800205 public AnimatedPropertySetter(
206 long duration, AnimationLayerSet layerView, AnimatorSet anim) {
Sunny Goyalaeb16432017-10-16 11:46:41 -0700207 mDuration = duration;
208 mLayerViews = layerView;
209 mStateAnimator = anim;
210 }
211
212 @Override
213 public void setViewAlpha(Animator anim, View view, float alpha) {
214 if (anim == null) {
215 if (view.getAlpha() == alpha) {
216 return;
217 }
218 anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
219 anim.addListener(new AlphaUpdateListener(view, isAccessibilityEnabled(view)));
Winson Chungdc61c4d2015-04-20 18:26:57 -0700220 }
Winson Chungdc61c4d2015-04-20 18:26:57 -0700221
Sunny Goyalaeb16432017-10-16 11:46:41 -0700222 anim.setDuration(mDuration).setInterpolator(getFadeInterpolator(alpha));
223 mLayerViews.addView(view);
224 mStateAnimator.play(anim);
Winson Chungdc61c4d2015-04-20 18:26:57 -0700225 }
Sunny Goyalaeb16432017-10-16 11:46:41 -0700226
227 @Override
228 public <T> void setFloat(T target, Property<T, Float> property, float value,
229 TimeInterpolator interpolator) {
230 if (property.get(target) == value) {
231 return;
232 }
233 Animator anim = ObjectAnimator.ofFloat(target, property, value);
234 anim.setDuration(mDuration).setInterpolator(interpolator);
235 mStateAnimator.play(anim);
236 }
237
238 @Override
239 public <T> void setInt(T target, Property<T, Integer> property, int value,
240 TimeInterpolator interpolator) {
241 if (property.get(target) == value) {
242 return;
243 }
244 Animator anim = ObjectAnimator.ofInt(target, property, value);
245 anim.setDuration(mDuration).setInterpolator(interpolator);
246 mStateAnimator.play(anim);
247 }
248
249 private TimeInterpolator getFadeInterpolator(float finalAlpha) {
Sunny Goyal5bc6b6f2017-10-26 15:36:10 -0700250 return finalAlpha == 0 ? Interpolators.DEACCEL_2 : null;
Sunny Goyalaeb16432017-10-16 11:46:41 -0700251 }
Winson Chungdc61c4d2015-04-20 18:26:57 -0700252 }
253}