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