1 /* 2 * Copyright (C) 2015 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 package android.telecom.cts; 17 18 import android.app.Instrumentation; 19 import android.bluetooth.BluetoothDevice; 20 import android.content.ComponentName; 21 import android.content.ContentProviderOperation; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.graphics.Color; 26 import android.net.Uri; 27 import android.os.Build; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.os.Parcel; 32 import android.os.ParcelFileDescriptor; 33 import android.os.Process; 34 import android.os.SystemClock; 35 import android.os.UserManager; 36 import android.provider.ContactsContract; 37 import android.telecom.PhoneAccount; 38 import android.telecom.PhoneAccountHandle; 39 import android.telecom.TelecomManager; 40 41 import androidx.test.InstrumentationRegistry; 42 43 import junit.framework.TestCase; 44 45 import java.io.BufferedReader; 46 import java.io.FileInputStream; 47 import java.io.InputStream; 48 import java.io.InputStreamReader; 49 import java.nio.charset.StandardCharsets; 50 import java.util.ArrayList; 51 import java.util.Optional; 52 import java.util.Random; 53 import java.util.UUID; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 import java.util.function.Predicate; 57 58 public class TestUtils { 59 static final String TAG = "TelecomCTSTests"; 60 static final boolean HAS_TELECOM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 61 static final long WAIT_FOR_STATE_CHANGE_TIMEOUT_MS = 10000; 62 static final long WAIT_FOR_CALL_ADDED_TIMEOUT_S = 15; 63 static final long WAIT_FOR_STATE_CHANGE_TIMEOUT_CALLBACK = 50; 64 static final long WAIT_FOR_PHONE_STATE_LISTENER_REGISTERED_TIMEOUT_S = 15; 65 static final long WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S = 15; 66 static final boolean HAS_BLUETOOTH = hasBluetoothFeature(); 67 static final BluetoothDevice BLUETOOTH_DEVICE1 = makeBluetoothDevice("00:00:00:00:00:01"); 68 static final BluetoothDevice BLUETOOTH_DEVICE2 = makeBluetoothDevice("00:00:00:00:00:02"); 69 70 // Non-final to allow modification by tests not in this package (e.g. permission-related 71 // tests in the Telecom2 test package. 72 public static String PACKAGE = "android.telecom.cts"; 73 public static final String TEST_URI_SCHEME = "foobuzz"; 74 public static final String COMPONENT = "android.telecom.cts.CtsConnectionService"; 75 public static final String INCALL_COMPONENT = "android.telecom.cts/.MockInCallService"; 76 public static final String SELF_MANAGED_COMPONENT = 77 "android.telecom.cts.CtsSelfManagedConnectionService"; 78 public static final String REMOTE_COMPONENT = "android.telecom.cts.CtsRemoteConnectionService"; 79 public static final String ACCOUNT_ID_1 = "xtstest_CALL_PROVIDER_ID_1"; 80 public static final String ACCOUNT_ID_2 = "xtstest_CALL_PROVIDER_ID_2"; 81 public static final String ACCOUNT_ID_SIM = "sim_acct"; 82 public static final String ACCOUNT_ID_EMERGENCY = "xtstest_CALL_PROVIDER_EMERGENCY"; 83 public static final String EXTRA_PHONE_NUMBER = "android.telecom.cts.extra.PHONE_NUMBER"; 84 public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE = 85 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_1); 86 public static final PhoneAccountHandle TEST_SIM_PHONE_ACCOUNT_HANDLE = 87 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_SIM); 88 public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE_2 = 89 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_2); 90 public static final PhoneAccountHandle TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE = 91 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID_EMERGENCY); 92 public static final String DEFAULT_TEST_ACCOUNT_1_ID = "ctstest_DEFAULT_TEST_ID_1"; 93 public static final String DEFAULT_TEST_ACCOUNT_2_ID = "ctstest_DEFAULT_TEST_ID_2"; 94 public static final PhoneAccountHandle TEST_DEFAULT_PHONE_ACCOUNT_HANDLE_1 = 95 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), 96 DEFAULT_TEST_ACCOUNT_1_ID); 97 public static final PhoneAccountHandle TEST_DEFAULT_PHONE_ACCOUNT_HANDLE_2 = 98 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), 99 DEFAULT_TEST_ACCOUNT_2_ID); 100 public static final PhoneAccountHandle TEST_HANDOVER_SRC_PHONE_ACCOUNT_HANDLE = 101 new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), "handoverFrom"); 102 public static final PhoneAccountHandle TEST_HANDOVER_DEST_PHONE_ACCOUNT_HANDLE = 103 new PhoneAccountHandle(new ComponentName(PACKAGE, SELF_MANAGED_COMPONENT), 104 "handoverTo"); 105 public static final String REMOTE_ACCOUNT_ID = "xtstest_REMOTE_CALL_PROVIDER_ID"; 106 public static final String SELF_MANAGED_ACCOUNT_ID_1 = "ctstest_SELF_MANAGED_ID_1"; 107 public static final PhoneAccountHandle TEST_SELF_MANAGED_HANDLE_1 = 108 new PhoneAccountHandle(new ComponentName(PACKAGE, SELF_MANAGED_COMPONENT), 109 SELF_MANAGED_ACCOUNT_ID_1); 110 public static final String SELF_MANAGED_ACCOUNT_ID_2 = "ctstest_SELF_MANAGED_ID_2"; 111 public static final PhoneAccountHandle TEST_SELF_MANAGED_HANDLE_2 = 112 new PhoneAccountHandle(new ComponentName(PACKAGE, SELF_MANAGED_COMPONENT), 113 SELF_MANAGED_ACCOUNT_ID_2); 114 public static final String SELF_MANAGED_ACCOUNT_ID_3 = "ctstest_SELF_MANAGED_ID_3"; 115 public static final PhoneAccountHandle TEST_SELF_MANAGED_HANDLE_3 = 116 new PhoneAccountHandle(new ComponentName(PACKAGE, SELF_MANAGED_COMPONENT), 117 SELF_MANAGED_ACCOUNT_ID_3); 118 public static final String SELF_MANAGED_ACCOUNT_ID_4 = "ctstest_SELF_MANAGED_ID_4"; 119 public static final PhoneAccountHandle TEST_SELF_MANAGED_HANDLE_4 = 120 new PhoneAccountHandle(new ComponentName(PACKAGE, SELF_MANAGED_COMPONENT), 121 SELF_MANAGED_ACCOUNT_ID_4); 122 123 public static final String ACCOUNT_LABEL = "CTSConnectionService"; 124 public static final String SIM_ACCOUNT_LABEL = "CTSConnectionServiceSim"; 125 public static final PhoneAccount TEST_PHONE_ACCOUNT = PhoneAccount.builder( 126 TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL) 127 .setAddress(Uri.parse("tel:555-TEST")) 128 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 129 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 130 PhoneAccount.CAPABILITY_VIDEO_CALLING | 131 PhoneAccount.CAPABILITY_RTT | 132 PhoneAccount.CAPABILITY_CONNECTION_MANAGER | 133 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS | 134 PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING) 135 .setHighlightColor(Color.RED) 136 .setShortDescription(ACCOUNT_LABEL) 137 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 138 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 139 .build(); 140 141 public static final PhoneAccount TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME = 142 PhoneAccount.builder( 143 TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL) 144 .setAddress(Uri.parse("tel:555-TEST")) 145 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 146 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 147 PhoneAccount.CAPABILITY_VIDEO_CALLING | 148 PhoneAccount.CAPABILITY_RTT | 149 PhoneAccount.CAPABILITY_CONNECTION_MANAGER | 150 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS | 151 PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING) 152 .setHighlightColor(Color.RED) 153 .setShortDescription(ACCOUNT_LABEL) 154 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 155 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 156 .addSupportedUriScheme("content") 157 .build(); 158 159 public static final PhoneAccount TEST_SIM_PHONE_ACCOUNT = PhoneAccount.builder( 160 TEST_SIM_PHONE_ACCOUNT_HANDLE, SIM_ACCOUNT_LABEL) 161 .setAddress(Uri.parse("tel:555-TEST")) 162 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 163 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 164 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 165 .setHighlightColor(Color.RED) 166 .setShortDescription(SIM_ACCOUNT_LABEL) 167 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 168 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 169 .build(); 170 171 public static final PhoneAccount TEST_PHONE_ACCOUNT_2 = PhoneAccount.builder( 172 TEST_PHONE_ACCOUNT_HANDLE_2, ACCOUNT_LABEL + "2") 173 .setAddress(Uri.parse("tel:555-TEST2")) 174 .setSubscriptionAddress(Uri.parse("tel:555-TEST2")) 175 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 176 PhoneAccount.CAPABILITY_VIDEO_CALLING | 177 PhoneAccount.CAPABILITY_RTT | 178 PhoneAccount.CAPABILITY_CONNECTION_MANAGER) 179 .setHighlightColor(Color.BLUE) 180 .setShortDescription(ACCOUNT_LABEL) 181 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 182 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 183 .build(); 184 185 public static final PhoneAccount TEST_DEFAULT_PHONE_ACCOUNT_1 = PhoneAccount.builder( 186 TEST_DEFAULT_PHONE_ACCOUNT_HANDLE_1, "Default Test 1") 187 .setAddress(Uri.parse("foobuzz:testuri1")) 188 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) 189 .setHighlightColor(Color.RED) 190 .setShortDescription("Default Test 1") 191 .addSupportedUriScheme(TEST_URI_SCHEME) 192 .build(); 193 public static final PhoneAccount TEST_DEFAULT_PHONE_ACCOUNT_2 = PhoneAccount.builder( 194 TEST_DEFAULT_PHONE_ACCOUNT_HANDLE_2, "Default Test 2") 195 .setAddress(Uri.parse("foobuzz:testuri2")) 196 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) 197 .setHighlightColor(Color.RED) 198 .setShortDescription("Default Test 2") 199 .addSupportedUriScheme(TEST_URI_SCHEME) 200 .build(); 201 private static final Bundle SUPPORTS_HANDOVER_FROM_EXTRAS = new Bundle(); 202 private static final Bundle SUPPORTS_HANDOVER_TO_EXTRAS = new Bundle(); 203 static { SUPPORTS_HANDOVER_FROM_EXTRAS.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM, true)204 SUPPORTS_HANDOVER_FROM_EXTRAS.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM, true); SUPPORTS_HANDOVER_TO_EXTRAS.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO, true)205 SUPPORTS_HANDOVER_TO_EXTRAS.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_TO, true); 206 } 207 public static final PhoneAccount TEST_PHONE_ACCOUNT_HANDOVER_SRC = PhoneAccount.builder( 208 TEST_HANDOVER_SRC_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL) 209 .setAddress(Uri.parse("tel:555-TEST")) 210 .setExtras(SUPPORTS_HANDOVER_FROM_EXTRAS) 211 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 212 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) 213 .setHighlightColor(Color.BLUE) 214 .setShortDescription(ACCOUNT_LABEL) 215 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 216 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 217 .build(); 218 public static final PhoneAccount TEST_PHONE_ACCOUNT_HANDOVER_DEST = PhoneAccount.builder( 219 TEST_HANDOVER_DEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL) 220 .setAddress(Uri.parse("tel:555-TEST")) 221 .setExtras(SUPPORTS_HANDOVER_TO_EXTRAS) 222 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 223 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) 224 .setHighlightColor(Color.MAGENTA) 225 .setShortDescription(ACCOUNT_LABEL) 226 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 227 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 228 .build(); 229 public static final String REMOTE_ACCOUNT_LABEL = "CTSRemoteConnectionService"; 230 public static final String SELF_MANAGED_ACCOUNT_LABEL = "android.telecom.cts"; 231 public static final PhoneAccount TEST_SELF_MANAGED_PHONE_ACCOUNT_3 = PhoneAccount.builder( 232 TEST_SELF_MANAGED_HANDLE_3, SELF_MANAGED_ACCOUNT_LABEL) 233 .setAddress(Uri.fromParts(TEST_URI_SCHEME, "test@test.com", null)) 234 .setSubscriptionAddress(Uri.fromParts(TEST_URI_SCHEME, "test@test.com", null)) 235 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED | 236 PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING | 237 PhoneAccount.CAPABILITY_VIDEO_CALLING) 238 .setHighlightColor(Color.BLUE) 239 .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL) 240 .addSupportedUriScheme(TEST_URI_SCHEME) 241 .build(); 242 public static final Bundle SELF_MANAGED_ACCOUNT_1_EXTRAS; 243 static { 244 SELF_MANAGED_ACCOUNT_1_EXTRAS = new Bundle(); SELF_MANAGED_ACCOUNT_1_EXTRAS.putBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false)245 SELF_MANAGED_ACCOUNT_1_EXTRAS.putBoolean( 246 PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false); 247 } 248 public static final Bundle SELF_MANAGED_ACCOUNT_2_EXTRAS; 249 static { 250 SELF_MANAGED_ACCOUNT_2_EXTRAS = new Bundle(); SELF_MANAGED_ACCOUNT_2_EXTRAS.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true)251 SELF_MANAGED_ACCOUNT_2_EXTRAS.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true); 252 } 253 public static final Bundle SELF_MANAGED_ACCOUNT_4_EXTRAS; 254 static { 255 SELF_MANAGED_ACCOUNT_4_EXTRAS = new Bundle(); SELF_MANAGED_ACCOUNT_4_EXTRAS.putBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true)256 SELF_MANAGED_ACCOUNT_4_EXTRAS.putBoolean( 257 PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true); 258 } 259 260 public static final PhoneAccount TEST_SELF_MANAGED_PHONE_ACCOUNT_2 = PhoneAccount.builder( 261 TEST_SELF_MANAGED_HANDLE_2, SELF_MANAGED_ACCOUNT_LABEL) 262 .setAddress(Uri.parse("sip:test@test.com")) 263 .setSubscriptionAddress(Uri.parse("sip:test@test.com")) 264 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED | 265 PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING | 266 PhoneAccount.CAPABILITY_VIDEO_CALLING) 267 .setHighlightColor(Color.BLUE) 268 .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL) 269 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 270 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) 271 .setExtras(SELF_MANAGED_ACCOUNT_2_EXTRAS) 272 .build(); 273 public static final PhoneAccount TEST_SELF_MANAGED_PHONE_ACCOUNT_1 = PhoneAccount.builder( 274 TEST_SELF_MANAGED_HANDLE_1, SELF_MANAGED_ACCOUNT_LABEL) 275 .setAddress(Uri.parse("sip:test@test.com")) 276 .setSubscriptionAddress(Uri.parse("sip:test@test.com")) 277 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED | 278 PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING | 279 PhoneAccount.CAPABILITY_VIDEO_CALLING) 280 .setHighlightColor(Color.BLUE) 281 .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL) 282 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 283 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) 284 .setExtras(SELF_MANAGED_ACCOUNT_1_EXTRAS) 285 .build(); 286 public static final PhoneAccount TEST_SELF_MANAGED_PHONE_ACCOUNT_4 = PhoneAccount.builder( 287 TEST_SELF_MANAGED_HANDLE_4, SELF_MANAGED_ACCOUNT_LABEL) 288 .setAddress(Uri.parse("sip:test@test.com")) 289 .setSubscriptionAddress(Uri.parse("sip:test@test.com")) 290 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED | 291 PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING | 292 PhoneAccount.CAPABILITY_VIDEO_CALLING) 293 .setHighlightColor(Color.BLUE) 294 .setShortDescription(SELF_MANAGED_ACCOUNT_LABEL) 295 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 296 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) 297 .setExtras(SELF_MANAGED_ACCOUNT_4_EXTRAS) 298 .build(); 299 300 /** 301 * See {@link TelecomManager#ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION} 302 */ 303 public static final String ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION_STRING = 304 "ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION "; 305 306 /** 307 * See {@link TelecomManager#ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION} 308 */ 309 public static final String ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION_STRING = 310 "ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION "; 311 312 private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = 313 "telecom set-call-diagnostic-service "; 314 315 private static final String COMMAND_SET_DEFAULT_DIALER = "telecom set-default-dialer "; 316 317 private static final String COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer"; 318 319 private static final String COMMAND_SET_SYSTEM_DIALER = "telecom set-system-dialer "; 320 321 private static final String COMMAND_GET_SYSTEM_DIALER = "telecom get-system-dialer"; 322 323 private static final String COMMAND_ENABLE = "telecom set-phone-account-enabled "; 324 325 private static final String COMMAND_SET_ACCT_SUGGESTION = 326 "telecom set-phone-acct-suggestion-component "; 327 328 private static final String COMMAND_REGISTER_SIM = "telecom register-sim-phone-account "; 329 330 private static final String COMMAND_SET_DEFAULT_PHONE_ACCOUNT = 331 "telecom set-user-selected-outgoing-phone-account "; 332 333 private static final String COMMAND_WAIT_ON_HANDLERS = "telecom wait-on-handlers"; 334 335 private static final String COMMAND_ADD_TEST_EMERGENCY_NUMBER = 336 "cmd phone emergency-number-test-mode -a "; 337 338 private static final String COMMAND_REMOVE_TEST_EMERGENCY_NUMBER = 339 "cmd phone emergency-number-test-mode -r "; 340 341 private static final String COMMAND_CLEAR_TEST_EMERGENCY_NUMBERS = 342 "cmd phone emergency-number-test-mode -c"; 343 344 private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER = 345 "telecom set-test-emergency-phone-account-package-filter "; 346 347 private static final String COMMAND_AM_COMPAT = "am compat "; 348 349 public static final String MERGE_CALLER_NAME = "calls-merged"; 350 public static final String SWAP_CALLER_NAME = "calls-swapped"; 351 shouldTestTelecom(Context context)352 public static boolean shouldTestTelecom(Context context) { 353 if (!HAS_TELECOM) { 354 return false; 355 } 356 final PackageManager pm = context.getPackageManager(); 357 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && 358 pm.hasSystemFeature(PackageManager.FEATURE_TELECOM); 359 } 360 setCallDiagnosticService(Instrumentation instrumentation, String packageName)361 public static String setCallDiagnosticService(Instrumentation instrumentation, 362 String packageName) 363 throws Exception { 364 return executeShellCommand(instrumentation, COMMAND_SET_CALL_DIAGNOSTIC_SERVICE 365 + packageName); 366 } 367 setDefaultDialer(Instrumentation instrumentation, String packageName)368 public static String setDefaultDialer(Instrumentation instrumentation, String packageName) 369 throws Exception { 370 return executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_DIALER + packageName); 371 } 372 setSystemDialerOverride(Instrumentation instrumentation)373 public static String setSystemDialerOverride(Instrumentation instrumentation) throws Exception { 374 return executeShellCommand(instrumentation, COMMAND_SET_SYSTEM_DIALER + INCALL_COMPONENT); 375 } 376 clearSystemDialerOverride( Instrumentation instrumentation)377 public static String clearSystemDialerOverride( 378 Instrumentation instrumentation) throws Exception { 379 return executeShellCommand(instrumentation, COMMAND_SET_SYSTEM_DIALER + "default"); 380 } 381 setCtsPhoneAccountSuggestionService(Instrumentation instrumentation, ComponentName componentName)382 public static String setCtsPhoneAccountSuggestionService(Instrumentation instrumentation, 383 ComponentName componentName) throws Exception { 384 return executeShellCommand(instrumentation, 385 COMMAND_SET_ACCT_SUGGESTION 386 + (componentName == null ? "" : componentName.flattenToString())); 387 } 388 getDefaultDialer(Instrumentation instrumentation)389 public static String getDefaultDialer(Instrumentation instrumentation) throws Exception { 390 return executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER); 391 } 392 getSystemDialer(Instrumentation instrumentation)393 public static String getSystemDialer(Instrumentation instrumentation) throws Exception { 394 return executeShellCommand(instrumentation, COMMAND_GET_SYSTEM_DIALER); 395 } 396 enablePhoneAccount(Instrumentation instrumentation, PhoneAccountHandle handle)397 public static void enablePhoneAccount(Instrumentation instrumentation, 398 PhoneAccountHandle handle) throws Exception { 399 final ComponentName component = handle.getComponentName(); 400 final long currentUserSerial = getCurrentUserSerialNumber(instrumentation); 401 executeShellCommand(instrumentation, COMMAND_ENABLE 402 + component.getPackageName() + "/" + component.getClassName() + " " 403 + handle.getId() + " " + currentUserSerial); 404 } 405 registerSimPhoneAccount(Instrumentation instrumentation, PhoneAccountHandle handle, String label, String address)406 public static void registerSimPhoneAccount(Instrumentation instrumentation, 407 PhoneAccountHandle handle, String label, String address) throws Exception { 408 final ComponentName component = handle.getComponentName(); 409 final long currentUserSerial = getCurrentUserSerialNumber(instrumentation); 410 executeShellCommand(instrumentation, COMMAND_REGISTER_SIM 411 + component.getPackageName() + "/" + component.getClassName() + " " 412 + handle.getId() + " " + currentUserSerial + " " + label + " " + address); 413 } 414 registerEmergencyPhoneAccount(Instrumentation instrumentation, PhoneAccountHandle handle, String label, String address)415 public static void registerEmergencyPhoneAccount(Instrumentation instrumentation, 416 PhoneAccountHandle handle, String label, String address) throws Exception { 417 final ComponentName component = handle.getComponentName(); 418 final long currentUserSerial = getCurrentUserSerialNumber(instrumentation); 419 executeShellCommand(instrumentation, COMMAND_REGISTER_SIM + "-e " 420 + component.getPackageName() + "/" + component.getClassName() + " " 421 + handle.getId() + " " + currentUserSerial + " " + label + " " + address); 422 } 423 setDefaultOutgoingPhoneAccount(Instrumentation instrumentation, PhoneAccountHandle handle)424 public static void setDefaultOutgoingPhoneAccount(Instrumentation instrumentation, 425 PhoneAccountHandle handle) throws Exception { 426 if (handle != null) { 427 final ComponentName component = handle.getComponentName(); 428 final long currentUserSerial = getCurrentUserSerialNumber(instrumentation); 429 executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_PHONE_ACCOUNT 430 + component.getPackageName() + "/" + component.getClassName() + " " 431 + handle.getId() + " " + currentUserSerial); 432 } else { 433 executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_PHONE_ACCOUNT); 434 } 435 } 436 waitOnAllHandlers(Instrumentation instrumentation)437 public static void waitOnAllHandlers(Instrumentation instrumentation) { 438 try { 439 executeShellCommand(instrumentation, COMMAND_WAIT_ON_HANDLERS); 440 } catch (Throwable t) { 441 throw new RuntimeException(t); 442 } 443 } 444 waitOnLocalMainLooper(long timeoutMs)445 public static void waitOnLocalMainLooper(long timeoutMs) { 446 Handler mainHandler = new Handler(Looper.getMainLooper()); 447 final CountDownLatch lock = new CountDownLatch(1); 448 mainHandler.post(lock::countDown); 449 while (lock.getCount() > 0) { 450 try { 451 lock.await(timeoutMs, TimeUnit.MILLISECONDS); 452 } catch (InterruptedException e) { 453 // do nothing 454 } 455 } 456 } 457 addTestEmergencyNumber(Instrumentation instr, String testNumber)458 public static void addTestEmergencyNumber(Instrumentation instr, 459 String testNumber) throws Exception { 460 executeShellCommand(instr, COMMAND_ADD_TEST_EMERGENCY_NUMBER + testNumber); 461 } 462 removeTestEmergencyNumber(Instrumentation instr, String number)463 public static void removeTestEmergencyNumber(Instrumentation instr, 464 String number) throws Exception { 465 executeShellCommand(instr, COMMAND_REMOVE_TEST_EMERGENCY_NUMBER + number); 466 } 467 clearTestEmergencyNumbers(Instrumentation instr)468 public static void clearTestEmergencyNumbers(Instrumentation instr) throws Exception { 469 executeShellCommand(instr, COMMAND_CLEAR_TEST_EMERGENCY_NUMBERS); 470 } 471 setTestEmergencyPhoneAccountPackageFilter(Instrumentation instr, Context context)472 public static void setTestEmergencyPhoneAccountPackageFilter(Instrumentation instr, 473 Context context) throws Exception { 474 executeShellCommand(instr, COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER 475 + context.getPackageName()); 476 } 477 clearTestEmergencyPhoneAccountPackageFilter( Instrumentation instr)478 public static void clearTestEmergencyPhoneAccountPackageFilter( 479 Instrumentation instr) throws Exception { 480 executeShellCommand(instr, COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER); 481 } 482 enableCompatCommand(Instrumentation instr, String commandName)483 public static void enableCompatCommand(Instrumentation instr, 484 String commandName) throws Exception { 485 String cmd = COMMAND_AM_COMPAT + "enable --no-kill " + commandName + PACKAGE; 486 executeShellCommand(instr, cmd); 487 } 488 disableCompatCommand(Instrumentation instr, String commandName)489 public static void disableCompatCommand(Instrumentation instr, 490 String commandName) throws Exception { 491 String cmd = COMMAND_AM_COMPAT + "disable --no-kill " + commandName + PACKAGE; 492 executeShellCommand(instr, cmd); 493 } 494 resetCompatCommand(Instrumentation instr, String commandName)495 public static void resetCompatCommand(Instrumentation instr, 496 String commandName) throws Exception { 497 String cmd = COMMAND_AM_COMPAT + "reset --no-kill " + commandName + PACKAGE; 498 executeShellCommand(instr, cmd); 499 } 500 501 /** 502 * Executes the given shell command and returns the output in a string. Note that even 503 * if we don't care about the output, we have to read the stream completely to make the 504 * command execute. 505 */ executeShellCommand(Instrumentation instrumentation, String command)506 public static String executeShellCommand(Instrumentation instrumentation, 507 String command) throws Exception { 508 final ParcelFileDescriptor pfd = 509 instrumentation.getUiAutomation().executeShellCommand(command); 510 BufferedReader br = null; 511 try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) { 512 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 513 String str = null; 514 StringBuilder out = new StringBuilder(); 515 while ((str = br.readLine()) != null) { 516 out.append(str); 517 } 518 return out.toString(); 519 } finally { 520 if (br != null) { 521 closeQuietly(br); 522 } 523 closeQuietly(pfd); 524 } 525 } 526 closeQuietly(AutoCloseable closeable)527 private static void closeQuietly(AutoCloseable closeable) { 528 if (closeable != null) { 529 try { 530 closeable.close(); 531 } catch (RuntimeException rethrown) { 532 throw rethrown; 533 } catch (Exception ignored) { 534 } 535 } 536 } 537 538 /** 539 * Waits for the {@link CountDownLatch} to count down to 0 and then returns without reseting 540 * the latch. 541 * @param lock the latch that the system will wait on. 542 * @return true if the latch was released successfully, false if the latch timed out before 543 * resetting. 544 */ waitForLatchCountDown(CountDownLatch lock)545 public static boolean waitForLatchCountDown(CountDownLatch lock) { 546 if (lock == null) { 547 return false; 548 } 549 550 boolean success; 551 try { 552 success = lock.await(5000, TimeUnit.MILLISECONDS); 553 } catch (InterruptedException ie) { 554 return false; 555 } 556 557 return success; 558 } 559 560 /** 561 * Waits for the {@link CountDownLatch} to count down to 0 and then returns a new reset latch. 562 * @param lock The lock that will await a countDown to 0. 563 * @return a new reset {@link CountDownLatch} if the lock successfully counted down to 0 or 564 * null if the operation timed out. 565 */ waitForLock(CountDownLatch lock)566 public static CountDownLatch waitForLock(CountDownLatch lock) { 567 boolean success = waitForLatchCountDown(lock); 568 if (success) { 569 return new CountDownLatch(1); 570 } else { 571 return null; 572 } 573 } 574 575 /** 576 * Adds a new incoming call. 577 * 578 * @param instrumentation the Instrumentation, used for shell command execution. 579 * @param telecomManager the TelecomManager. 580 * @param handle the PhoneAccountHandle associated with the call. 581 * @param address the incoming address. 582 * @return the new self-managed incoming call. 583 */ addIncomingCall(Instrumentation instrumentation, TelecomManager telecomManager, PhoneAccountHandle handle, Uri address)584 public static void addIncomingCall(Instrumentation instrumentation, 585 TelecomManager telecomManager, PhoneAccountHandle handle, 586 Uri address) { 587 588 // Inform telecom of new incoming self-managed connection. 589 Bundle extras = new Bundle(); 590 extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, address); 591 telecomManager.addNewIncomingCall(handle, extras); 592 593 // Wait for Telecom to finish creating the new connection. 594 try { 595 waitOnAllHandlers(instrumentation); 596 } catch (Exception e) { 597 TestCase.fail("Failed to wait on handlers"); 598 } 599 } hasBluetoothFeature()600 public static boolean hasBluetoothFeature() { 601 return InstrumentationRegistry.getContext().getPackageManager(). 602 hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); 603 } makeBluetoothDevice(String address)604 public static BluetoothDevice makeBluetoothDevice(String address) { 605 if (!HAS_BLUETOOTH) return null; 606 Parcel p1 = Parcel.obtain(); 607 p1.writeString(address); 608 p1.setDataPosition(0); 609 BluetoothDevice device = BluetoothDevice.CREATOR.createFromParcel(p1); 610 p1.recycle(); 611 return device; 612 } 613 614 /** 615 * Places a new outgoing call. 616 * 617 * @param telecomManager the TelecomManager. 618 * @param handle the PhoneAccountHandle associated with the call. 619 * @param address outgoing call address. 620 * @return the new self-managed outgoing call. 621 */ placeOutgoingCall(Instrumentation instrumentation, TelecomManager telecomManager, PhoneAccountHandle handle, Uri address)622 public static void placeOutgoingCall(Instrumentation instrumentation, 623 TelecomManager telecomManager, PhoneAccountHandle handle, 624 Uri address) { 625 // Inform telecom of new incoming self-managed connection. 626 Bundle extras = new Bundle(); 627 extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, handle); 628 telecomManager.placeCall(address, extras); 629 630 // Wait for Telecom to finish creating the new connection. 631 try { 632 waitOnAllHandlers(instrumentation); 633 } catch (Exception e) { 634 TestCase.fail("Failed to wait on handlers"); 635 } 636 } 637 638 /** 639 * Waits for a new SelfManagedConnection with the given address to be added. 640 * @param address The expected address. 641 * @return The SelfManagedConnection found. 642 */ waitForAndGetConnection(Uri address)643 public static SelfManagedConnection waitForAndGetConnection(Uri address) { 644 // Wait for creation of the new connection. 645 if (!CtsSelfManagedConnectionService.waitForBinding()) { 646 TestCase.fail("Could not bind to Self-Managed ConnectionService"); 647 } 648 CtsSelfManagedConnectionService connectionService = 649 CtsSelfManagedConnectionService.getConnectionService(); 650 TestCase.assertTrue(connectionService.waitForUpdate( 651 CtsSelfManagedConnectionService.CONNECTION_CREATED_LOCK)); 652 653 Optional<SelfManagedConnection> connectionOptional = connectionService.getConnections() 654 .stream() 655 .filter(connection -> address.equals(connection.getAddress())) 656 .findFirst(); 657 assert(connectionOptional.isPresent()); 658 return connectionOptional.get(); 659 } 660 661 /** 662 * Utility class used to track the number of times a callback was invoked, and the arguments it 663 * was invoked with. This class is prefixed Invoke rather than the more typical Call for 664 * disambiguation purposes. 665 */ 666 public static final class InvokeCounter { 667 private final String mName; 668 private final Object mLock = new Object(); 669 private final ArrayList<Object[]> mInvokeArgs = new ArrayList<>(); 670 671 private int mInvokeCount; 672 InvokeCounter(String callbackName)673 public InvokeCounter(String callbackName) { 674 mName = callbackName; 675 } 676 invoke(Object... args)677 public void invoke(Object... args) { 678 synchronized (mLock) { 679 mInvokeCount++; 680 mInvokeArgs.add(args); 681 mLock.notifyAll(); 682 } 683 } 684 getArgs(int index)685 public Object[] getArgs(int index) { 686 synchronized (mLock) { 687 return mInvokeArgs.get(index); 688 } 689 } 690 getInvokeCount()691 public int getInvokeCount() { 692 synchronized (mLock) { 693 return mInvokeCount; 694 } 695 } 696 waitForCount(int count)697 public void waitForCount(int count) { 698 waitForCount(count, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 699 } 700 waitForCount(int count, long timeoutMillis)701 public void waitForCount(int count, long timeoutMillis) { 702 waitForCount(count, timeoutMillis, null); 703 } 704 waitForCount(long timeoutMillis)705 public void waitForCount(long timeoutMillis) { 706 synchronized (mLock) { 707 try { 708 mLock.wait(timeoutMillis); 709 }catch (InterruptedException ex) { 710 ex.printStackTrace(); 711 } 712 } 713 } 714 waitForCount(int count, long timeoutMillis, String message)715 public void waitForCount(int count, long timeoutMillis, String message) { 716 synchronized (mLock) { 717 final long startTimeMillis = SystemClock.uptimeMillis(); 718 while (mInvokeCount < count) { 719 try { 720 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 721 final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis; 722 if (remainingTimeMillis <= 0) { 723 if (message != null) { 724 TestCase.fail(message); 725 } else { 726 TestCase.fail(String.format("Expected %s to be called %d times.", 727 mName, count)); 728 } 729 } 730 mLock.wait(timeoutMillis); 731 } catch (InterruptedException ie) { 732 /* ignore */ 733 } 734 } 735 } 736 } 737 738 /** 739 * Waits for a predicate to return {@code true} within the specified timeout. Uses the 740 * {@link #mLock} for this {@link InvokeCounter} to eliminate the need to perform busy-wait. 741 * @param predicate The predicate. 742 * @param timeoutMillis The timeout. 743 */ waitForPredicate(Predicate predicate, long timeoutMillis)744 public void waitForPredicate(Predicate predicate, long timeoutMillis) { 745 synchronized (mLock) { 746 long startTimeMillis = SystemClock.uptimeMillis(); 747 long elapsedTimeMillis = 0; 748 long remainingTimeMillis = timeoutMillis; 749 Object foundValue = null; 750 boolean wasFound = false; 751 do { 752 try { 753 mLock.wait(timeoutMillis); 754 foundValue = (mInvokeArgs.get(mInvokeArgs.size()-1))[0]; 755 wasFound = predicate.test(foundValue); 756 elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 757 remainingTimeMillis = timeoutMillis - elapsedTimeMillis; 758 } catch (InterruptedException ie) { 759 /* ignore */ 760 } 761 } while (!wasFound && remainingTimeMillis > 0); 762 if (wasFound) { 763 return; 764 } else if (remainingTimeMillis <= 0) { 765 TestCase.fail("Expected value not found within time limit"); 766 } 767 } 768 } 769 clearArgs()770 public void clearArgs() { 771 synchronized (mLock) { 772 mInvokeArgs.clear(); 773 } 774 } 775 reset()776 public void reset() { 777 synchronized (mLock) { 778 clearArgs(); 779 mInvokeCount = 0; 780 } 781 } 782 } 783 getCurrentUserSerialNumber(Instrumentation instrumentation)784 private static long getCurrentUserSerialNumber(Instrumentation instrumentation) { 785 UserManager userManager = 786 instrumentation.getContext().getSystemService(UserManager.class); 787 return userManager.getSerialNumberForUser(Process.myUserHandle()); 788 } 789 790 791 insertContact(ContentResolver contentResolver, String phoneNumber)792 public static Uri insertContact(ContentResolver contentResolver, String phoneNumber) 793 throws Exception { 794 ArrayList<ContentProviderOperation> ops = new ArrayList<>(); 795 ops.add(ContentProviderOperation 796 .newInsert(ContactsContract.RawContacts.CONTENT_URI) 797 .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "test_type") 798 .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "test_name") 799 .build()); 800 ops.add(ContentProviderOperation 801 .newInsert(ContactsContract.Data.CONTENT_URI) 802 .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) 803 .withValue(ContactsContract.Data.MIMETYPE, 804 ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) 805 .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "test") 806 .build()); 807 ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) 808 .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) 809 .withValue(ContactsContract.Data.MIMETYPE, 810 ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) 811 .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber) 812 .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, 813 ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) 814 .withYieldAllowed(true) 815 .build()); 816 return contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)[0].uri; 817 } 818 deleteContact(ContentResolver contentResolver, Uri deleteUri)819 public static int deleteContact(ContentResolver contentResolver, Uri deleteUri) { 820 return contentResolver.delete(deleteUri, null, null); 821 } 822 823 /** 824 * Generates random phone accounts. 825 * @param seed random seed to use for random UUIDs; passed in for determinism. 826 * @param count How many phone accounts to use. 827 * @return Random phone accounts. 828 */ generateRandomPhoneAccounts(long seed, int count, String packageName, String component)829 public static ArrayList<PhoneAccount> generateRandomPhoneAccounts(long seed, int count, 830 String packageName, String component) { 831 Random random = new Random(seed); 832 ArrayList<PhoneAccount> accounts = new ArrayList<>(); 833 for (int ix = 0; ix < count; ix++) { 834 PhoneAccountHandle handle = new PhoneAccountHandle( 835 new ComponentName(packageName, component), getRandomUuid(random).toString()); 836 PhoneAccount acct = new PhoneAccount.Builder(handle, "TelecommTests") 837 .setAddress(Uri.parse("sip:test@test.com")) 838 .setSubscriptionAddress(Uri.parse("sip:test@test.com")) 839 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED 840 | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING 841 | PhoneAccount.CAPABILITY_VIDEO_CALLING) 842 .setHighlightColor(Color.BLUE) 843 .setShortDescription(TestUtils.SELF_MANAGED_ACCOUNT_LABEL) 844 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 845 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) 846 .setExtras(TestUtils.SELF_MANAGED_ACCOUNT_1_EXTRAS) 847 .build(); 848 accounts.add(acct); 849 } 850 return accounts; 851 } 852 853 /** 854 * Returns a random UUID based on the passed in Random generator. 855 * @param random Random generator. 856 * @return The UUID. 857 */ getRandomUuid(Random random)858 public static UUID getRandomUuid(Random random) { 859 byte[] array = new byte[16]; 860 random.nextBytes(array); 861 return UUID.nameUUIDFromBytes(array); 862 } 863 864 865 } 866