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