1 /*
2  * Copyright (C) 2021 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.keyguard;
18 
19 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
20 import static com.android.systemui.statusbar.StatusBarState.SHADE;
21 
22 import android.util.Property;
23 import android.view.View;
24 
25 import com.android.app.animation.Interpolators;
26 import com.android.systemui.keyguard.MigrateClocksToBlueprint;
27 import com.android.systemui.log.LogBuffer;
28 import com.android.systemui.log.core.LogLevel;
29 import com.android.systemui.statusbar.StatusBarState;
30 import com.android.systemui.statusbar.notification.AnimatableProperty;
31 import com.android.systemui.statusbar.notification.PropertyAnimator;
32 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
33 import com.android.systemui.statusbar.phone.DozeParameters;
34 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
35 import com.android.systemui.statusbar.policy.KeyguardStateController;
36 import com.android.systemui.util.Assert;
37 
38 import com.google.errorprone.annotations.CompileTimeConstant;
39 
40 import java.util.function.Consumer;
41 
42 /**
43  * Helper class for updating visibility of keyguard views based on keyguard and status bar state.
44  * This logic is shared by both the keyguard status view and the keyguard user switcher.
45  */
46 public class KeyguardVisibilityHelper {
47     private static final String TAG = "KeyguardVisibilityHelper";
48 
49     private View mView;
50     private final KeyguardStateController mKeyguardStateController;
51     private final DozeParameters mDozeParameters;
52     private final ScreenOffAnimationController mScreenOffAnimationController;
53     private boolean mAnimateYPos;
54     private boolean mKeyguardViewVisibilityAnimating;
55     private boolean mLastOccludedState = false;
56     private final AnimationProperties mAnimationProperties = new AnimationProperties();
57     private final LogBuffer mLogBuffer;
58 
KeyguardVisibilityHelper(View view, KeyguardStateController keyguardStateController, DozeParameters dozeParameters, ScreenOffAnimationController screenOffAnimationController, boolean animateYPos, LogBuffer logBuffer)59     public KeyguardVisibilityHelper(View view,
60             KeyguardStateController keyguardStateController,
61             DozeParameters dozeParameters,
62             ScreenOffAnimationController screenOffAnimationController,
63             boolean animateYPos,
64             LogBuffer logBuffer) {
65         mView = view;
66         mKeyguardStateController = keyguardStateController;
67         mDozeParameters = dozeParameters;
68         mScreenOffAnimationController = screenOffAnimationController;
69         mAnimateYPos = animateYPos;
70         mLogBuffer = logBuffer;
71     }
72 
log(@ompileTimeConstant String message)73     private void log(@CompileTimeConstant String message) {
74         if (mLogBuffer != null) {
75             mLogBuffer.log(TAG, LogLevel.DEBUG, message);
76         }
77     }
78 
isVisibilityAnimating()79     public boolean isVisibilityAnimating() {
80         return mKeyguardViewVisibilityAnimating;
81     }
82 
83     /**
84      * Set the visibility of a keyguard view based on some new state.
85      */
setViewVisibility( int statusBarState, boolean keyguardFadingAway, boolean goingToFullShade, int oldStatusBarState)86     public void setViewVisibility(
87             int statusBarState,
88             boolean keyguardFadingAway,
89             boolean goingToFullShade,
90             int oldStatusBarState) {
91         if (MigrateClocksToBlueprint.isEnabled()) {
92             log("Ignoring KeyguardVisibilityelper, migrateClocksToBlueprint flag on");
93             return;
94         }
95         Assert.isMainThread();
96         PropertyAnimator.cancelAnimation(mView, AnimatableProperty.ALPHA);
97         boolean isOccluded = mKeyguardStateController.isOccluded();
98         mKeyguardViewVisibilityAnimating = false;
99 
100         if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
101                 && statusBarState != KEYGUARD) || goingToFullShade) {
102             mKeyguardViewVisibilityAnimating = true;
103 
104             AnimationProperties animProps = new AnimationProperties()
105                     .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_OUT)
106                     .setAnimationEndAction(mSetGoneEndAction);
107             if (keyguardFadingAway) {
108                 animProps
109                         .setDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
110                         .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration());
111                 log("goingToFullShade && keyguardFadingAway");
112             } else {
113                 animProps.setDelay(0).setDuration(160);
114                 log("goingToFullShade && !keyguardFadingAway");
115             }
116             if (MigrateClocksToBlueprint.isEnabled()) {
117                 log("Using LockscreenToGoneTransition 1");
118             } else {
119                 PropertyAnimator.setProperty(
120                         mView, AnimatableProperty.ALPHA, 0f, animProps, true /* animate */);
121             }
122         } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) {
123             mView.setVisibility(View.VISIBLE);
124             mKeyguardViewVisibilityAnimating = true;
125             mView.setAlpha(0f);
126             PropertyAnimator.setProperty(
127                     mView, AnimatableProperty.ALPHA, 1f,
128                     new AnimationProperties()
129                             .setDelay(0)
130                             .setDuration(320)
131                             .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_IN)
132                             .setAnimationEndAction(
133                                     property -> mSetVisibleEndRunnable.run()),
134                     true /* animate */);
135             log("keyguardFadingAway transition w/ Y Aniamtion");
136         } else if (statusBarState == KEYGUARD) {
137             // Sometimes, device will be unlocked and then locked very quickly.
138             // keyguardFadingAway hasn't been set to false cause unlock animation hasn't finished
139             // So we should not animate keyguard fading away in this case (when oldState is SHADE)
140             if (oldStatusBarState != SHADE) {
141                 log("statusBarState == KEYGUARD && oldStatusBarState != SHADE");
142             } else {
143                 log("statusBarState == KEYGUARD && oldStatusBarState == SHADE");
144             }
145 
146             if (keyguardFadingAway && oldStatusBarState != SHADE) {
147                 mKeyguardViewVisibilityAnimating = true;
148                 AnimationProperties animProps = new AnimationProperties()
149                         .setDelay(0)
150                         .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_LINEAR_IN)
151                         .setAnimationEndAction(mSetInvisibleEndAction);
152                 if (mAnimateYPos) {
153                     float target = mView.getY() - mView.getHeight() * 0.05f;
154                     int delay = 0;
155                     int duration = 125;
156                     // We animate the Y property separately using the PropertyAnimator, as the panel
157                     // view also needs to update the end position.
158                     mAnimationProperties.setDuration(duration).setDelay(delay);
159                     PropertyAnimator.cancelAnimation(mView, AnimatableProperty.Y);
160                     PropertyAnimator.setProperty(mView, AnimatableProperty.Y, target,
161                             mAnimationProperties,
162                             true /* animate */);
163                     animProps.setDuration(duration)
164                             .setDelay(delay);
165                     log("keyguardFadingAway transition w/ Y Aniamtion");
166                 } else {
167                     log("keyguardFadingAway transition w/o Y Animation");
168                 }
169                 PropertyAnimator.setProperty(
170                         mView, AnimatableProperty.ALPHA, 0f,
171                         animProps,
172                         true /* animate */);
173             } else if (mScreenOffAnimationController.shouldAnimateInKeyguard()) {
174                 if (MigrateClocksToBlueprint.isEnabled()) {
175                     log("Using GoneToAodTransition");
176                     mKeyguardViewVisibilityAnimating = false;
177                 } else {
178                     log("ScreenOff transition");
179                     mKeyguardViewVisibilityAnimating = true;
180 
181                     // Ask the screen off animation controller to animate the keyguard visibility
182                     // for us since it may need to be cancelled due to keyguard lifecycle events.
183                     mScreenOffAnimationController.animateInKeyguard(mView, mSetVisibleEndRunnable);
184                 }
185             } else {
186                 log("Direct set Visibility to VISIBLE");
187                 mView.setVisibility(View.VISIBLE);
188             }
189         } else {
190             if (MigrateClocksToBlueprint.isEnabled()) {
191                 log("Using LockscreenToGoneTransition 2");
192             } else {
193                 log("Direct set Visibility to GONE");
194                 mView.setVisibility(View.GONE);
195                 mView.setAlpha(1f);
196             }
197         }
198 
199         mLastOccludedState = isOccluded;
200     }
201 
202     private final Consumer<Property> mSetInvisibleEndAction = new Consumer<>() {
203         @Override
204         public void accept(Property property) {
205             mKeyguardViewVisibilityAnimating = false;
206             mView.setVisibility(View.INVISIBLE);
207             log("Callback Set Visibility to INVISIBLE");
208         }
209     };
210 
211     private final Consumer<Property> mSetGoneEndAction = new Consumer<>() {
212         @Override
213         public void accept(Property property) {
214             mKeyguardViewVisibilityAnimating = false;
215             mView.setVisibility(View.GONE);
216             log("CallbackSet Visibility to GONE");
217         }
218     };
219 
220     private final Runnable mSetVisibleEndRunnable = () -> {
221         mKeyguardViewVisibilityAnimating = false;
222         mView.setVisibility(View.VISIBLE);
223         log("Callback Set Visibility to VISIBLE");
224     };
225 }
226