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