Skip to content

Commit 8bdc8be

Browse files
committed
fix(settings): declare package visibility for the source pickers
targetSdk is 36 and the manifest had no <queries> block, so on Android 11+ getApplicationInfo() threw NameNotFoundException for every other app. The push-alert source sheet showed every source as "Not installed" and disabled its switch; the notification-screening sheet mislabeled installed sources. A notification listener gets no automatic package visibility. The manifest now names every package in PushAlertRegistry.ALERT_SOURCE_PACKAGES and NotificationScreeningSources.catalog. No permission is added and QUERY_ALL_PACKAGES is not requested. Verified on an API 35 emulator with `dumpsys package queries`: the HEAD build had no "queries via package name" entry and the image reports "system apps queryable: false"; the fixed build can see Messages, Gmail and Calendar. ManifestQueriesTest keeps <queries> equal to the two catalogs (mutation-checked by deleting one package line).
1 parent f7596ff commit 8bdc8be

3 files changed

Lines changed: 103 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ All notable changes to CallShield will be documented in this file.
114114
SMS receiver and the notification reader each logged it, so it showed up
115115
twice in the log and the statistics. The alert now says the text was
116116
flagged, not blocked, since it still reaches your messages app.
117+
- The trusted-source and message-screening pickers in Settings now see your
118+
installed apps on Android 11 and later. Android hides other apps from an app
119+
unless its manifest names them, and CallShield's named none, so every source
120+
showed as "Not installed", Google Messages included, and a trusted source
121+
couldn't be switched off. The manifest now names the apps on those two lists
122+
and nothing else.
117123

118124
### Live caller lookup
119125

‎app/src/main/AndroidManifest.xml‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@
1818
android:name="android.hardware.telephony"
1919
android:required="false" />
2020

21+
<!-- Package visibility (API 30+) for the apps the notification-source pickers
22+
list. Without it getApplicationInfo() fails for every one of them, and the
23+
pickers report installed apps as missing. ManifestQueriesTest keeps this
24+
list in step with the catalogs. -->
25+
<queries>
26+
<!-- Push-alert sources (PushAlertRegistry.ALERT_SOURCE_PACKAGES) -->
27+
<package android:name="com.amazon.logistics.driver" />
28+
<package android:name="com.amazon.mShop.android.shopping" />
29+
<package android:name="com.android.mms" />
30+
<package android:name="com.dd.doordash" />
31+
<package android:name="com.fedex.ida.android" />
32+
<package android:name="com.google.android.apps.messaging" />
33+
<package android:name="com.google.android.calendar" />
34+
<package android:name="com.grubhub.android" />
35+
<package android:name="com.instacart.client" />
36+
<package android:name="com.lyft.android" />
37+
<package android:name="com.microsoft.office.outlook" />
38+
<package android:name="com.samsung.android.messaging" />
39+
<package android:name="com.ubercab" />
40+
<package android:name="com.ubercab.driver" />
41+
<package android:name="com.ubercab.eats" />
42+
<package android:name="com.ups.mobile.android" />
43+
<package android:name="gov.usps.mobile" />
44+
<!-- Notification screening sources (NotificationScreeningSources.catalog) -->
45+
<package android:name="com.google.android.gm" />
46+
<package android:name="com.microsoft.android.smsorganizer" />
47+
<package android:name="com.whatsapp" />
48+
<package android:name="com.whatsapp.w4b" />
49+
<package android:name="net.thunderbird.android" />
50+
<package android:name="org.thoughtcrime.securesms" />
51+
</queries>
52+
2153
<application
2254
android:name=".CallShieldApp"
2355
android:allowBackup="true"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.sysadmindoc.callshield
2+
3+
import com.sysadmindoc.callshield.data.NotificationScreeningSources
4+
import com.sysadmindoc.callshield.data.PushAlertRegistry
5+
import org.junit.Assert.assertEquals
6+
import org.junit.Assert.assertTrue
7+
import org.junit.Test
8+
import org.w3c.dom.Element
9+
import java.io.File
10+
import javax.xml.parsers.DocumentBuilderFactory
11+
12+
/**
13+
* On API 30+ an app can only look up the packages it declares in `<queries>`.
14+
* The source pickers call getApplicationInfo() for every catalog package, so a
15+
* package missing from the manifest shows as "Not installed" even when it is.
16+
*/
17+
class ManifestQueriesTest {
18+
@Test
19+
fun `manifest queries every catalog package the source pickers look up`() {
20+
val declared = declaredQueryPackages()
21+
val expected =
22+
PushAlertRegistry.ALERT_SOURCE_PACKAGES +
23+
NotificationScreeningSources.catalog.map { it.packageName }
24+
25+
assertEquals("catalog packages missing from <queries>", emptySet<String>(), expected - declared)
26+
assertEquals("<queries> packages no catalog uses", emptySet<String>(), declared - expected)
27+
}
28+
29+
@Test
30+
fun `queries block adds package visibility without a new permission`() {
31+
val manifest = locate(MANIFEST_PATH).readText()
32+
33+
assertTrue(declaredQueryPackages().isNotEmpty())
34+
assertTrue("QUERY_ALL_PACKAGES must not be requested", "QUERY_ALL_PACKAGES" !in manifest)
35+
}
36+
37+
private fun declaredQueryPackages(): Set<String> {
38+
val factory = DocumentBuilderFactory.newInstance().apply { isNamespaceAware = true }
39+
val document = factory.newDocumentBuilder().parse(locate(MANIFEST_PATH))
40+
val queries = document.getElementsByTagName("queries")
41+
val packages = mutableSetOf<String>()
42+
for (index in 0 until queries.length) {
43+
val entries = (queries.item(index) as Element).getElementsByTagName("package")
44+
for (entry in 0 until entries.length) {
45+
packages += (entries.item(entry) as Element).getAttributeNS(ANDROID_NAMESPACE, "name")
46+
}
47+
}
48+
return packages
49+
}
50+
51+
private fun locate(relativePath: String): File {
52+
var dir: File? = File("").absoluteFile
53+
while (dir != null) {
54+
val candidate = File(dir, relativePath)
55+
if (candidate.isFile) return candidate
56+
dir = dir.parentFile
57+
}
58+
error("Could not find $relativePath walking up from ${File("").absolutePath}")
59+
}
60+
61+
private companion object {
62+
const val MANIFEST_PATH = "app/src/main/AndroidManifest.xml"
63+
const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
64+
}
65+
}

0 commit comments

Comments
 (0)