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