| /* |
| * Copyright (C) 2016 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 android.provider; |
| |
| import android.annotation.IntDef; |
| import android.annotation.WorkerThread; |
| import android.content.Context; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.telecom.Log; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * <p> |
| * The contract between the blockednumber provider and applications. Contains definitions for |
| * the supported URIs and columns. |
| * </p> |
| * |
| * <h3> Overview </h3> |
| * <p> |
| * The content provider exposes a table containing blocked numbers. The columns and URIs for |
| * accessing this table are defined by the {@link BlockedNumbers} class. Messages, and calls from |
| * blocked numbers are discarded by the platform. Notifications upon provider changes can be |
| * received using a {@link android.database.ContentObserver}. |
| * </p> |
| * <p> |
| * The platform will not block messages, and calls from emergency numbers as defined by |
| * {@link android.telephony.PhoneNumberUtils#isEmergencyNumber(String)}. If the user contacts |
| * emergency services, number blocking is disabled by the platform for a duration defined by |
| * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}. |
| * </p> |
| * |
| * <h3> Permissions </h3> |
| * <p> |
| * Only the system, the default SMS application, and the default phone app |
| * (See {@link android.telecom.TelecomManager#getDefaultDialerPackage()}), and carrier apps |
| * (See {@link android.service.carrier.CarrierService}) can read, and write to the blockednumber |
| * provider. However, {@link #canCurrentUserBlockNumbers(Context)} can be accessed by any |
| * application. |
| * </p> |
| * |
| * <h3> Data </h3> |
| * <p> |
| * 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 blocked numbers are stored |
| * in the {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column. A normalized version of phone |
| * numbers (if normalization is possible) is stored in {@link BlockedNumbers#COLUMN_E164_NUMBER} |
| * column. The platform blocks calls, and messages from an address if it is present in in the |
| * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column or if the E164 version of the address |
| * matches the {@link BlockedNumbers#COLUMN_E164_NUMBER} column. |
| * </p> |
| * |
| * <h3> Operations </h3> |
| * <dl> |
| * <dt><b>Insert</b></dt> |
| * <dd> |
| * <p> |
| * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} is a required column that needs to be populated. |
| * Apps can optionally provide the {@link BlockedNumbers#COLUMN_E164_NUMBER} which is the phone |
| * number's E164 representation. The provider automatically populates this column if the app does |
| * not provide it. Note that this column is not populated if normalization fails or if the address |
| * is not a phone number (eg: email). |
| * <p> |
| * Attempting to insert an existing blocked number (same |
| * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column) will result in replacing the existing |
| * blocked number. |
| * <p> |
| * Examples: |
| * <pre> |
| * ContentValues values = new ContentValues(); |
| * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890"); |
| * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values); |
| * </pre> |
| * <pre> |
| * ContentValues values = new ContentValues(); |
| * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890"); |
| * values.put(BlockedNumbers.COLUMN_E164_NUMBER, "+11234567890"); |
| * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values); |
| * </pre> |
| * <pre> |
| * ContentValues values = new ContentValues(); |
| * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "[email protected]"); |
| * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values); |
| * </pre> |
| * </p> |
| * </dd> |
| * <dt><b>Update</b></dt> |
| * <dd> |
| * <p> |
| * Updates are not supported. Use Delete, and Insert instead. |
| * </p> |
| * </dd> |
| * <dt><b>Delete</b></dt> |
| * <dd> |
| * <p> |
| * Deletions can be performed as follows: |
| * <pre> |
| * ContentValues values = new ContentValues(); |
| * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890"); |
| * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values); |
| * getContentResolver().delete(uri, null, null); |
| * </pre> |
| * To check if a particular number is blocked, use the method |
| * {@link #isBlocked(Context, String)}. |
| * </p> |
| * </dd> |
| * <dt><b>Query</b></dt> |
| * <dd> |
| * <p> |
| * All blocked numbers can be enumerated as follows: |
| * <pre> |
| * Cursor c = getContentResolver().query(BlockedNumbers.CONTENT_URI, |
| * new String[]{BlockedNumbers.COLUMN_ID, BlockedNumbers.COLUMN_ORIGINAL_NUMBER, |
| * BlockedNumbers.COLUMN_E164_NUMBER}, null, null, null); |
| * </pre> |
| * </p> |
| * </dd> |
| * <dt><b>Unblock</b></dt> |
| * <dd> |
| * <p> |
| * Use the method {@link #unblock(Context, String)} to unblock numbers. |
| * </p> |
| * </dd> |
| * |
| * <h3> Multi-user </h3> |
| * <p> |
| * Apps must use the method {@link #canCurrentUserBlockNumbers(Context)} before performing any |
| * operation on the blocked number provider. If {@link #canCurrentUserBlockNumbers(Context)} returns |
| * {@code false}, all operations on the provider will fail with a {@link SecurityException}. The |
| * platform will block calls, and messages from numbers in the provider independent of the current |
| * user. |
| * </p> |
| */ |
| public class BlockedNumberContract { |
| private BlockedNumberContract() { |
| } |
| |
| /** The authority for the blocked number provider */ |
| public static final String AUTHORITY = "com.android.blockednumber"; |
| |
| /** A content:// style uri to the authority for the blocked number provider */ |
| public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); |
| |
| private static final String LOG_TAG = BlockedNumberContract.class.getSimpleName(); |
| |
| /** |
| * Constants to interact with the blocked numbers list. |
| */ |
| public static class BlockedNumbers { |
| private BlockedNumbers() { |
| } |
| |
| /** |
| * Content URI for the blocked numbers. |
| * <h3> Supported operations </h3> |
| * <p> blocked |
| * <ul> |
| * <li> query |
| * <li> delete |
| * <li> insert |
| * </ul> |
| * <p> blocked/ID |
| * <ul> |
| * <li> query (selection is not supported) |
| * <li> delete (selection is not supported) |
| * </ul> |
| */ |
| public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "blocked"); |
| |
| /** |
| * The MIME type of {@link #CONTENT_URI} itself providing a directory of blocked phone |
| * numbers. |
| */ |
| public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number"; |
| |
| /** |
| * The MIME type of a blocked phone number under {@link #CONTENT_URI}. |
| */ |
| public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number"; |
| |
| /** |
| * Auto-generated ID field which monotonically increases. |
| * <p>TYPE: long</p> |
| */ |
| public static final String COLUMN_ID = "_id"; |
| |
| /** |
| * Phone number to block. |
| * <p>Must be specified in {@code insert}. |
| * <p>TYPE: String</p> |
| */ |
| public static final String COLUMN_ORIGINAL_NUMBER = "original_number"; |
| |
| /** |
| * Phone number to block. The system generates it from {@link #COLUMN_ORIGINAL_NUMBER} |
| * by removing all formatting characters. |
| * <p>Optional in {@code insert}. When not specified, the system tries to generate it |
| * assuming the current country. (Which will still be null if the number is not valid.) |
| * <p>TYPE: String</p> |
| */ |
| public static final String COLUMN_E164_NUMBER = "e164_number"; |
| } |
| |
| /** @hide */ |
| public static final String METHOD_IS_BLOCKED = "is_blocked"; |
| |
| /** @hide */ |
| public static final String METHOD_UNBLOCK= "unblock"; |
| |
| /** @hide */ |
| public static final String RES_NUMBER_IS_BLOCKED = "blocked"; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = { "STATUS_" }, |
| value = {STATUS_NOT_BLOCKED, STATUS_BLOCKED_IN_LIST, STATUS_BLOCKED_RESTRICTED, |
| STATUS_BLOCKED_UNKNOWN_NUMBER, STATUS_BLOCKED_PAYPHONE, |
| STATUS_BLOCKED_NOT_IN_CONTACTS}) |
| public @interface BlockStatus {} |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was not |
| * blocked. |
| * @hide |
| */ |
| public static final int STATUS_NOT_BLOCKED = 0; |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked |
| * because it is in the list of blocked numbers maintained by the provider. |
| * @hide |
| */ |
| public static final int STATUS_BLOCKED_IN_LIST = 1; |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked |
| * because it is from a restricted number. |
| * @hide |
| */ |
| public static final int STATUS_BLOCKED_RESTRICTED = 2; |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked |
| * because it is from an unknown number. |
| * @hide |
| */ |
| public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked |
| * because it is from a pay phone. |
| * @hide |
| */ |
| public static final int STATUS_BLOCKED_PAYPHONE = 4; |
| |
| /** |
| * Integer reason code used with {@link #RES_BLOCK_STATUS} to indicate that a call was blocked |
| * because it is from a number not in the users contacts. |
| * @hide |
| */ |
| public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; |
| |
| /** |
| * Integer reason indicating whether a call was blocked, and if so why. |
| * @hide |
| */ |
| public static final String RES_BLOCK_STATUS = "block_status"; |
| |
| /** @hide */ |
| public static final String RES_NUM_ROWS_DELETED = "num_deleted"; |
| |
| /** @hide */ |
| public static final String METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS = |
| "can_current_user_block_numbers"; |
| |
| /** @hide */ |
| public static final String RES_CAN_BLOCK_NUMBERS = "can_block"; |
| |
| /** @hide */ |
| public static final String RES_ENHANCED_SETTING_IS_ENABLED = "enhanced_setting_enabled"; |
| |
| /** @hide */ |
| public static final String RES_SHOW_EMERGENCY_CALL_NOTIFICATION = |
| "show_emergency_call_notification"; |
| |
| /** @hide */ |
| public static final String EXTRA_ENHANCED_SETTING_KEY = "extra_enhanced_setting_key"; |
| |
| /** @hide */ |
| public static final String EXTRA_ENHANCED_SETTING_VALUE = "extra_enhanced_setting_value"; |
| |
| /** @hide */ |
| public static final String EXTRA_CONTACT_EXIST = "extra_contact_exist"; |
| |
| /** @hide */ |
| public static final String EXTRA_CALL_PRESENTATION = "extra_call_presentation"; |
| |
| /** |
| * Returns whether a given number is in the blocked list. |
| * |
| * <p> This matches the {@code phoneNumber} against the |
| * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column, and the E164 representation of the |
| * {@code phoneNumber} with the {@link BlockedNumbers#COLUMN_E164_NUMBER} column. |
| * |
| * <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user |
| * context {@code context}, this method will throw a {@link SecurityException}. |
| * |
| * @return {@code true} if the {@code phoneNumber} is blocked. |
| */ |
| @WorkerThread |
| public static boolean isBlocked(Context context, String phoneNumber) { |
| try { |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null); |
| boolean isBlocked = res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false); |
| Log.d(LOG_TAG, "isBlocked: phoneNumber=%s, isBlocked=%b", Log.piiHandle(phoneNumber), |
| isBlocked); |
| return isBlocked; |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "isBlocked: provider not ready."); |
| return false; |
| } |
| } |
| |
| /** |
| * Unblocks the {@code phoneNumber} if it is blocked. |
| * |
| * <p> This deletes all rows where the {@code phoneNumber} matches the |
| * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column or the E164 representation of the |
| * {@code phoneNumber} matches the {@link BlockedNumbers#COLUMN_E164_NUMBER} column. |
| * |
| * <p>To delete rows based on exact match with specific columns such as |
| * {@link BlockedNumbers#COLUMN_ID} use |
| * {@link android.content.ContentProvider#delete(Uri, String, String[])} with |
| * {@link BlockedNumbers#CONTENT_URI} URI. |
| * |
| * <p> Note that if the {@link #canCurrentUserBlockNumbers} is {@code false} for the user |
| * context {@code context}, this method will throw a {@link SecurityException}. |
| * |
| * @return the number of rows deleted in the blocked number provider as a result of unblock. |
| */ |
| @WorkerThread |
| public static int unblock(Context context, String phoneNumber) { |
| Log.d(LOG_TAG, "unblock: phoneNumber=%s", Log.piiHandle(phoneNumber)); |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_UNBLOCK, phoneNumber, null); |
| return res.getInt(RES_NUM_ROWS_DELETED, 0); |
| } |
| |
| /** |
| * Checks if blocking numbers is supported for the current user. |
| * <p> Typically, blocking numbers is only supported for one user at a time. |
| * |
| * @return {@code true} if the current user can block numbers. |
| */ |
| public static boolean canCurrentUserBlockNumbers(Context context) { |
| try { |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_CAN_CURRENT_USER_BLOCK_NUMBERS, null, null); |
| return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false); |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "canCurrentUserBlockNumbers: provider not ready."); |
| return false; |
| } |
| } |
| |
| /** |
| * <p> |
| * The contract between the blockednumber provider and the system. |
| * </p> |
| * <p>This is a wrapper over {@link BlockedNumberContract} that also manages the blocking |
| * behavior when the user contacts emergency services. See |
| * {@link #notifyEmergencyContact(Context)} for details. All methods are protected by |
| * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} and |
| * {@link android.Manifest.permission#WRITE_BLOCKED_NUMBERS} appropriately which ensure that |
| * only system can access the methods defined here. |
| * </p> |
| * @hide |
| */ |
| public static class SystemContract { |
| /** |
| * A protected broadcast intent action for letting components with |
| * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppression |
| * status as returned by {@link #getBlockSuppressionStatus(Context)} has been updated. |
| */ |
| public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED = |
| "android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED"; |
| |
| public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact"; |
| |
| public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression"; |
| |
| public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number"; |
| |
| public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS = |
| "get_block_suppression_status"; |
| |
| public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION = |
| "should_show_emergency_call_notification"; |
| |
| public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed"; |
| |
| public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP = |
| "blocking_suppressed_until_timestamp"; |
| |
| public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting"; |
| public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting"; |
| |
| /* Preference key of block numbers not in contacts setting. */ |
| public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED = |
| "block_numbers_not_in_contacts_setting"; |
| /* Preference key of block private number calls setting. */ |
| public static final String ENHANCED_SETTING_KEY_BLOCK_PRIVATE = |
| "block_private_number_calls_setting"; |
| /* Preference key of block payphone calls setting. */ |
| public static final String ENHANCED_SETTING_KEY_BLOCK_PAYPHONE = |
| "block_payphone_calls_setting"; |
| /* Preference key of block unknown calls setting. */ |
| public static final String ENHANCED_SETTING_KEY_BLOCK_UNKNOWN = |
| "block_unknown_calls_setting"; |
| /* Preference key for whether should show an emergency call notification. */ |
| public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION = |
| "show_emergency_call_notification"; |
| |
| /** |
| * Notifies the provider that emergency services were contacted by the user. |
| * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent |
| * of the contents of the provider for a duration defined by |
| * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT} |
| * the provider unless {@link #endBlockSuppression(Context)} is called. |
| */ |
| public static void notifyEmergencyContact(Context context) { |
| try { |
| Log.i(LOG_TAG, "notifyEmergencyContact; caller=%s", context.getOpPackageName()); |
| context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null); |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "notifyEmergencyContact: provider not ready."); |
| } |
| } |
| |
| /** |
| * Notifies the provider to disable suppressing blocking. If emergency services were not |
| * contacted recently at all, calling this method is a no-op. |
| */ |
| public static void endBlockSuppression(Context context) { |
| String caller = context.getOpPackageName(); |
| Log.i(LOG_TAG, "endBlockSuppression: caller=%s", caller); |
| context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSION, null, null); |
| } |
| |
| /** |
| * Returns {@code true} if {@code phoneNumber} is blocked taking |
| * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services |
| * have not been contacted recently and enhanced call blocking not been enabled, this |
| * method is equivalent to {@link #isBlocked(Context, String)}. |
| * |
| * @param context the context of the caller. |
| * @param phoneNumber the number to check. |
| * @param extras the extra attribute of the number. |
| * @return result code indicating if the number should be blocked, and if so why. |
| * Valid values are: {@link #STATUS_NOT_BLOCKED}, {@link #STATUS_BLOCKED_IN_LIST}, |
| * {@link #STATUS_BLOCKED_NOT_IN_CONTACTS}, {@link #STATUS_BLOCKED_PAYPHONE}, |
| * {@link #STATUS_BLOCKED_RESTRICTED}, {@link #STATUS_BLOCKED_UNKNOWN_NUMBER}. |
| */ |
| public static int shouldSystemBlockNumber(Context context, String phoneNumber, |
| Bundle extras) { |
| try { |
| String caller = context.getOpPackageName(); |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras); |
| int blockResult = res != null ? res.getInt(RES_BLOCK_STATUS, STATUS_NOT_BLOCKED) : |
| BlockedNumberContract.STATUS_NOT_BLOCKED; |
| Log.d(LOG_TAG, "shouldSystemBlockNumber: number=%s, caller=%s, result=%s", |
| Log.piiHandle(phoneNumber), caller, blockStatusToString(blockResult)); |
| return blockResult; |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "shouldSystemBlockNumber: provider not ready."); |
| return BlockedNumberContract.STATUS_NOT_BLOCKED; |
| } |
| } |
| |
| /** |
| * Returns the current status of block suppression. |
| */ |
| public static BlockSuppressionStatus getBlockSuppressionStatus(Context context) { |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSION_STATUS, null, null); |
| BlockSuppressionStatus blockSuppressionStatus = new BlockSuppressionStatus( |
| res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false), |
| res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0)); |
| Log.d(LOG_TAG, "getBlockSuppressionStatus: caller=%s, status=%s", |
| context.getOpPackageName(), blockSuppressionStatus); |
| return blockSuppressionStatus; |
| } |
| |
| /** |
| * Check whether should show the emergency call notification. |
| * |
| * @param context the context of the caller. |
| * @return {@code true} if should show emergency call notification. {@code false} otherwise. |
| */ |
| public static boolean shouldShowEmergencyCallNotification(Context context) { |
| try { |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null); |
| return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false); |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "shouldShowEmergencyCallNotification: provider not ready."); |
| return false; |
| } |
| } |
| |
| /** |
| * Check whether the enhanced block setting is enabled. |
| * |
| * @param context the context of the caller. |
| * @param key the key of the setting to check, can be |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} |
| * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING} |
| * @return {@code true} if the setting is enabled. {@code false} otherwise. |
| */ |
| public static boolean getEnhancedBlockSetting(Context context, String key) { |
| Bundle extras = new Bundle(); |
| extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); |
| try { |
| final Bundle res = context.getContentResolver().call( |
| AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras); |
| return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false); |
| } catch (NullPointerException | IllegalArgumentException ex) { |
| // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if |
| // either of these happen. |
| Log.w(null, "getEnhancedBlockSetting: provider not ready."); |
| return false; |
| } |
| } |
| |
| /** |
| * Set the enhanced block setting enabled status. |
| * |
| * @param context the context of the caller. |
| * @param key the key of the setting to set, can be |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} |
| * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} |
| * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING} |
| * @param value the enabled statue of the setting to set. |
| */ |
| public static void setEnhancedBlockSetting(Context context, String key, boolean value) { |
| Bundle extras = new Bundle(); |
| extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); |
| extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value); |
| context.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING, |
| null, extras); |
| } |
| |
| /** |
| * Converts a block status constant to a string equivalent for logging. |
| * @hide |
| */ |
| public static String blockStatusToString(int blockStatus) { |
| switch (blockStatus) { |
| case STATUS_NOT_BLOCKED: |
| return "not blocked"; |
| case STATUS_BLOCKED_IN_LIST: |
| return "blocked - in list"; |
| case STATUS_BLOCKED_RESTRICTED: |
| return "blocked - restricted"; |
| case STATUS_BLOCKED_UNKNOWN_NUMBER: |
| return "blocked - unknown"; |
| case STATUS_BLOCKED_PAYPHONE: |
| return "blocked - payphone"; |
| case STATUS_BLOCKED_NOT_IN_CONTACTS: |
| return "blocked - not in contacts"; |
| } |
| return "unknown"; |
| } |
| |
| /** |
| * Represents the current status of |
| * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services |
| * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking |
| * is disabled until the timestamp {@link #untilTimestampMillis}. |
| */ |
| public static class BlockSuppressionStatus { |
| public final boolean isSuppressed; |
| /** |
| * Timestamp in milliseconds from epoch. |
| */ |
| public final long untilTimestampMillis; |
| |
| public BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) { |
| this.isSuppressed = isSuppressed; |
| this.untilTimestampMillis = untilTimestampMillis; |
| } |
| |
| @Override |
| public String toString() { |
| return "[BlockSuppressionStatus; isSuppressed=" + isSuppressed + ", until=" |
| + untilTimestampMillis + "]"; |
| } |
| } |
| } |
| } |