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