Merge "Throw exception if IntentFilter is not valid"
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index ff4711c..98d7f8b 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.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 @@
  * 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 @@
      *
      * @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 @@
         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.
      * <br>
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 2bff548..ead14e5 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.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.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 @@
         val user1 = UserHandle.of(1)
 
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): 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 @@
                 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 @@
         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,