• 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 
getDisplaynull118     override fun getDisplay(displayId: Int): Display {
119         return displayManager.getDisplay(displayId)
120     }
121 
122     @WorkerThread
onDisplayAddednull123     private fun onDisplayAdded(displayId: Int, list: List<DisplayTrackerDataItem>) {
124         Assert.isNotMainThread()
125 
126         notifySubscribers({ onDisplayAdded(displayId) }, list)
127     }
128 
129     @WorkerThread
onDisplayRemovednull130     private fun onDisplayRemoved(displayId: Int, list: List<DisplayTrackerDataItem>) {
131         Assert.isNotMainThread()
132 
133         notifySubscribers({ onDisplayRemoved(displayId) }, list)
134     }
135 
136     @WorkerThread
onDisplayChangednull137     private fun onDisplayChanged(displayId: Int, list: List<DisplayTrackerDataItem>) {
138         Assert.isNotMainThread()
139 
140         notifySubscribers({ onDisplayChanged(displayId) }, list)
141     }
142 
notifySubscribersnull143     private inline fun notifySubscribers(
144         crossinline action: DisplayTracker.Callback.() -> Unit,
145         list: List<DisplayTrackerDataItem>
146     ) {
147         list.forEach {
148             if (it.callback.get() != null) {
149                 it.executor.execute { it.callback.get()?.action() }
150             }
151         }
152     }
153 
154     private data class DisplayTrackerDataItem(
155         val callback: WeakReference<DisplayTracker.Callback>,
156         val executor: Executor
157     ) {
sameOrEmptynull158         fun sameOrEmpty(other: DisplayTracker.Callback): Boolean {
159             return callback.get()?.equals(other) ?: true
160         }
161     }
162 }
163