blob: ff4711cb208ae4dd05ae5410716d652778baaa0e [file] [log] [blame]
Fabian Kozynski42f86a02019-07-09 12:39:03 -04001/*
2 * Copyright (C) 2019 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
17package com.android.systemui.broadcast
18
19import android.content.BroadcastReceiver
20import android.content.Context
21import android.content.IntentFilter
22import android.os.Handler
23import android.os.Looper
24import android.os.Message
25import android.os.UserHandle
26import android.util.Log
27import android.util.SparseArray
28import com.android.internal.annotations.VisibleForTesting
Fabian Kozynski42f86a02019-07-09 12:39:03 -040029import com.android.systemui.Dumpable
Dave Mankofff4736812019-10-18 17:25:50 -040030import com.android.systemui.dagger.qualifiers.BgLooper
31import com.android.systemui.dagger.qualifiers.MainHandler
Fabian Kozynski42f86a02019-07-09 12:39:03 -040032import java.io.FileDescriptor
33import java.io.PrintWriter
34import javax.inject.Inject
Fabian Kozynski42f86a02019-07-09 12:39:03 -040035import javax.inject.Singleton
36
37data class ReceiverData(
38 val receiver: BroadcastReceiver,
39 val filter: IntentFilter,
40 val handler: Handler,
41 val user: UserHandle
42)
43
44private const val MSG_ADD_RECEIVER = 0
45private const val MSG_REMOVE_RECEIVER = 1
46private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
47private const val TAG = "BroadcastDispatcher"
48private const val DEBUG = false
49
50/**
51 * SystemUI master Broadcast Dispatcher.
52 *
53 * This class allows [BroadcastReceiver] to register and centralizes registrations to [Context]
54 * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for
55 * a given broadcast.
56 *
57 * Use only for IntentFilters with actions and optionally categories. It does not support,
58 * permissions, schemes or data types. Cannot be used for getting sticky broadcasts.
59 */
60@Singleton
61open class BroadcastDispatcher @Inject constructor (
62 private val context: Context,
Dave Mankofff4736812019-10-18 17:25:50 -040063 @MainHandler private val mainHandler: Handler,
64 @BgLooper private val bgLooper: Looper
Fabian Kozynski42f86a02019-07-09 12:39:03 -040065) : Dumpable {
66
67 // Only modify in BG thread
68 private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20)
69
70 /**
71 * Register a receiver for broadcast with the dispatcher
72 *
73 * @param receiver A receiver to dispatch the [Intent]
74 * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
75 * It will only take into account actions and categories for filtering.
76 * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -040077 * main handler. Pass `null` to use the default.
Fabian Kozynski42f86a02019-07-09 12:39:03 -040078 * @param user A user handle to determine which broadcast should be dispatched to this receiver.
79 * By default, it is the current user.
80 */
81 @JvmOverloads
82 fun registerReceiver(
83 receiver: BroadcastReceiver,
84 filter: IntentFilter,
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -040085 handler: Handler? = mainHandler,
Fabian Kozynski42f86a02019-07-09 12:39:03 -040086 user: UserHandle = context.user
87 ) {
Fabian Kozynskiff5e91f2019-09-24 15:38:08 -040088 this.handler
89 .obtainMessage(MSG_ADD_RECEIVER,
90 ReceiverData(receiver, filter, handler ?: mainHandler, user))
Fabian Kozynski42f86a02019-07-09 12:39:03 -040091 .sendToTarget()
92 }
93
94 /**
95 * Unregister receiver for all users.
96 * <br>
97 * This will remove every registration of [receiver], not those done just with [UserHandle.ALL].
98 *
99 * @param receiver The receiver to unregister. It will be unregistered for all users.
100 */
101 fun unregisterReceiver(receiver: BroadcastReceiver) {
102 handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget()
103 }
104
105 /**
106 * Unregister receiver for a particular user.
107 *
108 * @param receiver The receiver to unregister. It will be unregistered for all users.
109 * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
110 */
111 fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
112 handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver)
113 .sendToTarget()
114 }
115
116 @VisibleForTesting
117 protected open fun createUBRForUser(userId: Int) =
118 UserBroadcastDispatcher(context, userId, mainHandler, bgLooper)
119
120 override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
121 pw?.println("Broadcast dispatcher:")
122 for (index in 0 until receiversByUser.size()) {
123 pw?.println(" User ${receiversByUser.keyAt(index)}")
124 receiversByUser.valueAt(index).dump(fd, pw, args)
125 }
126 }
127
128 private val handler = object : Handler(bgLooper) {
129 override fun handleMessage(msg: Message) {
130 when (msg.what) {
131 MSG_ADD_RECEIVER -> {
132 val data = msg.obj as ReceiverData
133 val userId = data.user.identifier
134 if (userId < UserHandle.USER_ALL) {
135 if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId")
136 return
137 }
138 val uBR = receiversByUser.get(userId, createUBRForUser(userId))
139 receiversByUser.put(userId, uBR)
140 uBR.registerReceiver(data)
141 }
142
143 MSG_REMOVE_RECEIVER -> {
144 for (it in 0 until receiversByUser.size()) {
145 receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver)
146 }
147 }
148
149 MSG_REMOVE_RECEIVER_FOR_USER -> {
150 receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver)
151 }
152
153 else -> super.handleMessage(msg)
154 }
155 }
156 }
157}