Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 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 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 19 | import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; |
| 20 | import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; |
| 21 | |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 22 | import android.animation.Animator; |
| 23 | import android.animation.AnimatorListenerAdapter; |
| 24 | import android.animation.AnimatorSet; |
Sunny Goyal | 4f3e938 | 2015-06-05 00:13:25 -0700 | [diff] [blame] | 25 | import android.animation.ObjectAnimator; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 26 | import android.animation.TimeInterpolator; |
| 27 | import android.animation.ValueAnimator; |
| 28 | import android.content.Context; |
| 29 | import android.content.res.Resources; |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 30 | import android.util.Property; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 31 | import android.view.View; |
| 32 | import android.view.accessibility.AccessibilityManager; |
Sunny Goyal | 1d08f70 | 2015-05-04 15:50:25 -0700 | [diff] [blame] | 33 | |
Sunny Goyal | 3e3f44c | 2017-10-23 17:14:52 -0700 | [diff] [blame] | 34 | import com.android.launcher3.LauncherStateManager.AnimationConfig; |
Sunny Goyal | b5e65c8 | 2016-10-26 18:32:38 -0700 | [diff] [blame] | 35 | import com.android.launcher3.anim.AnimationLayerSet; |
Sunny Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 36 | import com.android.launcher3.anim.Interpolators; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 37 | |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 38 | /** |
| 39 | * A convenience class to update a view's visibility state after an alpha animation. |
| 40 | */ |
| 41 | class 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 Song | eac1dac | 2016-06-21 16:37:13 -0700 | [diff] [blame] | 46 | private boolean mCanceled = false; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 47 | |
| 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 Song | eac1dac | 2016-06-21 16:37:13 -0700 | [diff] [blame] | 71 | public void onAnimationCancel(Animator animation) { |
| 72 | mCanceled = true; |
| 73 | } |
| 74 | |
| 75 | @Override |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 76 | public void onAnimationEnd(Animator arg0) { |
Hyunyoung Song | eac1dac | 2016-06-21 16:37:13 -0700 | [diff] [blame] | 77 | if (mCanceled) return; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 78 | 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 Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 89 | * Manages the animations between each of the workspace states. |
| 90 | */ |
| 91 | public class WorkspaceStateTransitionAnimation { |
| 92 | |
Sunny Goyal | c4fa8c3 | 2017-11-07 12:23:58 -0800 | [diff] [blame^] | 93 | public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter(); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 94 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 95 | public final int mWorkspaceScrimAlpha; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 96 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 97 | private final Launcher mLauncher; |
| 98 | private final Workspace mWorkspace; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 99 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 100 | private final boolean mWorkspaceFadeInAdjacentScreens; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 101 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 102 | private float mNewScale; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 103 | |
| 104 | public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) { |
| 105 | mLauncher = launcher; |
| 106 | mWorkspace = workspace; |
| 107 | |
Adam Cohen | 2e6da15 | 2015-05-06 11:42:25 -0700 | [diff] [blame] | 108 | DeviceProfile grid = mLauncher.getDeviceProfile(); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 109 | Resources res = launcher.getResources(); |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 110 | mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 111 | mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens(); |
| 112 | } |
| 113 | |
Sunny Goyal | 4c7f215 | 2017-10-17 17:17:16 -0700 | [diff] [blame] | 114 | public void setState(LauncherState toState) { |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 115 | setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER); |
Sunny Goyal | ce5a7e5 | 2015-07-08 15:44:27 -0700 | [diff] [blame] | 116 | } |
| 117 | |
Sunny Goyal | ea60926 | 2017-10-25 15:47:38 -0700 | [diff] [blame] | 118 | public void setStateWithAnimation(LauncherState toState, AnimatorSet anim, |
| 119 | AnimationLayerSet layerViews, AnimationConfig config) { |
Sunny Goyal | 4c7f215 | 2017-10-17 17:17:16 -0700 | [diff] [blame] | 120 | AnimatedPropertySetter propertySetter = |
Sunny Goyal | ea60926 | 2017-10-25 15:47:38 -0700 | [diff] [blame] | 121 | new AnimatedPropertySetter(config.duration, layerViews, anim); |
Sunny Goyal | 4c7f215 | 2017-10-17 17:17:16 -0700 | [diff] [blame] | 122 | setWorkspaceProperty(toState, propertySetter); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 123 | } |
| 124 | |
| 125 | public float getFinalScale() { |
| 126 | return mNewScale; |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * Starts a transition animation for the workspace. |
| 131 | */ |
Sunny Goyal | 4c7f215 | 2017-10-17 17:17:16 -0700 | [diff] [blame] | 132 | private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter) { |
Sunny Goyal | c99cb17 | 2017-10-19 16:15:09 -0700 | [diff] [blame] | 133 | float[] scaleAndTranslationY = state.getWorkspaceScaleAndTranslation(mLauncher); |
Sunny Goyal | 2104c30 | 2017-10-23 15:04:10 -0700 | [diff] [blame] | 134 | mNewScale = scaleAndTranslationY[0]; |
Sunny Goyal | c99cb17 | 2017-10-19 16:15:09 -0700 | [diff] [blame] | 135 | final float finalWorkspaceTranslationY = scaleAndTranslationY[1]; |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 136 | |
Sunny Goyal | ce5a7e5 | 2015-07-08 15:44:27 -0700 | [diff] [blame] | 137 | int toPage = mWorkspace.getPageNearestToCenterOfScreen(); |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 138 | final int childCount = mWorkspace.getChildCount(); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 139 | for (int i = 0; i < childCount; i++) { |
Sunny Goyal | 4d519f2 | 2017-10-24 10:32:40 -0700 | [diff] [blame] | 140 | applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, toPage, |
| 141 | propertySetter); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 142 | } |
| 143 | |
Sunny Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 144 | propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_IN); |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 145 | propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y, |
Sunny Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 146 | finalWorkspaceTranslationY, Interpolators.ZOOM_IN); |
Jon Miranda | 7f522a2 | 2017-07-28 11:56:47 -0700 | [diff] [blame] | 147 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 148 | // Set scrim |
| 149 | propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA, |
Sunny Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 150 | state.hasScrim ? mWorkspaceScrimAlpha : 0, Interpolators.DEACCEL_1_5); |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 151 | } |
| 152 | |
Sunny Goyal | 4d519f2 | 2017-10-24 10:32:40 -0700 | [diff] [blame] | 153 | 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 Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 161 | DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN); |
Sunny Goyal | 4d519f2 | 2017-10-24 10:32:40 -0700 | [diff] [blame] | 162 | |
| 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 Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 167 | finalAlpha, Interpolators.ZOOM_IN); |
Sunny Goyal | 4d519f2 | 2017-10-24 10:32:40 -0700 | [diff] [blame] | 168 | } |
| 169 | } |
| 170 | |
Sunny Goyal | c4fa8c3 | 2017-11-07 12:23:58 -0800 | [diff] [blame^] | 171 | public static class PropertySetter { |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 172 | |
| 173 | public void setViewAlpha(Animator anim, View view, float alpha) { |
| 174 | if (anim != null) { |
| 175 | anim.end(); |
| 176 | return; |
Jon Miranda | 7f522a2 | 2017-07-28 11:56:47 -0700 | [diff] [blame] | 177 | } |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 178 | view.setAlpha(alpha); |
| 179 | AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view)); |
| 180 | } |
Jon Miranda | 7f522a2 | 2017-07-28 11:56:47 -0700 | [diff] [blame] | 181 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 182 | public <T> void setFloat(T target, Property<T, Float> property, float value, |
| 183 | TimeInterpolator interpolator) { |
| 184 | property.set(target, value); |
| 185 | } |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 186 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 187 | public <T> void setInt(T target, Property<T, Integer> property, int value, |
| 188 | TimeInterpolator interpolator) { |
| 189 | property.set(target, value); |
| 190 | } |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 191 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 192 | protected boolean isAccessibilityEnabled(View v) { |
| 193 | AccessibilityManager am = (AccessibilityManager) |
| 194 | v.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); |
| 195 | return am.isEnabled(); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 196 | } |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 197 | } |
| 198 | |
Sunny Goyal | c4fa8c3 | 2017-11-07 12:23:58 -0800 | [diff] [blame^] | 199 | public static class AnimatedPropertySetter extends PropertySetter { |
Hyunyoung Song | 7eea78a | 2015-06-23 15:02:33 -0700 | [diff] [blame] | 200 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 201 | private final long mDuration; |
| 202 | private final AnimationLayerSet mLayerViews; |
| 203 | private final AnimatorSet mStateAnimator; |
Hyunyoung Song | 5796b03 | 2015-06-19 18:03:35 -0700 | [diff] [blame] | 204 | |
Sunny Goyal | c4fa8c3 | 2017-11-07 12:23:58 -0800 | [diff] [blame^] | 205 | public AnimatedPropertySetter( |
| 206 | long duration, AnimationLayerSet layerView, AnimatorSet anim) { |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 207 | 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 Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 220 | } |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 221 | |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 222 | anim.setDuration(mDuration).setInterpolator(getFadeInterpolator(alpha)); |
| 223 | mLayerViews.addView(view); |
| 224 | mStateAnimator.play(anim); |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 225 | } |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 226 | |
| 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 Goyal | 5bc6b6f | 2017-10-26 15:36:10 -0700 | [diff] [blame] | 250 | return finalAlpha == 0 ? Interpolators.DEACCEL_2 : null; |
Sunny Goyal | aeb1643 | 2017-10-16 11:46:41 -0700 | [diff] [blame] | 251 | } |
Winson Chung | dc61c4d | 2015-04-20 18:26:57 -0700 | [diff] [blame] | 252 | } |
| 253 | } |