xref: /aosp_15_r20/cts/tests/tests/telecom/src/android/telecom/cts/TestUtils.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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