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 package com.android.systemui.statusbar.phone
17 
18 import android.view.View
19 import android.view.WindowManager
20 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
21 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.AlphaProvider
22 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider
23 import com.android.systemui.unfold.SysUIUnfoldScope
24 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
25 import com.android.systemui.unfold.util.CurrentActivityTypeProvider
26 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
27 import javax.inject.Inject
28 import kotlin.math.max
29 
30 @SysUIUnfoldScope
31 class StatusBarMoveFromCenterAnimationController @Inject constructor(
32     private val progressProvider: ScopedUnfoldTransitionProgressProvider,
33     private val currentActivityTypeProvider: CurrentActivityTypeProvider,
34     windowManager: WindowManager
35 ) {
36 
37     // Whether we're on home activity. Updated only when the animation starts.
38     private var isOnHomeActivity: Boolean? = null
39 
40     private val transitionListener = TransitionListener()
41     private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(
42         windowManager,
43         viewCenterProvider = StatusBarViewsCenterProvider(),
44         alphaProvider = StatusBarIconsAlphaProvider()
45     )
46 
onViewsReadynull47     fun onViewsReady(viewsToAnimate: Array<View>) {
48         moveFromCenterAnimator.updateDisplayProperties()
49 
50         viewsToAnimate.forEach {
51             moveFromCenterAnimator.registerViewForAnimation(it)
52         }
53 
54         progressProvider.addCallback(transitionListener)
55     }
56 
onViewDetachednull57     fun onViewDetached() {
58         progressProvider.removeCallback(transitionListener)
59         moveFromCenterAnimator.clearRegisteredViews()
60     }
61 
onStatusBarWidthChangednull62     fun onStatusBarWidthChanged() {
63         moveFromCenterAnimator.updateDisplayProperties()
64         moveFromCenterAnimator.updateViewPositions()
65     }
66 
67     private inner class TransitionListener : TransitionProgressListener {
onTransitionStartednull68         override fun onTransitionStarted() {
69             isOnHomeActivity = currentActivityTypeProvider.isHomeActivity
70         }
71 
onTransitionProgressnull72         override fun onTransitionProgress(progress: Float) {
73             moveFromCenterAnimator.onTransitionProgress(progress)
74         }
75 
onTransitionFinishednull76         override fun onTransitionFinished() {
77             // Reset translations when transition is stopped/cancelled
78             // (e.g. the transition could be cancelled mid-way when rotating the screen)
79             moveFromCenterAnimator.onTransitionProgress(1f)
80             isOnHomeActivity = null
81         }
82     }
83 
84 
85     /**
86      * In certain cases, an alpha is applied based on the progress.
87      *
88      * This mainly happens to hide the statusbar during the unfold animation while on apps, as the
89      * bounds of the app "collapse" to the center, but the statusbar doesn't.
90      * While on launcher, this alpha is not applied.
91      */
92     private inner class StatusBarIconsAlphaProvider : AlphaProvider {
getAlphanull93         override fun getAlpha(progress: Float): Float {
94             if (isOnHomeActivity == true) {
95                 return 1.0f
96             }
97             return max(
98                 0f,
99                 (progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS)
100             )
101         }
102     }
103 }
104 
105 private const val ICONS_START_APPEARING_PROGRESS = 0.75F
106