• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings
18 
19 import android.hardware.display.DisplayManager
20 import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
21 import android.os.Handler
22 import android.view.Display
23 import androidx.annotation.GuardedBy
24 import androidx.annotation.VisibleForTesting
25 import androidx.annotation.WorkerThread
26 import com.android.systemui.dagger.qualifiers.Background
27 import com.android.systemui.util.Assert
28 import java.lang.ref.WeakReference
29 import java.util.concurrent.Executor
30 
31 class DisplayTrackerImpl
32 internal constructor(
33     val displayManager: DisplayManager,
34     @Background val backgroundHandler: Handler
35 ) : DisplayTracker {
36     override val defaultDisplayId: Int = Display.DEFAULT_DISPLAY
37     override val allDisplays: Array<Display>
38         get() = displayManager.displays
39 
40     @GuardedBy("displayCallbacks")
41     private val displayCallbacks: MutableList<DisplayTrackerDataItem> = ArrayList()
42     @GuardedBy("brightnessCallbacks")
43     private val brightnessCallbacks: MutableList<DisplayTrackerDataItem> = ArrayList()
44 
45     @VisibleForTesting
46     val displayChangedListener: DisplayManager.DisplayListener =
47         object : DisplayManager.DisplayListener {
onDisplayAddednull48             override fun onDisplayAdded(displayId: Int) {
49                 val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
50                 onDisplayAdded(displayId, list)
51             }
52 
onDisplayRemovednull53             override fun onDisplayRemoved(displayId: Int) {
54                 val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
55                 onDisplayRemoved(displayId, list)
56             }
57 
onDisplayChangednull58             override fun onDisplayChanged(displayId: Int) {
59                 val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
60                 onDisplayChanged(displayId, list)
61             }
62         }
63 
64     @VisibleForTesting
65     val displayBrightnessChangedListener: DisplayManager.DisplayListener =
66         object : DisplayManager.DisplayListener {
onDisplayAddednull67             override fun onDisplayAdded(displayId: Int) {}
68 
onDisplayRemovednull69             override fun onDisplayRemoved(displayId: Int) {}
70 
onDisplayChangednull71             override fun onDisplayChanged(displayId: Int) {
72                 val list = synchronized(brightnessCallbacks) { brightnessCallbacks.toList() }
73                 onDisplayChanged(displayId, list)
74             }
75         }
76 
addDisplayChangeCallbacknull77     override fun addDisplayChangeCallback(callback: DisplayTracker.Callback, executor: Executor) {
78         synchronized(displayCallbacks) {
79             if (displayCallbacks.isEmpty()) {
80                 displayManager.registerDisplayListener(displayChangedListener, backgroundHandler)
81             }
82             displayCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor))
83         }
84     }
85 
addBrightnessChangeCallbacknull86     override fun addBrightnessChangeCallback(
87         callback: DisplayTracker.Callback,
88         executor: Executor
89     ) {
90         synchronized(brightnessCallbacks) {
91             if (brightnessCallbacks.isEmpty()) {
92                 displayManager.registerDisplayListener(
93                     displayBrightnessChangedListener,
94                     backgroundHandler,
95                     EVENT_FLAG_DISPLAY_BRIGHTNESS
96                 )
97             }
98             brightnessCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor))
99         }
100     }
101 
removeCallbacknull102     override fun removeCallback(callback: DisplayTracker.Callback) {
103         synchronized(displayCallbacks) {
104             val changed = displayCallbacks.removeIf { it.sameOrEmpty(callback) }
105             if (changed && displayCallbacks.isEmpty()) {
106                 displayManager.unregisterDisplayListener(displayChangedListener)
107             }
108         }
109 
110         synchronized(brightnessCallbacks) {
111             val changed = brightnessCallbacks.removeIf { it.sameOrEmpty(callback) }
112             if (changed && brightnessCallbacks.isEmpty()) {
113                 displayManager.unregisterDisplayListener(displayBrightnessChangedListener)
114             }
115         }
116     }
117 
118     @WorkerThread
onDisplayAddednull119     private fun onDisplayAdded(displayId: Int, list: List<DisplayTrackerDataItem>) {
120         Assert.isNotMainThread()
121 
122         notifySubscribers({ onDisplayAdded(displayId) }, list)
123     }
124 
125     @WorkerThread
onDisplayRemovednull126     private fun onDisplayRemoved(displayId: Int, list: List<DisplayTrackerDataItem>) {
127         Assert.isNotMainThread()
128 
129         notifySubscribers({ onDisplayRemoved(displayId) }, list)
130     }
131 
132     @WorkerThread
onDisplayChangednull133     private fun onDisplayChanged(displayId: Int, list: List<DisplayTrackerDataItem>) {
134         Assert.isNotMainThread()
135 
136         notifySubscribers({ onDisplayChanged(displayId) }, list)
137     }
138 
notifySubscribersnull139     private inline fun notifySubscribers(
140         crossinline action: DisplayTracker.Callback.() -> Unit,
141         list: List<DisplayTrackerDataItem>
142     ) {
143         list.forEach {
144             if (it.callback.get() != null) {
145                 it.executor.execute { it.callback.get()?.action() }
146             }
147         }
148     }
149 
150     private data class DisplayTrackerDataItem(
151         val callback: WeakReference<DisplayTracker.Callback>,
152         val executor: Executor
153     ) {
sameOrEmptynull154         fun sameOrEmpty(other: DisplayTracker.Callback): Boolean {
155             return callback.get()?.equals(other) ?: true
156         }
157     }
158 }
159