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,