1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.provider; 18 19 import static android.provider.BlockedNumberContract.AUTHORITY_URI; 20 import static android.provider.BlockedNumberContract.EXTRA_ENHANCED_SETTING_KEY; 21 import static android.provider.BlockedNumberContract.EXTRA_ENHANCED_SETTING_VALUE; 22 import static android.provider.BlockedNumberContract.RES_BLOCK_STATUS; 23 import static android.provider.BlockedNumberContract.RES_ENHANCED_SETTING_IS_ENABLED; 24 import static android.provider.BlockedNumberContract.RES_SHOW_EMERGENCY_CALL_NOTIFICATION; 25 import static android.provider.BlockedNumberContract.STATUS_NOT_BLOCKED; 26 import static android.provider.BlockedNumberContract.SystemContract.METHOD_END_BLOCK_SUPPRESSION; 27 import static android.provider.BlockedNumberContract.SystemContract.METHOD_GET_BLOCK_SUPPRESSION_STATUS; 28 import static android.provider.BlockedNumberContract.SystemContract.METHOD_GET_ENHANCED_BLOCK_SETTING; 29 import static android.provider.BlockedNumberContract.SystemContract.METHOD_NOTIFY_EMERGENCY_CONTACT; 30 import static android.provider.BlockedNumberContract.SystemContract.METHOD_SET_ENHANCED_BLOCK_SETTING; 31 import static android.provider.BlockedNumberContract.SystemContract.METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION; 32 import static android.provider.BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER; 33 import static android.provider.BlockedNumberContract.SystemContract.RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP; 34 import static android.provider.BlockedNumberContract.SystemContract.RES_IS_BLOCKING_SUPPRESSED; 35 36 import android.Manifest; 37 import android.annotation.FlaggedApi; 38 import android.annotation.NonNull; 39 import android.annotation.RequiresPermission; 40 import android.annotation.SystemApi; 41 import android.content.Context; 42 import android.os.Bundle; 43 import android.telecom.Log; 44 import android.telecom.TelecomManager; 45 46 import com.android.server.telecom.flags.Flags; 47 48 /** 49 * Constants and methods to interact with the blocked numbers list. This class also serves as 50 * a mediator between the BlockedNumber provider and the system: it manages blocking behavior 51 * when the user contacts emergency services. Currently, this is only used internally by Telecom. 52 * 53 * Refer to {@link BlockedNumberContract} for more context. 54 * @hide 55 */ 56 @SystemApi 57 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 58 public final class BlockedNumbersManager { 59 private static final String LOG_TAG = BlockedNumbersManager.class.getSimpleName(); 60 private Context mContext; 61 62 /** 63 * @hide 64 */ BlockedNumbersManager(Context context)65 public BlockedNumbersManager(Context context) { 66 mContext = context; 67 } 68 69 /** 70 * A protected broadcast intent action for letting components with 71 * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppression 72 * status as returned by {@link #getBlockSuppressionStatus()} has been updated. 73 * @hide 74 */ 75 @SystemApi 76 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 77 public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED = 78 "android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED"; 79 80 /** 81 * Preference key of block numbers not in contacts setting. 82 * @hide 83 */ 84 @SystemApi 85 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 86 public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED = 87 "block_numbers_not_in_contacts_setting"; 88 89 /** 90 * Preference key of block private number calls setting. 91 * @hide 92 */ 93 @SystemApi 94 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 95 public static final String ENHANCED_SETTING_KEY_BLOCK_PRIVATE = 96 "block_private_number_calls_setting"; 97 98 /** 99 * Preference key of block payphone calls setting. 100 * @hide 101 */ 102 @SystemApi 103 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 104 public static final String ENHANCED_SETTING_KEY_BLOCK_PAYPHONE = 105 "block_payphone_calls_setting"; 106 107 /** 108 * Preference key of block unknown calls setting. 109 * @hide 110 */ 111 @SystemApi 112 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 113 public static final String ENHANCED_SETTING_KEY_BLOCK_UNKNOWN = 114 "block_unknown_calls_setting"; 115 116 /** 117 * Preference key for whether should show an emergency call notification. 118 * @hide 119 */ 120 @SystemApi 121 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 122 public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION = 123 "show_emergency_call_notification"; 124 125 /** 126 * Preference key of block unavailable calls setting. 127 * @hide 128 */ 129 @SystemApi 130 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 131 public static final String ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE = 132 "block_unavailable_calls_setting"; 133 134 /** 135 * Notifies the provider that emergency services were contacted by the user. 136 * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent 137 * of the contents of the provider for a duration defined by 138 * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT} 139 * the provider unless {@link #endBlockSuppression()} is called. 140 * @hide 141 */ 142 @SystemApi 143 @RequiresPermission(allOf = { 144 android.Manifest.permission.READ_BLOCKED_NUMBERS, 145 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 146 }) 147 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) notifyEmergencyContact()148 public void notifyEmergencyContact() { 149 verifyBlockedNumbersPermission(); 150 try { 151 Log.i(LOG_TAG, "notifyEmergencyContact; caller=%s", mContext.getOpPackageName()); 152 mContext.getContentResolver().call(AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, 153 null, null); 154 } catch (NullPointerException | IllegalArgumentException ex) { 155 // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if 156 // either of these happen. 157 Log.w(null, "notifyEmergencyContact: provider not ready."); 158 } 159 } 160 161 /** 162 * Notifies the provider to disable suppressing blocking. If emergency services were not 163 * contacted recently at all, calling this method is a no-op. 164 * @hide 165 */ 166 @SystemApi 167 @RequiresPermission(allOf = { 168 android.Manifest.permission.READ_BLOCKED_NUMBERS, 169 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 170 }) 171 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) endBlockSuppression()172 public void endBlockSuppression() { 173 verifyBlockedNumbersPermission(); 174 String caller = mContext.getOpPackageName(); 175 Log.i(LOG_TAG, "endBlockSuppression: caller=%s", caller); 176 mContext.getContentResolver().call(AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSION, null, null); 177 } 178 179 /** 180 * Returns {@code true} if {@code phoneNumber} is blocked taking 181 * {@link #notifyEmergencyContact()} into consideration. If emergency services 182 * have not been contacted recently and enhanced call blocking not been enabled, this 183 * method is equivalent to {@link BlockedNumberContract#isBlocked(Context, String)}. 184 * 185 * @param phoneNumber the number to check. 186 * @param numberPresentation the presentation code associated with the call. 187 * @param isNumberInContacts indicates if the provided number exists as a contact. 188 * @return result code indicating if the number should be blocked, and if so why. 189 * Valid values are: {@link BlockedNumberContract#STATUS_NOT_BLOCKED}, 190 * {@link BlockedNumberContract#STATUS_BLOCKED_IN_LIST}, 191 * {@link BlockedNumberContract#STATUS_BLOCKED_NOT_IN_CONTACTS}, 192 * {@link BlockedNumberContract#STATUS_BLOCKED_PAYPHONE}, 193 * {@link BlockedNumberContract#STATUS_BLOCKED_RESTRICTED}, 194 * {@link BlockedNumberContract#STATUS_BLOCKED_UNKNOWN_NUMBER}. 195 * @hide 196 */ 197 @SystemApi 198 @RequiresPermission(allOf = { 199 android.Manifest.permission.READ_BLOCKED_NUMBERS, 200 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 201 }) 202 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) shouldSystemBlockNumber(@onNull String phoneNumber, @TelecomManager.Presentation int numberPresentation, boolean isNumberInContacts)203 public int shouldSystemBlockNumber(@NonNull String phoneNumber, 204 @TelecomManager.Presentation int numberPresentation, boolean isNumberInContacts) { 205 verifyBlockedNumbersPermission(); 206 try { 207 String caller = mContext.getOpPackageName(); 208 Bundle extras = new Bundle(); 209 extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION, numberPresentation); 210 extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST, isNumberInContacts); 211 final Bundle res = mContext.getContentResolver().call(AUTHORITY_URI, 212 METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras); 213 int blockResult = res != null ? res.getInt(RES_BLOCK_STATUS, STATUS_NOT_BLOCKED) : 214 BlockedNumberContract.STATUS_NOT_BLOCKED; 215 Log.d(LOG_TAG, "shouldSystemBlockNumber: number=%s, caller=%s, result=%s", 216 Log.piiHandle(phoneNumber), caller, 217 BlockedNumberContract.SystemContract.blockStatusToString(blockResult)); 218 return blockResult; 219 } catch (NullPointerException | IllegalArgumentException ex) { 220 // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if 221 // either of these happen. 222 Log.w(null, "shouldSystemBlockNumber: provider not ready."); 223 return BlockedNumberContract.STATUS_NOT_BLOCKED; 224 } 225 } 226 227 /** 228 * @return The current status of block suppression. 229 * @hide 230 */ 231 @SystemApi 232 @RequiresPermission(allOf = { 233 android.Manifest.permission.READ_BLOCKED_NUMBERS, 234 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 235 }) 236 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) getBlockSuppressionStatus()237 public @NonNull BlockSuppressionStatus getBlockSuppressionStatus() { 238 verifyBlockedNumbersPermission(); 239 final Bundle res = mContext.getContentResolver().call( 240 AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSION_STATUS, null, null); 241 BlockSuppressionStatus blockSuppressionStatus = new BlockSuppressionStatus( 242 res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false), 243 res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0)); 244 Log.d(LOG_TAG, "getBlockSuppressionStatus: caller=%s, status=%s", 245 mContext.getOpPackageName(), blockSuppressionStatus); 246 return blockSuppressionStatus; 247 } 248 249 /** 250 * Check whether should show the emergency call notification. 251 * 252 * @return {@code true} if should show emergency call notification. {@code false} otherwise. 253 * @hide 254 */ 255 @SystemApi 256 @RequiresPermission(allOf = { 257 android.Manifest.permission.READ_BLOCKED_NUMBERS, 258 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 259 }) 260 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) shouldShowEmergencyCallNotification()261 public boolean shouldShowEmergencyCallNotification() { 262 verifyBlockedNumbersPermission(); 263 try { 264 final Bundle res = mContext.getContentResolver().call(AUTHORITY_URI, 265 METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null); 266 return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false); 267 } catch (NullPointerException | IllegalArgumentException ex) { 268 // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if 269 // either of these happen. 270 Log.w(null, "shouldShowEmergencyCallNotification: provider not ready."); 271 return false; 272 } 273 } 274 275 /** 276 * Check whether the enhanced block setting is enabled. 277 * 278 * @param key the key of the setting to check, can be 279 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} 280 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE} 281 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} 282 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} 283 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE} 284 * {@link BlockedNumberContract.SystemContract 285 * #ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION} 286 * @return {@code true} if the setting is enabled. {@code false} otherwise. 287 * @hide 288 */ 289 @SystemApi 290 @RequiresPermission(allOf = { 291 android.Manifest.permission.READ_BLOCKED_NUMBERS, 292 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 293 }) 294 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) getBlockedNumberSetting(@onNull String key)295 public boolean getBlockedNumberSetting(@NonNull String key) { 296 verifyBlockedNumbersPermission(); 297 Bundle extras = new Bundle(); 298 extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); 299 try { 300 final Bundle res = mContext.getContentResolver().call(AUTHORITY_URI, 301 METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras); 302 return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false); 303 } catch (NullPointerException | IllegalArgumentException ex) { 304 // The content resolver can throw an NPE or IAE; we don't want to crash Telecom if 305 // either of these happen. 306 Log.w(null, "getEnhancedBlockSetting: provider not ready."); 307 return false; 308 } 309 } 310 311 /** 312 * Set the enhanced block setting enabled status. 313 * 314 * @param key the key of the setting to set, can be 315 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED} 316 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE} 317 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE} 318 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN} 319 * {@link BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE} 320 * {@link BlockedNumberContract.SystemContract 321 * #ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION} 322 * @param value the enabled statue of the setting to set. 323 * @hide 324 */ 325 @SystemApi 326 @RequiresPermission(allOf = { 327 android.Manifest.permission.READ_BLOCKED_NUMBERS, 328 android.Manifest.permission.WRITE_BLOCKED_NUMBERS 329 }) 330 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) setBlockedNumberSetting(@onNull String key, boolean value)331 public void setBlockedNumberSetting(@NonNull String key, boolean value) { 332 verifyBlockedNumbersPermission(); 333 Bundle extras = new Bundle(); 334 extras.putString(EXTRA_ENHANCED_SETTING_KEY, key); 335 extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value); 336 mContext.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING, 337 null, extras); 338 } 339 340 /** 341 * Represents the current status of 342 * {@link #shouldSystemBlockNumber(String, int, boolean)}. If emergency services 343 * have been contacted recently, {@link #mIsSuppressed} is {@code true}, and blocking 344 * is disabled until the timestamp {@link #mUntilTimestampMillis}. 345 * @hide 346 */ 347 @SystemApi 348 @FlaggedApi(Flags.FLAG_TELECOM_MAINLINE_BLOCKED_NUMBERS_MANAGER) 349 public static final class BlockSuppressionStatus { 350 /** 351 * Indicates if block suppression is enabled. 352 */ 353 private boolean mIsSuppressed; 354 355 /** 356 * Timestamp in milliseconds from epoch. 357 */ 358 private long mUntilTimestampMillis; 359 BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis)360 public BlockSuppressionStatus(boolean isSuppressed, long untilTimestampMillis) { 361 this.mIsSuppressed = isSuppressed; 362 this.mUntilTimestampMillis = untilTimestampMillis; 363 } 364 365 @Override toString()366 public String toString() { 367 return "[BlockSuppressionStatus; isSuppressed=" + mIsSuppressed + ", until=" 368 + mUntilTimestampMillis + "]"; 369 } 370 371 /** 372 * @return mIsSuppressed Indicates whether or not block suppression is enabled. 373 */ getIsSuppressed()374 public boolean getIsSuppressed() { 375 return mIsSuppressed; 376 } 377 378 /** 379 * @return mUntilTimestampMillis The timestamp until which block suppression would be 380 * enabled for 381 */ getUntilTimestampMillis()382 public long getUntilTimestampMillis() { 383 return mUntilTimestampMillis; 384 } 385 } 386 387 /** 388 * Verifies that the caller holds both the 389 * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} permission and the 390 * {@link android.Manifest.permission#WRITE_BLOCKED_NUMBERS} permission. 391 * 392 * @throws SecurityException if the caller is missing the necessary permissions 393 */ verifyBlockedNumbersPermission()394 private void verifyBlockedNumbersPermission() { 395 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_BLOCKED_NUMBERS, 396 "Caller does not have the android.permission.READ_BLOCKED_NUMBERS permission"); 397 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_BLOCKED_NUMBERS, 398 "Caller does not have the android.permission.WRITE_BLOCKED_NUMBERS permission"); 399 } 400 } 401