1 /*
2  * Copyright (C) 2022 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.systemui.statusbar.phone
18 
19 import android.graphics.Rect
20 import android.view.View
21 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
22 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.END_SIDE_CONTENT
23 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.START_SIDE_CONTENT
24 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope
25 import com.android.systemui.util.boundsOnScreen
26 import javax.inject.Inject
27 import javax.inject.Named
28 
29 /** Provides various bounds within the status bar. */
30 @StatusBarFragmentScope
31 class StatusBarBoundsProvider
32 @Inject
33 constructor(
34     private val changeListeners: Set<@JvmSuppressWildcards BoundsChangeListener>,
35     @Named(START_SIDE_CONTENT) private val startSideContent: View,
36     @Named(END_SIDE_CONTENT) private val endSideContent: View,
37 ) : StatusBarFragmentComponent.Startable {
38 
39     interface BoundsChangeListener {
40         fun onStatusBarBoundsChanged()
41     }
42 
43     private var previousBounds =
44         BoundsPair(start = startSideContent.boundsOnScreen, end = endSideContent.boundsOnScreen)
45 
46     private val layoutListener =
47         View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
48             val newBounds = BoundsPair(start = visibleStartSideBounds, end = visibleEndSideBounds)
49             if (previousBounds != newBounds) {
50                 previousBounds = newBounds
51                 changeListeners.forEach { it.onStatusBarBoundsChanged() }
52             }
53         }
54 
55     override fun start() {
56         startSideContent.addOnLayoutChangeListener(layoutListener)
57         endSideContent.addOnLayoutChangeListener(layoutListener)
58     }
59 
60     override fun stop() {
61         startSideContent.removeOnLayoutChangeListener(layoutListener)
62         endSideContent.removeOnLayoutChangeListener(layoutListener)
63     }
64 
65     /**
66      * Returns the bounds of the end side of the status bar that are visible to the user. The end
67      * side is right when in LTR and is left when in RTL.
68      *
69      * Note that even though the layout might be larger, here we only return the bounds for what is
70      * visible to the user.
71      *
72      * The end side of the status bar contains the multi-user switcher and status icons such as
73      * wi-fi, battery, etc
74      */
75     val visibleEndSideBounds: Rect
76         get() = endSideContent.boundsOnScreen
77 
78     /**
79      * Returns the bounds of the start side of the status bar that are visible to the user. The
80      * start side is left when in LTR and is right when in RTL.
81      *
82      * Note that even though the layout might be larger, here we only return the bounds for what is
83      * visible to the user.
84      *
85      * The start side of the status bar contains the operator name, clock, on-going call chip, and
86      * notifications.
87      */
88     val visibleStartSideBounds: Rect
89         get() = startSideContent.boundsOnScreen
90 }
91 
92 private data class BoundsPair(val start: Rect, val end: Rect)
93