Merge "Fixes a NPE in the DisplayResolutionTracker."
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 87579eb..4e3adfb 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -27,6 +27,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -396,6 +397,20 @@
     final <T> T getValueAt(int i, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) {
         Object object = mMap.valueAt(i);
         if (object instanceof BiFunction<?, ?, ?>) {
+            synchronized (this) {
+                object = unwrapLazyValueFromMapLocked(i, clazz, itemTypes);
+            }
+        }
+        return (clazz != null) ? clazz.cast(object) : (T) object;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nullable
+    @GuardedBy("this")
+    private Object unwrapLazyValueFromMapLocked(int i, @Nullable Class<?> clazz,
+            @Nullable Class<?>... itemTypes) {
+        Object object = mMap.valueAt(i);
+        if (object instanceof BiFunction<?, ?, ?>) {
             try {
                 object = ((BiFunction<Class<?>, Class<?>[], ?>) object).apply(clazz, itemTypes);
             } catch (BadParcelableException e) {
@@ -409,7 +424,8 @@
             mMap.setValueAt(i, object);
             mLazyValues--;
             if (mOwnsLazyValues) {
-                Preconditions.checkState(mLazyValues >= 0, "Lazy values ref count below 0");
+                Preconditions.checkState(mLazyValues >= 0,
+                        "Lazy values ref count below 0");
                 // No more lazy values in mMap, so we can recycle the parcel early rather than
                 // waiting for the next GC run
                 if (mLazyValues == 0) {
@@ -420,7 +436,7 @@
                 }
             }
         }
-        return (clazz != null) ? clazz.cast(object) : (T) object;
+        return object;
     }
 
     private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean ownsParcel,
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
index 6f675a3..787d096 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
@@ -52,7 +52,7 @@
             ),
             rootPages = listOf(
                 SettingsPage.create(HomePageProvider.name)
-            ) + ArgumentPageProvider.buildRootPages()
+            )
         )
     }
 
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
index 199a45b..d8ef937 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
@@ -25,6 +25,7 @@
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.gallery.R
+import com.android.settingslib.spa.gallery.page.ArgumentPageModel
 import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
 import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
@@ -39,52 +40,28 @@
 
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val owner = SettingsPage.create(name)
-        val entryList = mutableListOf<SettingsEntry>()
-        entryList.add(
-            PreferenceMainPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
+        return listOf(
+            PreferenceMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            ArgumentPageProvider.buildInjectEntry("foo")!!.setLink(fromPage = owner).build(),
+            SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            FooterPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            IllustrationPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
         )
-        entryList.add(
-            SliderPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
-        )
-        entryList.add(
-            SpinnerPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
-        )
-        entryList.add(
-            SettingsPagerPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
-        )
-        entryList.add(
-            FooterPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
-        )
-        entryList.add(
-            IllustrationPageProvider.buildInjectEntry()
-                .setLink(fromPage = owner).build()
-        )
-
-        return entryList
     }
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        HomePage()
-    }
-}
-
-@Composable
-private fun HomePage() {
-    HomeScaffold(title = stringResource(R.string.app_name)) {
-        PreferenceMainPageProvider.EntryItem()
-        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
-
-        SliderPageProvider.EntryItem()
-        SpinnerPageProvider.EntryItem()
-        SettingsPagerPageProvider.EntryItem()
-        FooterPageProvider.EntryItem()
-        IllustrationPageProvider.EntryItem()
+        HomeScaffold(title = stringResource(R.string.app_name)) {
+            for (entry in buildEntry(arguments)) {
+                if (entry.name.startsWith(ArgumentPageModel.name)) {
+                    entry.UiLayout(ArgumentPageModel.buildArgument(intParam = 0))
+                } else {
+                    entry.UiLayout()
+                }
+            }
+        }
     }
 }
 
@@ -92,6 +69,6 @@
 @Composable
 private fun HomeScreenPreview() {
     SettingsTheme {
-        HomePage()
+        HomePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index 5cce215..e32de7a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -43,7 +43,7 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genStringParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genStringParamPreferenceModel())
                 }.build()
         )
 
@@ -53,54 +53,44 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genIntParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genIntParamPreferenceModel())
                 }.build()
         )
 
-        val entryFoo = buildInjectEntry(ArgumentPageModel.buildNextArgument("foo", arguments))
-        val entryBar = buildInjectEntry(ArgumentPageModel.buildNextArgument("bar", arguments))
-        if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
-        if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("foo")!!.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("bar")!!.setLink(fromPage = owner).build())
 
         return entryList
     }
 
-    private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
+    fun buildInjectEntry(stringParam: String): SettingsEntryBuilder? {
+        val arguments = ArgumentPageModel.buildArgument(stringParam)
         if (!ArgumentPageModel.isValidArgument(arguments)) return null
 
         return SettingsEntryBuilder.createInject(
-            entryName = ArgumentPageModel.getInjectEntryName(arguments),
+            entryName = "${name}_$stringParam",
             owner = SettingsPage.create(name, parameter, arguments)
         )
             // Set attributes
             .setIsAllowSearch(false)
             .setUiLayoutFn {
                 // Set ui rendering
-                Preference(ArgumentPageModel.create(arguments).genInjectPreferenceModel())
+                Preference(ArgumentPageModel.create(it).genInjectPreferenceModel())
             }
     }
 
-    fun buildRootPages(): List<SettingsPage> {
-        return listOf(
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("foo")),
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("bar")),
-        )
-    }
-
     @Composable
     override fun Page(arguments: Bundle?) {
         RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
             for (entry in buildEntry(arguments)) {
-                entry.uiLayout()
+                if (entry.name.startsWith(name)) {
+                    entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments))
+                } else {
+                    entry.UiLayout()
+                }
             }
         }
     }
-
-    @Composable
-    fun EntryItem(stringParam: String, intParam: Int) {
-        buildInjectEntry(ArgumentPageModel.buildArgument(stringParam, intParam))
-            ?.build()?.uiLayout?.let { it() }
-    }
 }
 
 @Preview(showBackground = true)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
index e27bf6d..6e86fd7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
@@ -44,19 +44,17 @@
             navArgument(INT_PARAM_NAME) { type = NavType.IntType },
         )
 
-        fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
+        fun buildArgument(stringParam: String? = null, intParam: Int? = null): Bundle {
             val args = Bundle()
-            args.putString(STRING_PARAM_NAME, stringParam)
+            if (stringParam != null) args.putString(STRING_PARAM_NAME, stringParam)
             if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
             return args
         }
 
-        fun buildNextArgument(newStringParam: String, arguments: Bundle? = null): Bundle {
+        fun buildNextArgument(arguments: Bundle? = null): Bundle {
             val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
-            return if (intParam == null)
-                buildArgument(newStringParam)
-            else
-                buildArgument(newStringParam, intParam + 1)
+            val nextIntParam = if (intParam != null) intParam + 1 else null
+            return buildArgument(intParam = nextIntParam)
         }
 
         fun isValidArgument(arguments: Bundle?): Boolean {
@@ -64,10 +62,6 @@
             return (stringParam != null && listOf("foo", "bar").contains(stringParam))
         }
 
-        fun getInjectEntryName(arguments: Bundle?): String {
-            return "${name}_${parameter.getStringArg(STRING_PARAM_NAME, arguments)}"
-        }
-
         @Composable
         fun create(arguments: Bundle?): ArgumentPageModel {
             val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
index a822583..0fc2a5f 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -69,22 +69,12 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        FooterPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun FooterPage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in FooterPageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+            Footer(footerText = "Footer text always at the end of page.")
         }
-        Footer(footerText = "Footer text always at the end of page.")
     }
 }
 
@@ -92,6 +82,6 @@
 @Composable
 private fun FooterPagePreview() {
     SettingsTheme {
-        FooterPage()
+        FooterPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
index 1afb7d8..a64d4a5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
@@ -84,20 +84,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        IllustrationPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun IllustrationPage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in IllustrationPageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -106,6 +96,6 @@
 @Composable
 private fun IllustrationPagePreview() {
     SettingsTheme {
-        IllustrationPage()
+        IllustrationPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index ff5f71b..e09ebda 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -48,20 +48,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        SettingsPagerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun SettingsPagerPage() {
-    SettingsScaffold(title = TITLE) {
-        SettingsPager(listOf("Personal", "Work")) {
-            PlaceholderTitle("Page $it")
+        SettingsScaffold(title = TITLE) {
+            SettingsPager(listOf("Personal", "Work")) {
+                PlaceholderTitle("Page $it")
+            }
         }
     }
 }
@@ -70,6 +60,6 @@
 @Composable
 private fun SettingsPagerPagePreview() {
     SettingsTheme {
-        SettingsPagerPage()
+        SettingsPagerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
index 53eeda2..0f95bf6 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -121,20 +121,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        SliderPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun SliderPage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in SliderPageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -143,6 +133,6 @@
 @Composable
 private fun SliderPagePreview() {
     SettingsTheme {
-        SliderPage()
+        SliderPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
index 04f1543..a8e4938 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
@@ -74,20 +74,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        MainSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun MainSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in MainSwitchPreferencePageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -121,6 +111,6 @@
 @Composable
 private fun MainSwitchPreferencePagePreview() {
     SettingsTheme {
-        MainSwitchPreferencePage()
+        MainSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
index 417601e..0f99c57 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -33,25 +33,16 @@
     override val name = "PreferenceMain"
 
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
-        val entryList = mutableListOf<SettingsEntry>()
-        entryList.add(
+        return listOf(
             PreferencePageProvider.buildInjectEntry()
-                .setLink(fromPage = SettingsPage.create(name)).build()
-        )
-        entryList.add(
+                .setLink(fromPage = SettingsPage.create(name)).build(),
             SwitchPreferencePageProvider.buildInjectEntry()
-                .setLink(fromPage = SettingsPage.create(name)).build()
-        )
-        entryList.add(
+                .setLink(fromPage = SettingsPage.create(name)).build(),
             MainSwitchPreferencePageProvider.buildInjectEntry()
-                .setLink(fromPage = SettingsPage.create(name)).build()
-        )
-        entryList.add(
+                .setLink(fromPage = SettingsPage.create(name)).build(),
             TwoTargetSwitchPreferencePageProvider.buildInjectEntry()
-                .setLink(fromPage = SettingsPage.create(name)).build()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
         )
-
-        return entryList
     }
 
     fun buildInjectEntry(): SettingsEntryBuilder {
@@ -67,21 +58,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferenceMain()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun PreferenceMain() {
-    RegularScaffold(title = TITLE) {
-        PreferencePageProvider.EntryItem()
-        SwitchPreferencePageProvider.EntryItem()
-        MainSwitchPreferencePageProvider.EntryItem()
-        TwoTargetSwitchPreferencePageProvider.EntryItem()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index c7547a0..cbd028d 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -143,20 +143,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun PreferencePage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in PreferencePageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -165,6 +155,6 @@
 @Composable
 private fun PreferencePagePreview() {
     SettingsTheme {
-        PreferencePage()
+        PreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index c5d52d8..46b44ca 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -90,20 +90,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        SwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun SwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in SwitchPreferencePageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -168,6 +158,6 @@
 @Composable
 private fun SwitchPreferencePagePreview() {
     SettingsTheme {
-        SwitchPreferencePage()
+        SwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
index 63bb50e..b991f59 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -90,20 +90,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        TwoTargetSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun TwoTargetSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        for (entry in TwoTargetSwitchPreferencePageProvider.buildEntry(arguments = null)) {
-            entry.uiLayout()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
         }
     }
 }
@@ -168,6 +158,6 @@
 @Composable
 private fun TwoTargetSwitchPreferencePagePreview() {
     SettingsTheme {
-        TwoTargetSwitchPreferencePage()
+        TwoTargetSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
index 7479d467..03b72d3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
@@ -51,28 +51,20 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        SpinnerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        buildInjectEntry().build().uiLayout.let { it() }
-    }
-}
-
-@Composable
-private fun SpinnerPage() {
-    RegularScaffold(title = TITLE) {
-        val selectedIndex = rememberSaveable { mutableStateOf(0) }
-        Spinner(
-            options = (1..3).map { "Option $it" },
-            selectedIndex = selectedIndex.value,
-            setIndex = { selectedIndex.value = it },
-        )
-        Preference(object : PreferenceModel {
-            override val title = "Selected index"
-            override val summary = remember { derivedStateOf { selectedIndex.value.toString() } }
-        })
+        RegularScaffold(title = TITLE) {
+            val selectedIndex = rememberSaveable { mutableStateOf(0) }
+            Spinner(
+                options = (1..3).map { "Option $it" },
+                selectedIndex = selectedIndex.value,
+                setIndex = { selectedIndex.value = it },
+            )
+            Preference(object : PreferenceModel {
+                override val title = "Selected index"
+                override val summary = remember {
+                    derivedStateOf { selectedIndex.value.toString() }
+                }
+            })
+        }
     }
 }
 
@@ -80,6 +72,6 @@
 @Composable
 private fun SpinnerPagePreview() {
     SettingsTheme {
-        SpinnerPage()
+        SpinnerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
index 095e683..bd5aaa7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
@@ -60,6 +60,17 @@
         setTheme(R.style.Theme_SpaLib_DayNight)
         super.onCreate(savedInstanceState)
 
+        val packageName = browseActivityClass.packageName
+        val className = browseActivityClass.toString().removePrefix("class $packageName")
+        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+            if (pageWithEntry.page.hasRuntimeParam()) continue
+            val route = pageWithEntry.page.buildRoute()
+            Log.d(
+                "DEBUG ACTIVITY",
+                "adb shell am start -n $packageName/$className -e $KEY_DESTINATION $route"
+            )
+        }
+
         setContent {
             SettingsTheme {
                 MainContent()
@@ -136,6 +147,7 @@
             Text(text = "Entry size: ${pageWithEntry.entries.size}")
             Preference(model = object : PreferenceModel {
                 override val title = "open page"
+                override val enabled = (!pageWithEntry.page.hasRuntimeParam()).toState()
                 override val onClick = openPage(pageWithEntry.page)
             })
             EntryList(pageWithEntry.entries)
@@ -149,6 +161,7 @@
         RegularScaffold(title = "Entry ${entry.displayName}") {
             Preference(model = object : PreferenceModel {
                 override val title = "open entry"
+                override val enabled = (!entry.hasRuntimeParam()).toState()
                 override val onClick = openEntry(entry)
             })
             Text(text = entry.formatAll())
@@ -168,7 +181,8 @@
     }
 
     @Composable
-    private fun openPage(page: SettingsPage): () -> Unit {
+    private fun openPage(page: SettingsPage): (() -> Unit)? {
+        if (page.hasRuntimeParam()) return null
         val route = page.buildRoute()
         val context = LocalContext.current
         val intent = Intent(context, browseActivityClass).apply {
@@ -181,7 +195,8 @@
     }
 
     @Composable
-    private fun openEntry(entry: SettingsEntry): () -> Unit {
+    private fun openEntry(entry: SettingsEntry): (() -> Unit)? {
+        if (entry.hasRuntimeParam()) return null
         val route = entry.buildRoute()
         val context = LocalContext.current
         val intent = Intent(context, browseActivityClass).apply {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 86e75f3d..b0a1cbe 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -19,9 +19,9 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.navigation.NamedNavArgument
+import androidx.navigation.NavType
 import com.android.settingslib.spa.framework.BrowseActivity
 import com.android.settingslib.spa.framework.util.navLink
-import com.android.settingslib.spa.framework.util.normalize
 
 const val INJECT_ENTRY_NAME = "INJECT"
 const val ROOT_ENTRY_NAME = "ROOT"
@@ -85,6 +85,10 @@
                 "?${BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME}=$highlightEntryName"
         return name + parameter.navLink(arguments) + highlightParam
     }
+
+    fun hasRuntimeParam(): Boolean {
+        return parameter.hasRuntimeParam(arguments)
+    }
 }
 
 /**
@@ -139,7 +143,7 @@
      * injected entry. In the long term, we may deprecate the @Composable Page() API in SPP, and
      * use each entries' UI rendering function in the page instead.
      */
-    val uiLayout: (@Composable () -> Unit) = {},
+    val uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
 ) {
     fun formatAll(): String {
         val content = listOf<String>(
@@ -150,10 +154,25 @@
         return content.joinToString("\n")
     }
 
+    private fun getDisplayPage(): SettingsPage {
+        // Display the entry on its from-page, or on its owner page if the from-page is unset.
+        return fromPage ?: owner
+    }
+
     fun buildRoute(): String {
-        // Open entry in its fromPage.
-        val page = fromPage ?: owner
-        return page.buildRoute(name)
+        return getDisplayPage().buildRoute(name)
+    }
+
+    fun hasRuntimeParam(): Boolean {
+        return getDisplayPage().hasRuntimeParam()
+    }
+
+    @Composable
+    fun UiLayout(runtimeArguments: Bundle? = null) {
+        val arguments = Bundle()
+        if (owner.arguments != null) arguments.putAll(owner.arguments)
+        if (runtimeArguments != null) arguments.putAll(runtimeArguments)
+        uiLayoutImpl(arguments)
     }
 }
 
@@ -196,7 +215,7 @@
     private var isAllowSearch: Boolean? = null
 
     private var searchDataFn: () -> SearchData? = { null }
-    private var uiLayoutFn: (@Composable () -> Unit) = {}
+    private var uiLayoutFn: (@Composable (arguments: Bundle?) -> Unit) = {}
 
     fun build(): SettingsEntry {
         return SettingsEntry(
@@ -214,7 +233,7 @@
 
             // functions
             searchData = searchDataFn,
-            uiLayout = uiLayoutFn,
+            uiLayoutImpl = uiLayoutFn,
         )
     }
 
@@ -237,7 +256,7 @@
         return this
     }
 
-    fun setUiLayoutFn(fn: @Composable () -> Unit): SettingsEntryBuilder {
+    fun setUiLayoutFn(fn: @Composable (arguments: Bundle?) -> Unit): SettingsEntryBuilder {
         this.uiLayoutFn = fn
         return this
     }
@@ -272,3 +291,33 @@
 private fun String.toUniqueId(): Int {
     return this.hashCode()
 }
+
+private fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
+    if (this.isEmpty()) return null
+    val normArgs = Bundle()
+    for (navArg in this) {
+        when (navArg.argument.type) {
+            NavType.StringType -> {
+                val value = arguments?.getString(navArg.name)
+                if (value != null)
+                    normArgs.putString(navArg.name, value)
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+            NavType.IntType -> {
+                if (arguments != null && arguments.containsKey(navArg.name))
+                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+        }
+    }
+    return normArgs
+}
+
+private fun List<NamedNavArgument>.hasRuntimeParam(arguments: Bundle? = null): Boolean {
+    for (navArg in this) {
+        if (arguments == null || !arguments.containsKey(navArg.name)) return true
+    }
+    return false
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
index 4e768eb..aaf8107 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
@@ -40,29 +40,6 @@
     return argsArray.joinToString("") { arg -> "/$arg" }
 }
 
-fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
-    if (this.isEmpty()) return null
-    val normArgs = Bundle()
-    for (navArg in this) {
-        when (navArg.argument.type) {
-            NavType.StringType -> {
-                val value = arguments?.getString(navArg.name)
-                if (value != null)
-                    normArgs.putString(navArg.name, value)
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-            NavType.IntType -> {
-                if (arguments != null && arguments.containsKey(navArg.name))
-                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-        }
-    }
-    return normArgs
-}
-
 fun List<NamedNavArgument>.getStringArg(name: String, arguments: Bundle? = null): String? {
     if (this.containsStringArg(name) && arguments != null) {
         return arguments.getString(name)
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
index fd40880..cff3bf8 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
@@ -38,6 +38,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -78,6 +79,7 @@
         batteryOnScreenOff();
     }
 
+    @Ignore("b/244349060")
     @Test
     public void testNoCpuDataForRemovedUser() throws Exception {
         mIam.startUserInBackground(mTestUserId);
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 12f3a16..8aa3e25 100644
--- a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -40,7 +40,8 @@
         EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
         ManualPermissionCheckDetector.ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION,
         SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
-        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS
+        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
+        RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,
     )
 
     override val api: Int
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
new file mode 100644
index 0000000..c3e0428
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
@@ -0,0 +1,927 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.checks.DataFlowAnalyzer
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.UastLintUtils.Companion.findLastAssignment
+import com.android.tools.lint.detector.api.getMethodName
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiVariable
+import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UParenthesizedExpression
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.getContainingUMethod
+import org.jetbrains.uast.isNullLiteral
+import org.jetbrains.uast.skipParenthesizedExprDown
+import org.jetbrains.uast.tryResolve
+
+/**
+ * Detector that identifies `registerReceiver()` calls which are missing the `RECEIVER_EXPORTED` or
+ * `RECEIVER_NOT_EXPORTED` flags on T+.
+ *
+ * TODO: Add API level conditions to better support non-platform code.
+ * 1. Check if registerReceiver() call is reachable on T+.
+ * 2. Check if targetSdkVersion is T+.
+ *
+ * eg: isWithinVersionCheckConditional(context, node, 31, false)
+ * eg: isPrecededByVersionCheckExit(context, node, 31) ?
+ */
+@Suppress("UnstableApiUsage")
+class RegisterReceiverFlagDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> = listOf(
+            "registerReceiver",
+            "registerReceiverAsUser",
+            "registerReceiverForAllUsers"
+    )
+
+    private fun checkIsProtectedReceiverAndReturnUnprotectedActions(
+            filterArg: UExpression,
+            node: UCallExpression,
+            evaluator: ConstantEvaluator
+        ): Pair<Boolean, List<String>> { // isProtected, unprotectedActions
+            val actions = mutableSetOf<String>()
+            val construction = findIntentFilterConstruction(filterArg, node)
+
+            if (construction == null) return Pair(false, listOf<String>())
+            val constructorActionArg = construction.getArgumentForParameter(0)
+            (constructorActionArg?.let(evaluator::evaluate) as? String)?.let(actions::add)
+
+            val actionCollectorVisitor =
+                ActionCollectorVisitor(setOf(construction), node, evaluator)
+
+            val parent = node.getContainingUMethod()
+            parent?.accept(actionCollectorVisitor)
+            actions.addAll(actionCollectorVisitor.actions)
+
+            // If we failed to evaluate any actions, there will be a null action in the set.
+            val isProtected =
+              actions.all(PROTECTED_BROADCASTS::contains) &&
+                !actionCollectorVisitor.intentFilterEscapesScope
+            val unprotectedActionsList = actions.filterNot(PROTECTED_BROADCASTS::contains)
+            return Pair(isProtected, unprotectedActionsList)
+        }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (!context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) return
+
+        // The parameter positions vary across the various registerReceiver*() methods, so rather
+        // than hardcode them we simply look them up based on the parameter name and type.
+        val receiverArg =
+            findArgument(node, method, "android.content.BroadcastReceiver", "receiver")
+        val filterArg = findArgument(node, method, "android.content.IntentFilter", "filter")
+        val flagsArg = findArgument(node, method, "int", "flags")
+
+        if (receiverArg == null || receiverArg.isNullLiteral() || filterArg == null) {
+            return
+        }
+
+        val evaluator = ConstantEvaluator().allowFieldInitializers()
+
+        val (isProtected, unprotectedActionsList) =
+          checkIsProtectedReceiverAndReturnUnprotectedActions(filterArg, node, evaluator)
+
+        val flags = evaluator.evaluate(flagsArg) as? Int
+
+        if (!isProtected) {
+            val actionsList = unprotectedActionsList.joinToString(", ", "", "", -1, "")
+            val message = "$receiverArg is missing 'RECEIVED_EXPORTED` or 'RECEIVE_NOT_EXPORTED' " +
+                            "flag for unprotected broadcast(s) registered for $actionsList."
+            if (flagsArg == null) {
+                context.report(
+                  ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(node), message)
+            } else if (flags != null && (flags and RECEIVER_EXPORTED_FLAG_PRESENT_MASK) == 0) {
+                context.report(
+                  ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(flagsArg), message)
+            }
+        }
+
+        if (DEBUG) {
+            println(node.asRenderString())
+            println("Unprotected Actions: $unprotectedActionsList")
+            println("Protected: $isProtected")
+            println("Flags: $flags")
+        }
+    }
+
+    /** Finds the first argument of a method that matches the given parameter type and name. */
+    private fun findArgument(
+            node: UCallExpression,
+            method: PsiMethod,
+            type: String,
+            name: String
+    ): UExpression? {
+        val psiParameter = method.parameterList.parameters.firstOrNull {
+            it.type.canonicalText == type && it.name == name
+        } ?: return null
+        val argument = node.getArgumentForParameter(psiParameter.parameterIndex())
+        return argument?.skipParenthesizedExprDown()
+    }
+
+    /**
+     * For the supplied expression (eg. intent filter argument), attempts to find its construction.
+     * This will be an `IntentFilter()` constructor, an `IntentFilter.create()` call, or `null`.
+     */
+    private fun findIntentFilterConstruction(
+            expression: UExpression,
+            node: UCallExpression
+    ): UCallExpression? {
+        val resolved = expression.tryResolve()
+
+        if (resolved is PsiVariable) {
+            val assignment = findLastAssignment(resolved, node) ?: return null
+            return findIntentFilterConstruction(assignment, node)
+        }
+
+        if (expression is UParenthesizedExpression) {
+            return findIntentFilterConstruction(expression.expression, node)
+        }
+
+        if (expression is UQualifiedReferenceExpression) {
+            val call = expression.selector as? UCallExpression ?: return null
+            return if (isReturningContext(call)) {
+                // eg. filter.apply { addAction("abc") } --> use filter variable.
+                findIntentFilterConstruction(expression.receiver, node)
+            } else {
+                // eg. IntentFilter.create("abc") --> use create("abc") UCallExpression.
+                findIntentFilterConstruction(call, node)
+            }
+        }
+
+        val method = resolved as? PsiMethod ?: return null
+        return if (isIntentFilterFactoryMethod(method)) {
+            expression as? UCallExpression
+        } else {
+            null
+        }
+    }
+
+    private fun isIntentFilterFactoryMethod(method: PsiMethod) =
+            (method.containingClass?.qualifiedName == "android.content.IntentFilter" &&
+               (method.returnType?.canonicalText == "android.content.IntentFilter" ||
+                    method.isConstructor))
+
+    /**
+     * Returns true if the given call represents a Kotlin scope function where the return value is
+     * the context object; see https://kotlinlang.org/docs/scope-functions.html#function-selection.
+     */
+    private fun isReturningContext(node: UCallExpression): Boolean {
+        val name = getMethodName(node)
+        if (name == "apply" || name == "also") {
+            return isScopingFunction(node)
+        }
+        return false
+    }
+
+    /**
+     * Returns true if the given node appears to be one of the scope functions. Only checks parent
+     * class; caller should intend that it's actually one of let, with, apply, etc.
+     */
+    private fun isScopingFunction(node: UCallExpression): Boolean {
+        val called = node.resolve() ?: return true
+        // See libraries/stdlib/jvm/build/stdlib-declarations.json
+        return called.containingClass?.qualifiedName == "kotlin.StandardKt__StandardKt"
+    }
+
+    inner class ActionCollectorVisitor(
+        start: Collection<UElement>,
+        val functionCall: UCallExpression,
+        val evaluator: ConstantEvaluator,
+    ) : DataFlowAnalyzer(start) {
+       private var finished = false
+       var intentFilterEscapesScope = false; private set
+       val actions = mutableSetOf<String>()
+
+       override fun argument(call: UCallExpression, reference: UElement) {
+           // TODO: Remove this temporary fix for DataFlowAnalyzer bug (ag/15787550):
+           if (reference !in call.valueArguments) return
+           val methodNames = super@RegisterReceiverFlagDetector.getApplicableMethodNames()
+           when {
+               finished -> return
+               // We've reached the registerReceiver*() call in question.
+               call == functionCall -> finished = true
+               // The filter 'intentFilterEscapesScope' to a method which could modify it.
+               methodNames != null && getMethodName(call)!! !in methodNames ->
+                 intentFilterEscapesScope = true
+           }
+       }
+
+       // Fixed in b/199163915: DataFlowAnalyzer doesn't call this for Kotlin properties.
+       override fun field(field: UElement) {
+           if (!finished) intentFilterEscapesScope = true
+       }
+
+       override fun receiver(call: UCallExpression) {
+           if (!finished && getMethodName(call) == "addAction") {
+               val actionArg = call.getArgumentForParameter(0)
+               if (actionArg != null) {
+                   val action = evaluator.evaluate(actionArg) as? String
+                   if (action != null) actions.add(action)
+               }
+           }
+       }
+    }
+
+    companion object {
+        const val DEBUG = false
+
+        private const val RECEIVER_EXPORTED = 0x2
+        private const val RECEIVER_NOT_EXPORTED = 0x4
+        private const val RECEIVER_EXPORTED_FLAG_PRESENT_MASK =
+          RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED
+
+        @JvmField
+        val ISSUE_RECEIVER_EXPORTED_FLAG: Issue = Issue.create(
+                id = "UnspecifiedRegisterReceiverFlag",
+                briefDescription = "Missing `registerReceiver()` exported flag",
+                explanation = """
+                    Apps targeting Android T (SDK 33) and higher must specify either `RECEIVER_EXPORTED` \
+                    or `RECEIVER_NOT_EXPORTED` when registering a broadcast receiver, unless the \
+                    receiver is only registered for protected system broadcast actions.
+                    """,
+                category = Category.SECURITY,
+                priority = 5,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        RegisterReceiverFlagDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        val PROTECTED_BROADCASTS = listOf(
+                "android.intent.action.SCREEN_OFF",
+                "android.intent.action.SCREEN_ON",
+                "android.intent.action.USER_PRESENT",
+                "android.intent.action.TIME_SET",
+                "android.intent.action.TIME_TICK",
+                "android.intent.action.TIMEZONE_CHANGED",
+                "android.intent.action.DATE_CHANGED",
+                "android.intent.action.PRE_BOOT_COMPLETED",
+                "android.intent.action.BOOT_COMPLETED",
+                "android.intent.action.PACKAGE_INSTALL",
+                "android.intent.action.PACKAGE_ADDED",
+                "android.intent.action.PACKAGE_REPLACED",
+                "android.intent.action.MY_PACKAGE_REPLACED",
+                "android.intent.action.PACKAGE_REMOVED",
+                "android.intent.action.PACKAGE_REMOVED_INTERNAL",
+                "android.intent.action.PACKAGE_FULLY_REMOVED",
+                "android.intent.action.PACKAGE_CHANGED",
+                "android.intent.action.PACKAGE_FULLY_LOADED",
+                "android.intent.action.PACKAGE_ENABLE_ROLLBACK",
+                "android.intent.action.CANCEL_ENABLE_ROLLBACK",
+                "android.intent.action.ROLLBACK_COMMITTED",
+                "android.intent.action.PACKAGE_RESTARTED",
+                "android.intent.action.PACKAGE_DATA_CLEARED",
+                "android.intent.action.PACKAGE_FIRST_LAUNCH",
+                "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION",
+                "android.intent.action.PACKAGE_NEEDS_VERIFICATION",
+                "android.intent.action.PACKAGE_VERIFIED",
+                "android.intent.action.PACKAGES_SUSPENDED",
+                "android.intent.action.PACKAGES_UNSUSPENDED",
+                "android.intent.action.PACKAGES_SUSPENSION_CHANGED",
+                "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY",
+                "android.intent.action.DISTRACTING_PACKAGES_CHANGED",
+                "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED",
+                "android.intent.action.UID_REMOVED",
+                "android.intent.action.QUERY_PACKAGE_RESTART",
+                "android.intent.action.CONFIGURATION_CHANGED",
+                "android.intent.action.SPLIT_CONFIGURATION_CHANGED",
+                "android.intent.action.LOCALE_CHANGED",
+                "android.intent.action.APPLICATION_LOCALE_CHANGED",
+                "android.intent.action.BATTERY_CHANGED",
+                "android.intent.action.BATTERY_LEVEL_CHANGED",
+                "android.intent.action.BATTERY_LOW",
+                "android.intent.action.BATTERY_OKAY",
+                "android.intent.action.ACTION_POWER_CONNECTED",
+                "android.intent.action.ACTION_POWER_DISCONNECTED",
+                "android.intent.action.ACTION_SHUTDOWN",
+                "android.intent.action.CHARGING",
+                "android.intent.action.DISCHARGING",
+                "android.intent.action.DEVICE_STORAGE_LOW",
+                "android.intent.action.DEVICE_STORAGE_OK",
+                "android.intent.action.DEVICE_STORAGE_FULL",
+                "android.intent.action.DEVICE_STORAGE_NOT_FULL",
+                "android.intent.action.NEW_OUTGOING_CALL",
+                "android.intent.action.REBOOT",
+                "android.intent.action.DOCK_EVENT",
+                "android.intent.action.THERMAL_EVENT",
+                "android.intent.action.MASTER_CLEAR_NOTIFICATION",
+                "android.intent.action.USER_ADDED",
+                "android.intent.action.USER_REMOVED",
+                "android.intent.action.USER_STARTING",
+                "android.intent.action.USER_STARTED",
+                "android.intent.action.USER_STOPPING",
+                "android.intent.action.USER_STOPPED",
+                "android.intent.action.USER_BACKGROUND",
+                "android.intent.action.USER_FOREGROUND",
+                "android.intent.action.USER_SWITCHED",
+                "android.intent.action.USER_INITIALIZE",
+                "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION",
+                "android.intent.action.DOMAINS_NEED_VERIFICATION",
+                "android.intent.action.OVERLAY_ADDED",
+                "android.intent.action.OVERLAY_CHANGED",
+                "android.intent.action.OVERLAY_REMOVED",
+                "android.intent.action.OVERLAY_PRIORITY_CHANGED",
+                "android.intent.action.MY_PACKAGE_SUSPENDED",
+                "android.intent.action.MY_PACKAGE_UNSUSPENDED",
+                "android.os.action.POWER_SAVE_MODE_CHANGED",
+                "android.os.action.DEVICE_IDLE_MODE_CHANGED",
+                "android.os.action.POWER_SAVE_WHITELIST_CHANGED",
+                "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED",
+                "android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL",
+                "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED",
+                "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED",
+                "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED",
+                "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL",
+                "android.app.action.ENTER_CAR_MODE",
+                "android.app.action.EXIT_CAR_MODE",
+                "android.app.action.ENTER_CAR_MODE_PRIORITIZED",
+                "android.app.action.EXIT_CAR_MODE_PRIORITIZED",
+                "android.app.action.ENTER_DESK_MODE",
+                "android.app.action.EXIT_DESK_MODE",
+                "android.app.action.NEXT_ALARM_CLOCK_CHANGED",
+                "android.app.action.USER_ADDED",
+                "android.app.action.USER_REMOVED",
+                "android.app.action.USER_STARTED",
+                "android.app.action.USER_STOPPED",
+                "android.app.action.USER_SWITCHED",
+                "android.app.action.BUGREPORT_SHARING_DECLINED",
+                "android.app.action.BUGREPORT_FAILED",
+                "android.app.action.BUGREPORT_SHARE",
+                "android.app.action.SHOW_DEVICE_MONITORING_DIALOG",
+                "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED",
+                "android.intent.action.INCIDENT_REPORT_READY",
+                "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS",
+                "android.appwidget.action.APPWIDGET_DELETED",
+                "android.appwidget.action.APPWIDGET_DISABLED",
+                "android.appwidget.action.APPWIDGET_ENABLED",
+                "android.appwidget.action.APPWIDGET_HOST_RESTORED",
+                "android.appwidget.action.APPWIDGET_RESTORED",
+                "android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE",
+                "android.os.action.SETTING_RESTORED",
+                "android.app.backup.intent.CLEAR",
+                "android.app.backup.intent.INIT",
+                "android.bluetooth.intent.DISCOVERABLE_TIMEOUT",
+                "android.bluetooth.adapter.action.STATE_CHANGED",
+                "android.bluetooth.adapter.action.SCAN_MODE_CHANGED",
+                "android.bluetooth.adapter.action.DISCOVERY_STARTED",
+                "android.bluetooth.adapter.action.DISCOVERY_FINISHED",
+                "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED",
+                "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED",
+                "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.device.action.UUID",
+                "android.bluetooth.device.action.MAS_INSTANCE",
+                "android.bluetooth.device.action.ALIAS_CHANGED",
+                "android.bluetooth.device.action.FOUND",
+                "android.bluetooth.device.action.CLASS_CHANGED",
+                "android.bluetooth.device.action.ACL_CONNECTED",
+                "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED",
+                "android.bluetooth.device.action.ACL_DISCONNECTED",
+                "android.bluetooth.device.action.NAME_CHANGED",
+                "android.bluetooth.device.action.BOND_STATE_CHANGED",
+                "android.bluetooth.device.action.NAME_FAILED",
+                "android.bluetooth.device.action.PAIRING_REQUEST",
+                "android.bluetooth.device.action.PAIRING_CANCEL",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST",
+                "android.bluetooth.device.action.SDP_RECORD",
+                "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED",
+                "android.bluetooth.devicepicker.action.LAUNCH",
+                "android.bluetooth.devicepicker.action.DEVICE_SELECTED",
+                "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.CSIS_DEVICE_AVAILABLE",
+                "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE",
+                "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_CONF_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED",
+                "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED",
+                "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION",
+                "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT",
+                "android.btopp.intent.action.LIST",
+                "android.btopp.intent.action.OPEN_OUTBOUND",
+                "android.btopp.intent.action.HIDE_COMPLETE",
+                "android.btopp.intent.action.CONFIRM",
+                "android.btopp.intent.action.HIDE",
+                "android.btopp.intent.action.RETRY",
+                "android.btopp.intent.action.OPEN",
+                "android.btopp.intent.action.OPEN_INBOUND",
+                "android.btopp.intent.action.TRANSFER_COMPLETE",
+                "android.btopp.intent.action.ACCEPT",
+                "android.btopp.intent.action.DECLINE",
+                "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN",
+                "com.android.bluetooth.pbap.authchall",
+                "com.android.bluetooth.pbap.userconfirmtimeout",
+                "com.android.bluetooth.pbap.authresponse",
+                "com.android.bluetooth.pbap.authcancelled",
+                "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT",
+                "com.android.bluetooth.sap.action.DISCONNECT_ACTION",
+                "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED",
+                "android.hardware.usb.action.USB_STATE",
+                "android.hardware.usb.action.USB_PORT_CHANGED",
+                "android.hardware.usb.action.USB_ACCESSORY_ATTACHED",
+                "android.hardware.usb.action.USB_ACCESSORY_DETACHED",
+                "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE",
+                "android.hardware.usb.action.USB_DEVICE_ATTACHED",
+                "android.hardware.usb.action.USB_DEVICE_DETACHED",
+                "android.intent.action.HEADSET_PLUG",
+                "android.media.action.HDMI_AUDIO_PLUG",
+                "android.media.action.MICROPHONE_MUTE_CHANGED",
+                "android.media.action.SPEAKERPHONE_STATE_CHANGED",
+                "android.media.AUDIO_BECOMING_NOISY",
+                "android.media.RINGER_MODE_CHANGED",
+                "android.media.VIBRATE_SETTING_CHANGED",
+                "android.media.VOLUME_CHANGED_ACTION",
+                "android.media.MASTER_VOLUME_CHANGED_ACTION",
+                "android.media.MASTER_MUTE_CHANGED_ACTION",
+                "android.media.MASTER_MONO_CHANGED_ACTION",
+                "android.media.MASTER_BALANCE_CHANGED_ACTION",
+                "android.media.SCO_AUDIO_STATE_CHANGED",
+                "android.media.ACTION_SCO_AUDIO_STATE_UPDATED",
+                "android.intent.action.MEDIA_REMOVED",
+                "android.intent.action.MEDIA_UNMOUNTED",
+                "android.intent.action.MEDIA_CHECKING",
+                "android.intent.action.MEDIA_NOFS",
+                "android.intent.action.MEDIA_MOUNTED",
+                "android.intent.action.MEDIA_SHARED",
+                "android.intent.action.MEDIA_UNSHARED",
+                "android.intent.action.MEDIA_BAD_REMOVAL",
+                "android.intent.action.MEDIA_UNMOUNTABLE",
+                "android.intent.action.MEDIA_EJECT",
+                "android.net.conn.CAPTIVE_PORTAL",
+                "android.net.conn.CONNECTIVITY_CHANGE",
+                "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE",
+                "android.net.conn.DATA_ACTIVITY_CHANGE",
+                "android.net.conn.RESTRICT_BACKGROUND_CHANGED",
+                "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED",
+                "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
+                "android.net.nsd.STATE_CHANGED",
+                "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED",
+                "android.nfc.action.ADAPTER_STATE_CHANGED",
+                "android.nfc.action.PREFERRED_PAYMENT_CHANGED",
+                "android.nfc.action.TRANSACTION_DETECTED",
+                "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC",
+                "com.android.nfc.action.LLCP_UP",
+                "com.android.nfc.action.LLCP_DOWN",
+                "com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG",
+                "com.android.nfc.handover.action.ALLOW_CONNECT",
+                "com.android.nfc.handover.action.DENY_CONNECT",
+                "com.android.nfc.handover.action.TIMEOUT_CONNECT",
+                "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED",
+                "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED",
+                "com.android.nfc_extras.action.AID_SELECTED",
+                "android.btopp.intent.action.WHITELIST_DEVICE",
+                "android.btopp.intent.action.STOP_HANDOVER_TRANSFER",
+                "android.nfc.handover.intent.action.HANDOVER_SEND",
+                "android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE",
+                "com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER",
+                "android.net.action.CLEAR_DNS_CACHE",
+                "android.intent.action.PROXY_CHANGE",
+                "android.os.UpdateLock.UPDATE_LOCK_CHANGED",
+                "android.intent.action.DREAMING_STARTED",
+                "android.intent.action.DREAMING_STOPPED",
+                "android.intent.action.ANY_DATA_STATE",
+                "com.android.server.stats.action.TRIGGER_COLLECTION",
+                "com.android.server.WifiManager.action.START_SCAN",
+                "com.android.server.WifiManager.action.START_PNO",
+                "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP",
+                "com.android.server.WifiManager.action.DEVICE_IDLE",
+                "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED",
+                "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED",
+                "com.android.internal.action.EUICC_FACTORY_RESET",
+                "com.android.server.usb.ACTION_OPEN_IN_APPS",
+                "com.android.server.am.DELETE_DUMPHEAP",
+                "com.android.server.net.action.SNOOZE_WARNING",
+                "com.android.server.net.action.SNOOZE_RAPID",
+                "com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED",
+                "com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER",
+                "com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER",
+                "com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED",
+                "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION",
+                "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK",
+                "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK",
+                "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE",
+                "com.android.server.wifi.wakeup.DISMISS_NOTIFICATION",
+                "com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES",
+                "com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS",
+                "com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE",
+                "android.net.wifi.WIFI_STATE_CHANGED",
+                "android.net.wifi.WIFI_AP_STATE_CHANGED",
+                "android.net.wifi.WIFI_CREDENTIAL_CHANGED",
+                "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED",
+                "android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED",
+                "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED",
+                "android.net.wifi.SCAN_RESULTS",
+                "android.net.wifi.RSSI_CHANGED",
+                "android.net.wifi.STATE_CHANGE",
+                "android.net.wifi.LINK_CONFIGURATION_CHANGED",
+                "android.net.wifi.CONFIGURED_NETWORKS_CHANGE",
+                "android.net.wifi.action.NETWORK_SETTINGS_RESET",
+                "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT",
+                "android.net.wifi.action.PASSPOINT_ICON",
+                "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST",
+                "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION",
+                "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW",
+                "android.net.wifi.action.REFRESH_USER_PROVISIONING",
+                "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION",
+                "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED",
+                "android.net.wifi.supplicant.CONNECTION_CHANGE",
+                "android.net.wifi.supplicant.STATE_CHANGE",
+                "android.net.wifi.p2p.STATE_CHANGED",
+                "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE",
+                "android.net.wifi.p2p.THIS_DEVICE_CHANGED",
+                "android.net.wifi.p2p.PEERS_CHANGED",
+                "android.net.wifi.p2p.CONNECTION_STATE_CHANGE",
+                "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED",
+                "android.net.conn.TETHER_STATE_CHANGED",
+                "android.net.conn.INET_CONDITION_ACTION",
+                "android.net.conn.NETWORK_CONDITIONS_MEASURED",
+                "android.net.scoring.SCORE_NETWORKS",
+                "android.net.scoring.SCORER_CHANGED",
+                "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE",
+                "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE",
+                "android.intent.action.AIRPLANE_MODE",
+                "android.intent.action.ADVANCED_SETTINGS",
+                "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED",
+                "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES",
+                "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT",
+                "com.android.server.adb.WIRELESS_DEBUG_STATUS",
+                "android.intent.action.ACTION_IDLE_MAINTENANCE_START",
+                "android.intent.action.ACTION_IDLE_MAINTENANCE_END",
+                "com.android.server.ACTION_TRIGGER_IDLE",
+                "android.intent.action.HDMI_PLUGGED",
+                "android.intent.action.PHONE_STATE",
+                "android.intent.action.SUB_DEFAULT_CHANGED",
+                "android.location.PROVIDERS_CHANGED",
+                "android.location.MODE_CHANGED",
+                "android.location.action.GNSS_CAPABILITIES_CHANGED",
+                "android.net.proxy.PAC_REFRESH",
+                "android.telecom.action.DEFAULT_DIALER_CHANGED",
+                "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED",
+                "android.provider.action.SMS_MMS_DB_CREATED",
+                "android.provider.action.SMS_MMS_DB_LOST",
+                "android.intent.action.CONTENT_CHANGED",
+                "android.provider.Telephony.MMS_DOWNLOADED",
+                "android.content.action.PERMISSION_RESPONSE_RECEIVED",
+                "android.content.action.REQUEST_PERMISSION",
+                "android.nfc.handover.intent.action.HANDOVER_STARTED",
+                "android.nfc.handover.intent.action.TRANSFER_DONE",
+                "android.nfc.handover.intent.action.TRANSFER_PROGRESS",
+                "android.nfc.handover.intent.action.TRANSFER_DONE",
+                "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED",
+                "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED",
+                "android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE",
+                "android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED",
+                "android.internal.policy.action.BURN_IN_PROTECTION",
+                "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED",
+                "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
+                "android.app.action.DEVICE_OWNER_CHANGED",
+                "android.app.action.MANAGED_USER_CREATED",
+                "android.intent.action.ANR",
+                "android.intent.action.CALL",
+                "android.intent.action.CALL_PRIVILEGED",
+                "android.intent.action.DROPBOX_ENTRY_ADDED",
+                "android.intent.action.INPUT_METHOD_CHANGED",
+                "android.intent.action.internal_sim_state_changed",
+                "android.intent.action.LOCKED_BOOT_COMPLETED",
+                "android.intent.action.PRECISE_CALL_STATE",
+                "android.intent.action.SUBSCRIPTION_PHONE_STATE",
+                "android.intent.action.USER_INFO_CHANGED",
+                "android.intent.action.USER_UNLOCKED",
+                "android.intent.action.WALLPAPER_CHANGED",
+                "android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED",
+                "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS",
+                "android.app.action.DEVICE_ADMIN_DISABLED",
+                "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED",
+                "android.app.action.DEVICE_ADMIN_ENABLED",
+                "android.app.action.LOCK_TASK_ENTERING",
+                "android.app.action.LOCK_TASK_EXITING",
+                "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE",
+                "android.app.action.ACTION_PASSWORD_CHANGED",
+                "android.app.action.ACTION_PASSWORD_EXPIRING",
+                "android.app.action.ACTION_PASSWORD_FAILED",
+                "android.app.action.ACTION_PASSWORD_SUCCEEDED",
+                "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION",
+                "com.android.server.ACTION_PROFILE_OFF_DEADLINE",
+                "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION",
+                "android.intent.action.MANAGED_PROFILE_ADDED",
+                "android.intent.action.MANAGED_PROFILE_UNLOCKED",
+                "android.intent.action.MANAGED_PROFILE_REMOVED",
+                "android.app.action.MANAGED_PROFILE_PROVISIONED",
+                "android.bluetooth.adapter.action.BLE_STATE_CHANGED",
+                "com.android.bluetooth.map.USER_CONFIRM_TIMEOUT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
+                "android.content.jobscheduler.JOB_DELAY_EXPIRED",
+                "android.content.syncmanager.SYNC_ALARM",
+                "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION",
+                "android.media.STREAM_DEVICES_CHANGED_ACTION",
+                "android.media.STREAM_MUTE_CHANGED_ACTION",
+                "android.net.sip.SIP_SERVICE_UP",
+                "android.nfc.action.ADAPTER_STATE_CHANGED",
+                "android.os.action.CHARGING",
+                "android.os.action.DISCHARGING",
+                "android.search.action.SEARCHABLES_CHANGED",
+                "android.security.STORAGE_CHANGED",
+                "android.security.action.TRUST_STORE_CHANGED",
+                "android.security.action.KEYCHAIN_CHANGED",
+                "android.security.action.KEY_ACCESS_CHANGED",
+                "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED",
+                "android.telecom.action.PHONE_ACCOUNT_REGISTERED",
+                "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED",
+                "android.telecom.action.POST_CALL",
+                "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION",
+                "android.telephony.action.CARRIER_CONFIG_CHANGED",
+                "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED",
+                "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED",
+                "android.telephony.action.SECRET_CODE",
+                "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION",
+                "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED",
+                "com.android.bluetooth.btservice.action.ALARM_WAKEUP",
+                "com.android.server.action.NETWORK_STATS_POLL",
+                "com.android.server.action.NETWORK_STATS_UPDATED",
+                "com.android.server.timedetector.NetworkTimeUpdateService.action.POLL",
+                "com.android.server.telecom.intent.action.CALLS_ADD_ENTRY",
+                "com.android.settings.location.MODE_CHANGING",
+                "com.android.settings.bluetooth.ACTION_DISMISS_PAIRING",
+                "com.android.settings.network.DELETE_SUBSCRIPTION",
+                "com.android.settings.network.SWITCH_TO_SUBSCRIPTION",
+                "com.android.settings.wifi.action.NETWORK_REQUEST",
+                "NotificationManagerService.TIMEOUT",
+                "NotificationHistoryDatabase.CLEANUP",
+                "ScheduleConditionProvider.EVALUATE",
+                "EventConditionProvider.EVALUATE",
+                "SnoozeHelper.EVALUATE",
+                "wifi_scan_available",
+                "action.cne.started",
+                "android.content.jobscheduler.JOB_DEADLINE_EXPIRED",
+                "android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW",
+                "android.net.conn.CONNECTIVITY_CHANGE_SUPL",
+                "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED",
+                "android.os.storage.action.VOLUME_STATE_CHANGED",
+                "android.os.storage.action.DISK_SCANNED",
+                "com.android.server.action.UPDATE_TWILIGHT_STATE",
+                "com.android.server.action.RESET_TWILIGHT_AUTO",
+                "com.android.server.device_idle.STEP_IDLE_STATE",
+                "com.android.server.device_idle.STEP_LIGHT_IDLE_STATE",
+                "com.android.server.Wifi.action.TOGGLE_PNO",
+                "intent.action.ACTION_RF_BAND_INFO",
+                "android.intent.action.MEDIA_RESOURCE_GRANTED",
+                "android.app.action.NETWORK_LOGS_AVAILABLE",
+                "android.app.action.SECURITY_LOGS_AVAILABLE",
+                "android.app.action.COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED",
+                "android.app.action.INTERRUPTION_FILTER_CHANGED",
+                "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL",
+                "android.app.action.NOTIFICATION_POLICY_CHANGED",
+                "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED",
+                "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED",
+                "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED",
+                "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED",
+                "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED",
+                "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED",
+                "android.app.action.APP_BLOCK_STATE_CHANGED",
+                "android.permission.GET_APP_GRANTED_URI_PERMISSIONS",
+                "android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS",
+                "android.intent.action.DYNAMIC_SENSOR_CHANGED",
+                "android.accounts.LOGIN_ACCOUNTS_CHANGED",
+                "android.accounts.action.ACCOUNT_REMOVED",
+                "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED",
+                "com.android.sync.SYNC_CONN_STATUS_CHANGED",
+                "android.net.sip.action.SIP_INCOMING_CALL",
+                "com.android.phone.SIP_ADD_PHONE",
+                "android.net.sip.action.SIP_REMOVE_PROFILE",
+                "android.net.sip.action.SIP_SERVICE_UP",
+                "android.net.sip.action.SIP_CALL_OPTION_CHANGED",
+                "android.net.sip.action.START_SIP",
+                "android.bluetooth.adapter.action.BLE_ACL_CONNECTED",
+                "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED",
+                "android.bluetooth.input.profile.action.HANDSHAKE",
+                "android.bluetooth.input.profile.action.REPORT",
+                "android.intent.action.TWILIGHT_CHANGED",
+                "com.android.server.fingerprint.ACTION_LOCKOUT_RESET",
+                "android.net.wifi.PASSPOINT_ICON_RECEIVED",
+                "com.android.server.notification.CountdownConditionProvider",
+                "android.server.notification.action.ENABLE_NAS",
+                "android.server.notification.action.DISABLE_NAS",
+                "android.server.notification.action.LEARNMORE_NAS",
+                "com.android.internal.location.ALARM_WAKEUP",
+                "com.android.internal.location.ALARM_TIMEOUT",
+                "android.intent.action.GLOBAL_BUTTON",
+                "android.intent.action.MANAGED_PROFILE_AVAILABLE",
+                "android.intent.action.MANAGED_PROFILE_UNAVAILABLE",
+                "com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK",
+                "android.intent.action.PROFILE_ACCESSIBLE",
+                "android.intent.action.PROFILE_INACCESSIBLE",
+                "com.android.server.retaildemo.ACTION_RESET_DEMO",
+                "android.intent.action.DEVICE_LOCKED_CHANGED",
+                "com.android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED",
+                "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED",
+                "com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION",
+                "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED",
+                "android.content.pm.action.SESSION_COMMITTED",
+                "android.os.action.USER_RESTRICTIONS_CHANGED",
+                "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT",
+                "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED",
+                "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED",
+                "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED",
+                "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER",
+                "com.android.intent.action.timezone.RULES_UPDATE_OPERATION",
+                "com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK",
+                "android.intent.action.GET_RESTRICTION_ENTRIES",
+                "android.telephony.euicc.action.OTA_STATUS_CHANGED",
+                "android.app.action.PROFILE_OWNER_CHANGED",
+                "android.app.action.TRANSFER_OWNERSHIP_COMPLETE",
+                "android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE",
+                "android.app.action.STATSD_STARTED",
+                "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET",
+                "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET",
+                "android.intent.action.DOCK_IDLE",
+                "android.intent.action.DOCK_ACTIVE",
+                "android.content.pm.action.SESSION_UPDATED",
+                "android.settings.action.GRAYSCALE_CHANGED",
+                "com.android.server.jobscheduler.GARAGE_MODE_ON",
+                "com.android.server.jobscheduler.GARAGE_MODE_OFF",
+                "com.android.server.jobscheduler.FORCE_IDLE",
+                "com.android.server.jobscheduler.UNFORCE_IDLE",
+                "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL",
+                "android.intent.action.DEVICE_CUSTOMIZATION_READY",
+                "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
+                "com.android.internal.intent.action.BUGREPORT_REQUESTED",
+                "android.scheduling.action.REBOOT_READY",
+                "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED",
+                "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED",
+                "android.app.action.SHOW_NEW_USER_DISCLAIMER",
+                "android.telecom.action.CURRENT_TTY_MODE_CHANGED",
+                "android.intent.action.SERVICE_STATE",
+                "android.intent.action.RADIO_TECHNOLOGY",
+                "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED",
+                "android.intent.action.EMERGENCY_CALL_STATE_CHANGED",
+                "android.intent.action.SIG_STR",
+                "android.intent.action.ANY_DATA_STATE",
+                "android.intent.action.DATA_STALL_DETECTED",
+                "android.intent.action.SIM_STATE_CHANGED",
+                "android.intent.action.USER_ACTIVITY_NOTIFICATION",
+                "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS",
+                "android.intent.action.ACTION_MDN_STATE_CHANGED",
+                "android.telephony.action.SERVICE_PROVIDERS_UPDATED",
+                "android.provider.Telephony.SIM_FULL",
+                "com.android.internal.telephony.carrier_key_download_alarm",
+                "com.android.internal.telephony.data-restart-trysetup",
+                "com.android.internal.telephony.data-stall",
+                "com.android.internal.telephony.provisioning_apn_alarm",
+                "android.intent.action.DATA_SMS_RECEIVED",
+                "android.provider.Telephony.SMS_RECEIVED",
+                "android.provider.Telephony.SMS_DELIVER",
+                "android.provider.Telephony.SMS_REJECTED",
+                "android.provider.Telephony.WAP_PUSH_DELIVER",
+                "android.provider.Telephony.WAP_PUSH_RECEIVED",
+                "android.provider.Telephony.SMS_CB_RECEIVED",
+                "android.provider.action.SMS_EMERGENCY_CB_RECEIVED",
+                "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED",
+                "android.provider.Telephony.SECRET_CODE",
+                "com.android.internal.stk.command",
+                "com.android.internal.stk.session_end",
+                "com.android.internal.stk.icc_status_change",
+                "com.android.internal.stk.alpha_notify",
+                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED",
+                "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
+                "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE",
+                "com.android.internal.telephony.CARRIER_SIGNAL_RESET",
+                "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
+                "com.android.internal.telephony.PROVISION",
+                "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED",
+                "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED",
+                "com.android.intent.isim_refresh",
+                "com.android.ims.ACTION_RCS_SERVICE_AVAILABLE",
+                "com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE",
+                "com.android.ims.ACTION_RCS_SERVICE_DIED",
+                "com.android.ims.ACTION_PRESENCE_CHANGED",
+                "com.android.ims.ACTION_PUBLISH_STATUS_CHANGED",
+                "com.android.ims.IMS_SERVICE_UP",
+                "com.android.ims.IMS_SERVICE_DOWN",
+                "com.android.ims.IMS_INCOMING_CALL",
+                "com.android.ims.internal.uce.UCE_SERVICE_UP",
+                "com.android.ims.internal.uce.UCE_SERVICE_DOWN",
+                "com.android.imsconnection.DISCONNECTED",
+                "com.android.intent.action.IMS_FEATURE_CHANGED",
+                "com.android.intent.action.IMS_CONFIG_CHANGED",
+                "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR",
+                "com.android.phone.vvm.omtp.sms.REQUEST_SENT",
+                "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT",
+                "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED",
+                "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO",
+                "com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD",
+                "com.android.internal.telephony.action.COUNTRY_OVERRIDE",
+                "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP",
+                "com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID",
+                "android.telephony.action.SIM_CARD_STATE_CHANGED",
+                "android.telephony.action.SIM_APPLICATION_STATE_CHANGED",
+                "android.telephony.action.SIM_SLOT_STATUS_CHANGED",
+                "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
+                "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
+                "android.telephony.action.TOGGLE_PROVISION",
+                "android.telephony.action.NETWORK_COUNTRY_CHANGED",
+                "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED",
+                "android.telephony.action.MULTI_SIM_CONFIG_CHANGED",
+                "android.telephony.action.CARRIER_SIGNAL_RESET",
+                "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE",
+                "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
+                "android.telephony.action.CARRIER_SIGNAL_REDIRECTED",
+                "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
+                "com.android.phone.settings.CARRIER_PROVISIONING",
+                "com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING",
+                "com.android.internal.telephony.ACTION_VOWIFI_ENABLED",
+                "android.telephony.action.ANOMALY_REPORTED",
+                "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED",
+                "android.intent.action.ACTION_MANAGED_ROAMING_IND",
+                "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE",
+                "android.safetycenter.action.REFRESH_SAFETY_SOURCES",
+                "android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED",
+                "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED",
+                "android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER",
+                "android.service.autofill.action.DELAYED_FILL",
+                "android.app.action.PROVISIONING_COMPLETED",
+                "android.app.action.LOST_MODE_LOCATION_UPDATE",
+                "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED",
+                "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT",
+                "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED",
+                "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.AG_EVENT",
+                "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.RESULT",
+                "android.bluetooth.headsetclient.profile.action.LAST_VTAG",
+                "android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.BROWSE_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST",
+                "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT",
+                "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED",
+                "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED",
+                "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS",
+                "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
+                "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.TETHERING_STATE_CHANGED",
+                "com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS",
+                "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED",
+                "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION",
+                "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"
+        )
+    }
+}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
new file mode 100644
index 0000000..b76342a
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class RegisterReceiverFlagDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = RegisterReceiverFlagDetector()
+
+    override fun getIssues(): List<Issue> = listOf(
+            RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    fun testProtectedBroadcast() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testProtectedBroadcastCreate() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter =
+                                    IntentFilter.create(Intent.ACTION_BATTERY_CHANGED, "foo/bar");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testMultipleProtectedBroadcasts() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            filter.addAction(Intent.ACTION_BATTERY_LOW);
+                            filter.addAction(Intent.ACTION_BATTERY_OKAY);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testSubsequentFilterModification() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            filter.addAction(Intent.ACTION_BATTERY_LOW);
+                            filter.addAction(Intent.ACTION_BATTERY_OKAY);
+                            context.registerReceiver(receiver, filter);
+                            filter.addAction("querty");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:13: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testNullReceiver() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(null, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testExportedFlagPresent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testNotExportedFlagPresent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter,
+                                    Context.RECEIVER_NOT_EXPORTED);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testFlagArgumentAbsent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testExportedFlagsAbsent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter, 0);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter, 0);
+                                                                   ~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testExportedFlagVariable() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            var flags = Context.RECEIVER_EXPORTED;
+                            context.registerReceiver(receiver, filter, flags);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testUnknownFilter() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver,
+                                IntentFilter filter) {
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterEscapes() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            updateFilter(filter);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:10: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testInlineFilter() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            context.registerReceiver(receiver,
+                                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testInlineFilterApply() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            context.registerReceiver(receiver,
+                                    IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                        addAction("qwerty")
+                                    })
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:8: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver,
+                        ^
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterVariableApply() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction("qwerty")
+                            }
+                            context.registerReceiver(receiver, filter)
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter)
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterVariableApply2() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction(Intent.ACTION_BATTERY_OKAY)
+                            }
+                            context.registerReceiver(receiver, filter.apply {
+                                addAction("qwerty")
+                            })
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter.apply {
+                        ^
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterComplexChain() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction(Intent.ACTION_BATTERY_OKAY)
+                            }
+                            val filter2 = filter
+                            val filter3 = filter2.apply {
+                                addAction(Intent.ACTION_BATTERY_LOW)
+                            }
+                            context.registerReceiver(receiver, filter3)
+                            val filter4 = filter3.apply {
+                                addAction("qwerty")
+                            }
+                            context.registerReceiver(receiver, filter4)
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:19: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter4)
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    private val broadcastReceiverStub: TestFile = java(
+            """
+            package android.content;
+            public class BroadcastReceiver {
+                // Stub
+            }
+            """
+    ).indented()
+
+    private val contextStub: TestFile = java(
+            """
+            package android.content;
+            public class Context {
+                public static final int RECEIVER_EXPORTED = 0x2;
+                public static final int RECEIVER_NOT_EXPORTED = 0x4;
+                @Nullable
+                public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
+                                                        IntentFilter filter,
+                                                        @RegisterReceiverFlags int flags);
+            }
+            """
+    ).indented()
+
+    private val intentStub: TestFile = java(
+            """
+            package android.content;
+            public class Intent {
+                public static final String ACTION_BATTERY_CHANGED =
+                        "android.intent.action.BATTERY_CHANGED";
+                public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
+                public static final String ACTION_BATTERY_OKAY =
+                        "android.intent.action.BATTERY_OKAY";
+            }
+            """
+    ).indented()
+
+    private val intentFilterStub: TestFile = java(
+            """
+            package android.content;
+            public class IntentFilter {
+                public IntentFilter() {
+                    // Stub
+                }
+                public IntentFilter(String action) {
+                    // Stub
+                }
+                public IntentFilter(String action, String dataType) {
+                    // Stub
+                }
+                public static IntentFilter create(String action, String dataType) {
+                    return null;
+                }
+                public final void addAction(String action) {
+                    // Stub
+                }
+            }
+            """
+    ).indented()
+
+    private val stubs = arrayOf(broadcastReceiverStub, contextStub, intentStub, intentFilterStub)
+}