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