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.systemui.statusbar.events
18 
19 import android.annotation.IntRange
20 import android.annotation.SuppressLint
21 import android.content.Context
22 import android.view.View
23 import android.widget.ImageView
24 import com.android.systemui.privacy.OngoingPrivacyChip
25 import com.android.systemui.privacy.PrivacyItem
26 import com.android.systemui.statusbar.BatteryStatusChip
27 import com.android.systemui.statusbar.ConnectedDisplayChip
28 
29 typealias ViewCreator = (context: Context) -> BackgroundAnimatableView
30 
31 interface StatusEvent {
32     val priority: Int
33     // Whether or not to force the status bar open and show a dot
34     var forceVisible: Boolean
35     // Whether or not to show an animation for this event
36     val showAnimation: Boolean
37     val viewCreator: ViewCreator
38     var contentDescription: String?
39 
40     // Update this event with values from another event.
41     fun updateFromEvent(other: StatusEvent?) {
42         // no op by default
43     }
44 
45     // Whether or not this event should update its value from the provided. False by default
46     fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
47         return false
48     }
49 }
50 
51 class BGView(
52     context: Context
53 ) : View(context), BackgroundAnimatableView {
54     override val view: View
55         get() = this
56 
57     override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
58         setLeftTopRightBottom(l, t, r, b)
59     }
60 }
61 
62 @SuppressLint("AppCompatCustomView")
63 class BGImageView(
64     context: Context
65 ) : ImageView(context), BackgroundAnimatableView {
66     override val view: View
67         get() = this
68 
69     override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
70         setLeftTopRightBottom(l, t, r, b)
71     }
72 }
73 
74 class BatteryEvent(@IntRange(from = 0, to = 100) val batteryLevel: Int) : StatusEvent {
75     override val priority = 50
76     override var forceVisible = false
77     override val showAnimation = true
78     override var contentDescription: String? = ""
79 
80     override val viewCreator: ViewCreator = { context ->
81         BatteryStatusChip(context).apply {
82             setBatteryLevel(batteryLevel)
83         }
84     }
85 
86     override fun toString(): String {
87         return javaClass.simpleName
88     }
89 }
90 
91 /** Event that triggers a connected display chip in the status bar. */
92 class ConnectedDisplayEvent : StatusEvent {
93     /** Priority is set higher than [BatteryEvent]. */
94     override val priority = 60
95     override var forceVisible = false
96     override val showAnimation = true
97     override var contentDescription: String? = ""
98 
99     override val viewCreator: ViewCreator = { context ->
100         ConnectedDisplayChip(context)
101     }
102 
103     override fun toString(): String {
104         return javaClass.simpleName
105     }
106 }
107 
108 /** open only for testing purposes. (See [FakeStatusEvent.kt]) */
109 open class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
110     override var contentDescription: String? = null
111     override val priority = 100
112     override var forceVisible = true
113     var privacyItems: List<PrivacyItem> = listOf()
114     private var privacyChip: OngoingPrivacyChip? = null
115 
116     override val viewCreator: ViewCreator = { context ->
117         val v = OngoingPrivacyChip(context)
118         v.privacyList = privacyItems
119         v.contentDescription = contentDescription
120         privacyChip = v
121         v
122     }
123 
124     override fun toString(): String {
125         return "${javaClass.simpleName}(forceVisible=$forceVisible, privacyItems=$privacyItems)"
126     }
127 
128     override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
129         return other is PrivacyEvent && (other.privacyItems != privacyItems ||
130                 other.contentDescription != contentDescription ||
131                 (other.forceVisible && !forceVisible))
132     }
133 
134     override fun updateFromEvent(other: StatusEvent?) {
135         if (other !is PrivacyEvent) {
136             return
137         }
138 
139         privacyItems = other.privacyItems
140         contentDescription = other.contentDescription
141 
142         privacyChip?.contentDescription = other.contentDescription
143         privacyChip?.privacyList = other.privacyItems
144 
145         if (other.forceVisible) forceVisible = true
146     }
147 }
148