Blocked numbers¶
The Android 7.0 (API 24) release introduced the Blocked Numbers content provider that stores a list of phone numbers the user has specified should not be able to contact them via telephony communications (calls, SMS, MMS).
This library provides the following APIs that allow you to read/write blocked numbers;
Blocked number data¶
Blocked number data consists of the number
and normalizedNumber
.
The BlockedNumber.number
is the phone number to block as the user entered it. It may or may not be
formatted (e.g. (012) 345-6789).
ℹ️ Other than regular phone numbers, the blocked number provider can also store addresses (such as email) from which a user can receive messages, and calls.
The BlockedNumber.normalizedNumber
is the number
's E164 representation (e.g. +10123456789). This
value can be omitted in which case the provider will try to automatically infer it. (It'll be left
null if the provider fails to infer.) If present, number
has to be set as well (it will be ignored
otherwise). If you want to set this value yourself, you may want to look
at android.telephony.PhoneNumberUtils
.
ℹ️ This may contain an email if
number
is an email.
Privileges to read/write blocked numbers directly¶
Reading and writing directly to the Blocked Numbers database table can only be done by certain privileged apps. The Blocked Number APIs this library provides will only work if all of the following requirements are met;
- your app must is a system app and/or the default dialer/phone app and/or the default SMS/messaging app
- the current user (if in a multi-user environment) must be allowed to read/write blocked numbers
- the runtime OS version is at least Android 7.0 (N) (API 24)
To check if all of the requirements specified above are met,
Starting with Android 11 (API 30), you must include the following to your app's manifest in order to successfully use this function and therefore the bocked number APIs provided in this library.
<queries>
<intent>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent>
</queries>
ℹ️ The above is required to be able to check if your app is the default SMS/messaging app.
Use the builtin Blocked Numbers activity¶
If your app does not have the privilege to read/write directly to the blocked number provider, you may instead launch the builtin system Blocked numbers activity. It provides a fully functional UI allowing users to see, add, and remove blocked numbers. It is the same activity used by the AOSP Contacts app and Google Contacts app when accessing the "Blocked numbers".
If the activity
is null, the builtin blocked numbers activity will be launched as a new task,
separate from the current application instance. If it is provided, then the activity will be part of
the current application's stack/history.
Blocked numbers have been introduced in Android 7.0 (N) (API 24). Therefore, this will do nothing for versions lower than API 24.
Using the DefaultDialerRequest extensions¶
The most common way for 3rd party apps (apps that don't come pre-installed by the OEM) to get direct read/write access to the blocked numbers table is to be set as the default dialer/phone or SMS/messaging app.
The contacts.ui.util.DefaultDialerRequest.kt
in the ui
module` provides extension functions that
allow you to prompt the user to set your app as the default dialer/phone app.
To use it,
Activity {
fun onRequestToBeTheDefaultDialerAppClicked() {
requestToBeTheDefaultDialerApp()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
onRequestToBeDefaultDialerAppResult(requestCode, resultCode) {
// You are now able to use the BlockedNumbersQuery, BlockedNumbersInsert, and
// BlockedNumbersDelete APIs.
}
}
}
As per the official docs in RoleManagerCompat.ROLE_DIALER
,
your app must have an activity with following intent filters in your manifest. Otherwise, this will
do nothing.
<activity>
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="tel" />
</intent-filter>
</activity>
The above intent filters do NOT need to be added to the activity where the extension functions are invoked. It can be placed in any activity within the application.
Additionally, starting with API 33 (Tiramisu), to qualify for this role, an application needs to
handle the intent to dial, and implement an android.telecom.InCallService
...
<service
android:name=".SampleInCallServiceForDialerRoleRequest"
android:exported="true"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
android:value="false" />
<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>
To check if your app is the default dialer/phone app,
If your app is not a dialer/phone app, then you should not set it as the default dialer/phone app. Otherwise, users of your app may get confused as to why you are prompting them for this privilege. If you still want to read/write blocked numbers directly, you may still use this method. However, make it clear to your users as to why you are doing this despite your app not being a dialer/phone app.
Update an existing blocked number entry¶
Update operations are not supported by the Blocked Number provider. Use delete and insert instead.
Debugging¶
To look at all of the rows in the Blocked Numbers table, use the Context.logBlockedNumbersTable
function in the debug
module.
For more info, read Debug the Blocked Number Provider tables.