diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index ff4711cb208ae..98d7f8b864fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -23,6 +23,7 @@ import android.os.Handler
import android.os.Looper
import android.os.Message
import android.os.UserHandle
+import android.text.TextUtils
import android.util.Log
import android.util.SparseArray
import com.android.internal.annotations.VisibleForTesting
@@ -55,7 +56,8 @@ private const val DEBUG = false
* a given broadcast.
*
* Use only for IntentFilters with actions and optionally categories. It does not support,
- * permissions, schemes or data types. Cannot be used for getting sticky broadcasts.
+ * permissions, schemes, data types or data authorities.
+ * Cannot be used for getting sticky broadcasts.
*/
@Singleton
open class BroadcastDispatcher @Inject constructor (
@@ -72,11 +74,14 @@ open class BroadcastDispatcher @Inject constructor (
*
* @param receiver A receiver to dispatch the [Intent]
* @param filter A filter to determine what broadcasts should be dispatched to this receiver.
- * It will only take into account actions and categories for filtering.
+ * It will only take into account actions and categories for filtering. It must
+ * have at least one action.
* @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
* main handler. Pass `null` to use the default.
* @param user A user handle to determine which broadcast should be dispatched to this receiver.
* By default, it is the current user.
+ * @throws IllegalArgumentException if the filter has other constraints that are not actions or
+ * categories or the filter has no actions.
*/
@JvmOverloads
fun registerReceiver(
@@ -85,12 +90,23 @@ open class BroadcastDispatcher @Inject constructor (
handler: Handler? = mainHandler,
user: UserHandle = context.user
) {
+ checkFilter(filter)
this.handler
.obtainMessage(MSG_ADD_RECEIVER,
ReceiverData(receiver, filter, handler ?: mainHandler, user))
.sendToTarget()
}
+ private fun checkFilter(filter: IntentFilter) {
+ val sb = StringBuilder()
+ if (filter.countActions() == 0) sb.append("Filter must contain at least one action. ")
+ if (filter.countDataAuthorities() != 0) sb.append("Filter cannot contain DataAuthorities. ")
+ if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ")
+ if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ")
+ if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ")
+ if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString())
+ }
+
/**
* Unregister receiver for all users.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 2bff5488937db..ead14e5011939 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.content.IntentFilter
import android.os.Handler
import android.os.Looper
+import android.os.PatternMatcher
import android.os.UserHandle
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
@@ -33,6 +34,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -48,6 +50,10 @@ class BroadcastDispatcherTest : SysuiTestCase() {
val user1 = UserHandle.of(1)
fun capture(argumentCaptor: ArgumentCaptor): T = argumentCaptor.capture()
+ const val TEST_ACTION = "TEST_ACTION"
+ const val TEST_SCHEME = "TEST_SCHEME"
+ const val TEST_PATH = "TEST_PATH"
+ const val TEST_TYPE = "test/type"
}
@Mock
@@ -83,6 +89,11 @@ class BroadcastDispatcherTest : SysuiTestCase() {
Handler(testableLooper.looper),
testableLooper.looper,
mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
+
+ // These should be valid filters
+ `when`(intentFilter.countActions()).thenReturn(1)
+ `when`(intentFilterOther.countActions()).thenReturn(1)
+ `when`(mockContext.user).thenReturn(user0)
}
@Test
@@ -129,6 +140,44 @@ class BroadcastDispatcherTest : SysuiTestCase() {
verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
}
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustContainActions() {
+ val testFilter = IntentFilter()
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustNotContainDataScheme() {
+ val testFilter = IntentFilter(TEST_ACTION).apply {
+ addDataScheme(TEST_SCHEME)
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustNotContainDataAuthority() {
+ val testFilter = IntentFilter(TEST_ACTION).apply {
+ addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustNotContainDataPath() {
+ val testFilter = IntentFilter(TEST_ACTION).apply {
+ addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustNotContainDataType() {
+ val testFilter = IntentFilter(TEST_ACTION).apply {
+ addDataType(TEST_TYPE)
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
private class TestBroadcastDispatcher(
context: Context,
mainHandler: Handler,