• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package android.telephony.ims.cts;
18 
19 import static junit.framework.TestCase.assertEquals;
20 
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.junit.Assume.assumeTrue;
25 
26 import android.annotation.NonNull;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.database.ContentObserver;
32 import android.net.Uri;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.os.PersistableBundle;
36 import android.platform.test.annotations.AppModeNonSdkSandbox;
37 import android.telephony.AccessNetworkConstants;
38 import android.telephony.CarrierConfigManager;
39 import android.telephony.Rlog;
40 import android.telephony.ServiceState;
41 import android.telephony.SubscriptionManager;
42 import android.telephony.TelephonyCallback;
43 import android.telephony.TelephonyManager;
44 import android.telephony.ims.ImsException;
45 import android.telephony.ims.ImsManager;
46 import android.telephony.ims.ImsMmTelManager;
47 import android.telephony.ims.ImsStateCallback;
48 import android.telephony.ims.feature.MmTelFeature;
49 
50 import androidx.test.ext.junit.runners.AndroidJUnit4;
51 import androidx.test.platform.app.InstrumentationRegistry;
52 
53 import com.android.compatibility.common.util.ShellIdentityUtils;
54 
55 import org.junit.After;
56 import org.junit.AfterClass;
57 import org.junit.Before;
58 import org.junit.BeforeClass;
59 import org.junit.Test;
60 import org.junit.runner.RunWith;
61 
62 import java.util.concurrent.CountDownLatch;
63 import java.util.concurrent.LinkedBlockingQueue;
64 import java.util.concurrent.Semaphore;
65 import java.util.concurrent.TimeUnit;
66 
67 @RunWith(AndroidJUnit4.class)
68 public class ImsMmTelManagerTest {
69     private static final String TAG = "ImsMmTelManagerTest";
70     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
71 
72     // Copied from CarrierConfigManager, since these keys is inappropriately marked as @hide
73     private static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL =
74             "carrier_volte_override_wfc_provisioning_bool";
75     private static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
76     private static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL =
77             "use_wfc_home_network_mode_in_roaming_network_bool";
78     private static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
79             "editable_wfc_roaming_mode_bool";
80 
81     private static final String KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL =
82             "override_wfc_roaming_mode_while_using_ntn_bool";
83 
84     private static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL =
85             "satellite_attach_supported_bool";
86 
87     private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
88     private static Handler sHandler;
89     private static CarrierConfigReceiver sReceiver;
90     private static TelephonyManager sTelephonyManager;
91 
92     private static class CarrierConfigReceiver extends BroadcastReceiver {
93         private CountDownLatch mLatch = new CountDownLatch(1);
94         private final int mSubId;
95 
CarrierConfigReceiver(int subId)96         CarrierConfigReceiver(int subId) {
97             mSubId = subId;
98         }
99 
100         @Override
onReceive(Context context, Intent intent)101         public void onReceive(Context context, Intent intent) {
102             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
103                 int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
104                 if (mSubId == subId) {
105                     mLatch.countDown();
106                 }
107             }
108         }
109 
clearQueue()110         void clearQueue() {
111             mLatch = new CountDownLatch(1);
112         }
113 
waitForCarrierConfigChanged()114         void waitForCarrierConfigChanged() throws Exception {
115             mLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
116         }
117     }
118 
119     private static class ServiceStateListenerTest extends TelephonyCallback
120             implements TelephonyCallback.ServiceStateListener {
121 
122         private final Semaphore mNonTerrestrialNetworkSemaphore = new Semaphore(0);
123         private final Semaphore mSemaphore = new Semaphore(0);
124         private ServiceState mServiceState;
125 
126         @Override
onServiceStateChanged(ServiceState serviceState)127         public void onServiceStateChanged(ServiceState serviceState) {
128             logd("onServiceStateChanged: serviceState=" + serviceState);
129             mServiceState = serviceState;
130 
131             try {
132                 if (serviceState.isUsingNonTerrestrialNetwork()) {
133                     mNonTerrestrialNetworkSemaphore.release();
134                 }
135             } catch (Exception e) {
136                 loge("onServiceStateChanged: Got exception=" + e);
137             }
138 
139             try {
140                 mSemaphore.release();
141             } catch (Exception e) {
142                 loge("onServiceStateChanged: Got exception, ex=" + e);
143             }
144         }
145 
waitUntilServiceStateUpdate()146         public boolean waitUntilServiceStateUpdate() {
147             try {
148                 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
149                     loge("Timeout to receive onServiceStateChanged");
150                     return false;
151                 }
152             } catch (Exception ex) {
153                 loge("onServiceStateChanged: Got exception=" + ex);
154                 return false;
155             }
156 
157             return true;
158         }
159 
waitForNonTerrestrialNetworkConnection()160         public boolean waitForNonTerrestrialNetworkConnection() {
161             try {
162                 if (!mNonTerrestrialNetworkSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
163                     loge("Timeout to connect to non-terrestrial network");
164                     return false;
165                 }
166             } catch (Exception e) {
167                 loge("ServiceStateListenerTest waitForNonTerrestrialNetworkConnection: "
168                         + "Got exception=" + e);
169                 return false;
170             }
171             return true;
172         }
173 
getServiceState()174         public ServiceState getServiceState() {
175             return mServiceState;
176         }
177 
clearServiceStateChanges()178         public void clearServiceStateChanges() {
179             logd("clearServiceStateChanges()");
180             mNonTerrestrialNetworkSemaphore.drainPermits();
181         }
182     }
183 
184     @BeforeClass
beforeAllTests()185     public static void beforeAllTests() {
186         // assumeTrue() in @BeforeClass is not supported by our test runner.
187         // Resort to the early exit.
188         if (!ImsUtils.shouldTestImsService()) {
189             return;
190         }
191 
192         if (Looper.getMainLooper() == null) {
193             Looper.prepareMainLooper();
194         }
195         sHandler = new Handler(Looper.getMainLooper());
196 
197         sTelephonyManager = InstrumentationRegistry.getInstrumentation().getContext()
198                 .getSystemService(TelephonyManager.class);
199     }
200 
201     @AfterClass
afterAllTests()202     public static void afterAllTests() {
203         // assumeTrue() in @AfterClass is not supported by our test runner.
204         // Resort to the early exit.
205         if (!ImsUtils.shouldTestImsService()) {
206             return;
207         }
208 
209         sHandler = null;
210         sTelephonyManager = null;
211     }
212 
213     @Before
beforeTest()214     public void beforeTest() {
215         assumeTrue(ImsUtils.shouldTestImsService());
216 
217         sTestSub = ImsUtils.getPreferredActiveSubId();
218         if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
219             fail("This test requires that there is a SIM in the device!");
220         }
221 
222         sReceiver = new CarrierConfigReceiver(sTestSub);
223         IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
224         // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
225         getContext().registerReceiver(sReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED);
226     }
227 
228     @After
afterTest()229     public void afterTest() {
230         // assumeTrue() in @After is not supported by our test runner.
231         // Resort to the early exit.
232         if (!ImsUtils.shouldTestImsService()) {
233             return;
234         }
235 
236         if (sReceiver != null) {
237             getContext().unregisterReceiver(sReceiver);
238             sReceiver = null;
239         }
240     }
241 
242     @Test
testGetVoWiFiSetting_noPermission()243     public void testGetVoWiFiSetting_noPermission() {
244         try {
245             ImsManager imsManager = getContext().getSystemService(ImsManager.class);
246             ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
247             boolean isEnabled = mMmTelManager.isVoWiFiSettingEnabled();
248             fail("Expected SecurityException for missing permissions");
249         } catch (SecurityException ex) {
250             /* Expected */
251         }
252     }
253 
254     /**
255      * Given the advanced calling setting is editable and not hidden
256      * (see {@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL}, and
257      * {@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL}), set the advanced
258      * calling setting and ensure the correct calling setting is returned. Also ensure the
259      * ContentObserver is triggered properly.
260      */
261     @Test
262     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testAdvancedCallingSetting()263     public void testAdvancedCallingSetting() throws Exception {
264         // Ensure advanced calling setting is editable.
265         PersistableBundle bundle = new PersistableBundle();
266         bundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
267         bundle.putBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
268         overrideCarrierConfig(bundle);
269         // Register Observer
270         Uri callingUri = Uri.withAppendedPath(
271                 SubscriptionManager.ADVANCED_CALLING_ENABLED_CONTENT_URI, "" + sTestSub);
272         CountDownLatch contentObservedLatch = new CountDownLatch(1);
273         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
274 
275         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
276         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
277         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
278                 ImsMmTelManager::isAdvancedCallingSettingEnabled);
279         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
280                 (m) -> m.setAdvancedCallingSettingEnabled(!isEnabled));
281 
282         waitForLatch(contentObservedLatch, observer);
283         boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
284                 ImsMmTelManager::isAdvancedCallingSettingEnabled);
285         assertEquals("isAdvancedCallingSettingEnabled does not reflect the new value set by "
286                         + "setAdvancedCallingSettingEnabled", !isEnabled, isEnabledResult);
287 
288         // Set back to default
289         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
290                 (m) -> m.setAdvancedCallingSettingEnabled(isEnabled));
291         // restore original carrier config.
292         overrideCarrierConfig(null);
293     }
294 
295     /**
296      * Set the VT setting and ensure it is queried successfully. Also ensure the ContentObserver
297      * is triggered properly.
298      */
299     @Test
300     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVtSetting()301     public void testVtSetting() throws Exception {
302         // Register Observer
303         Uri callingUri = Uri.withAppendedPath(
304                 SubscriptionManager.VT_ENABLED_CONTENT_URI, "" + sTestSub);
305         CountDownLatch contentObservedLatch = new CountDownLatch(1);
306         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
307 
308         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
309         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
310         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
311                 ImsMmTelManager::isVtSettingEnabled);
312         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
313                 (m) -> m.setVtSettingEnabled(!isEnabled));
314 
315         waitForLatch(contentObservedLatch, observer);
316         boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
317                 ImsMmTelManager::isVtSettingEnabled);
318         assertEquals("isVtSettingEnabled does not match the value set by setVtSettingEnabled",
319                 !isEnabled, isEnabledResult);
320 
321         // Set back to default
322         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
323                 (m) -> m.setVtSettingEnabled(isEnabled));
324     }
325 
326     /**
327      * Set the VoWiFi setting and ensure it is queried successfully. Also ensure the ContentObserver
328      * is triggered properly.
329      */
330     @Test
331     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVoWiFiSetting()332     public void testVoWiFiSetting() throws Exception {
333         PersistableBundle bundle = new PersistableBundle();
334         // Do not worry about provisioning for this test
335         bundle.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
336         bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
337         overrideCarrierConfig(bundle);
338         // Register Observer
339         Uri callingUri = Uri.withAppendedPath(
340                 SubscriptionManager.WFC_ENABLED_CONTENT_URI, "" + sTestSub);
341         CountDownLatch contentObservedLatch = new CountDownLatch(1);
342         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
343 
344         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
345         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
346 
347         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
348                 ImsMmTelManager::isVoWiFiSettingEnabled);
349         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
350                 (m) -> m.setVoWiFiSettingEnabled(!isEnabled));
351 
352         waitForLatch(contentObservedLatch, observer);
353         boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
354                 ImsMmTelManager::isVoWiFiSettingEnabled);
355         assertEquals("isVoWiFiSettingEnabled did not match value set by setVoWiFiSettingEnabled",
356                 !isEnabled, isEnabledResult);
357 
358         // Set back to default
359         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
360                 (m) -> m.setVoWiFiSettingEnabled(isEnabled));
361         overrideCarrierConfig(null);
362     }
363 
364     /**
365      * Set the cross SIM setting and ensure it is queried successfully.
366      * Also ensure the ContentObserver is triggered properly.
367      */
368     @Test
369     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testCrossSIMSetting()370     public void testCrossSIMSetting() throws Exception {
371         PersistableBundle bundle = new PersistableBundle();
372         // Do not worry about provisioning for this test
373         bundle.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
374         bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
375         overrideCarrierConfig(bundle);
376         // Register Observer
377         Uri callingUri = Uri.withAppendedPath(
378                 SubscriptionManager.CROSS_SIM_ENABLED_CONTENT_URI, "" + sTestSub);
379         CountDownLatch contentObservedLatch = new CountDownLatch(1);
380         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
381 
382         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
383         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
384 
385         boolean isEnabled = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
386                 mMmTelManager, ImsMmTelManager::isCrossSimCallingEnabled, ImsException.class,
387                 "android.permission.READ_PRIVILEGED_PHONE_STATE");
388         ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
389                 (m) -> m.setCrossSimCallingEnabled(!isEnabled),  ImsException.class,
390                 "android.permission.MODIFY_PHONE_STATE");
391 
392         waitForLatch(contentObservedLatch, observer);
393         boolean isEnabledResult = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
394                 mMmTelManager,
395                 ImsMmTelManager::isCrossSimCallingEnabled,
396                 ImsException.class,
397                 "android.permission.READ_PRIVILEGED_PHONE_STATE");
398         assertEquals("isCrossSimCallingEnabled did not match"
399                         + "value set by setCrossSimCallingEnabled",
400                 !isEnabled, isEnabledResult);
401 
402         // Set back to default
403         ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
404                 (m) -> m.setCrossSimCallingEnabled(isEnabled),
405                 ImsException.class,
406                 "android.permission.MODIFY_PHONE_STATE");
407         overrideCarrierConfig(null);
408     }
409 
410     /**
411      * Set the VoWiFi roaming setting and ensure it is queried successfully. Also ensure the
412      * ContentObserver is triggered properly.
413      */
414     @Test
415     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVoWiFiRoamingSetting()416     public void testVoWiFiRoamingSetting() throws Exception {
417         Uri callingUri = Uri.withAppendedPath(
418                 SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI, "" + sTestSub);
419         CountDownLatch contentObservedLatch = new CountDownLatch(1);
420         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
421 
422         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
423         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
424         boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
425                 ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
426         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
427                 (m) -> m.setVoWiFiRoamingSettingEnabled(!isEnabled));
428 
429         waitForLatch(contentObservedLatch, observer);
430         boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
431                 ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
432         assertEquals("isVoWiFiRoamingSettingEnabled result does not match the value set by "
433                 + "setVoWiFiRoamingSettingEnabled", !isEnabled, isEnabledResult);
434 
435         // Set back to default
436         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
437                 (m) -> m.setVoWiFiRoamingSettingEnabled(isEnabled));
438     }
439 
440     /**
441      * Expect to fail when Set the VoWiFi Mode setting withour proper permission
442      */
443     @Test
testGetVoWiFiModeSetting_noPermission()444     public void testGetVoWiFiModeSetting_noPermission() throws Exception {
445         try {
446             ImsManager imsManager = getContext().getSystemService(ImsManager.class);
447             ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
448             int oldMode = mMmTelManager.getVoWiFiModeSetting();
449             fail("Expected SecurityException for missing permissoins");
450         } catch (SecurityException ex) {
451             /* Expected */
452         }
453 
454     }
455 
456     /**
457      * Expect to fail when Set the VoWiFi Mode setting withour proper permission
458      */
459     @Test
testGetVoWiFiRoamingModeSetting_noPermission()460     public void testGetVoWiFiRoamingModeSetting_noPermission() throws Exception {
461         try {
462             ImsManager imsManager = getContext().getSystemService(ImsManager.class);
463             ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
464             int oldMode = mMmTelManager.getVoWiFiRoamingModeSetting();
465             fail("Expected SecurityException for missing permissoins");
466         } catch (SecurityException ex) {
467             /* Expected */
468         }
469 
470     }
471 
472 
473     /**
474      * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
475      */
476     @Test
477     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVoWiFiModeSetting()478     public void testVoWiFiModeSetting() throws Exception {
479         PersistableBundle bundle = new PersistableBundle();
480         bundle.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
481         overrideCarrierConfig(bundle);
482         // Register Observer
483         Uri callingUri = Uri.withAppendedPath(
484                 SubscriptionManager.WFC_MODE_CONTENT_URI, "" + sTestSub);
485         CountDownLatch contentObservedLatch = new CountDownLatch(1);
486         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
487 
488         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
489         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
490         int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
491                 ImsMmTelManager::getVoWiFiModeSetting);
492         // Keep the mode in the bounds 0-2
493         int newMode = (oldMode + 1) % 3;
494         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
495                 (m) -> m.setVoWiFiModeSetting(newMode));
496 
497         waitForLatch(contentObservedLatch, observer);
498         int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
499                 ImsMmTelManager::getVoWiFiModeSetting);
500         assertEquals(newMode, newModeResult);
501 
502         // Set back to default
503         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
504                 (m) -> m.setVoWiFiModeSetting(oldMode));
505         overrideCarrierConfig(null);
506     }
507 
508     /**
509      * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
510      */
511     @Test
512     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVoWiFiRoamingModeSetting()513     public void testVoWiFiRoamingModeSetting() throws Exception {
514         PersistableBundle bundle = new PersistableBundle();
515         // Ensure the WFC roaming mode will be changed properly
516         bundle.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
517         bundle.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
518         overrideCarrierConfig(bundle);
519         // Register Observer
520         Uri callingUri = Uri.withAppendedPath(
521                 SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, "" + sTestSub);
522         CountDownLatch contentObservedLatch = new CountDownLatch(1);
523         ContentObserver observer = createObserver(callingUri, contentObservedLatch);
524 
525         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
526         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
527         int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
528                 ImsMmTelManager::getVoWiFiRoamingModeSetting);
529         // Keep the mode in the bounds 0-2
530         int newMode = (oldMode + 1) % 3;
531         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
532                 (m) -> m.setVoWiFiRoamingModeSetting(newMode));
533 
534         waitForLatch(contentObservedLatch, observer);
535         int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
536                 ImsMmTelManager::getVoWiFiRoamingModeSetting);
537         assertEquals("getVoWiFiRoamingModeSetting was not set to value set by"
538                 + "setVoWiFiRoamingModeSetting", newMode, newModeResult);
539 
540         // Set back to default
541         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
542                 (m) -> m.setVoWiFiRoamingModeSetting(oldMode));
543         overrideCarrierConfig(null);
544     }
545 
546     @Test
547     @AppModeNonSdkSandbox(reason = "SDK sandboxes do not have access to telephony provider")
testVoWiFiRoamingModeSettingUsingNonTerrestrialNetwork()548     public void testVoWiFiRoamingModeSettingUsingNonTerrestrialNetwork() throws Exception {
549         // Get original VoWiFi roaming mode
550         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
551         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
552         int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
553                 ImsMmTelManager::getVoWiFiRoamingModeSetting);
554 
555         // Register service state listener
556         ServiceStateListenerTest serviceStateListener = new ServiceStateListenerTest();
557         serviceStateListener.clearServiceStateChanges();
558         sTelephonyManager.registerTelephonyCallback(getContext().getMainExecutor(),
559                 serviceStateListener);
560         serviceStateListener.waitUntilServiceStateUpdate();
561         ServiceState serviceState = serviceStateListener.getServiceState();
562         if (serviceState != null) {
563             assumeTrue(
564                     "skip test as subscription is not in service",
565                     serviceState.getState() == ServiceState.STATE_IN_SERVICE);
566         }
567 
568         // Override carrier config
569         PersistableBundle bundle = new PersistableBundle();
570         bundle.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
571         bundle.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
572         bundle.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
573         bundle.putBoolean(KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, true);
574         String plmn = sTelephonyManager.getNetworkOperator(sTestSub);
575         PersistableBundle plmnBundle = new PersistableBundle();
576         int[] intArray1 = {3, 5};
577         plmnBundle.putIntArray(plmn, intArray1);
578         bundle.putPersistableBundle(
579                 CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
580                 plmnBundle);
581 
582         try {
583             overrideCarrierConfig(bundle);
584             assertTrue(serviceStateListener.waitForNonTerrestrialNetworkConnection());
585 
586             // Register Observer
587             Uri callingUri = Uri.withAppendedPath(
588                     SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, "" + sTestSub);
589             CountDownLatch contentObservedLatch = new CountDownLatch(1);
590             ContentObserver observer = createObserver(callingUri, contentObservedLatch);
591 
592             // Set VoWiFi roaming mode to CELLULAR_PREFERRED
593             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
594                     (m) -> m.setVoWiFiRoamingModeSetting(
595                             ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED));
596             waitForLatch(contentObservedLatch, observer);
597 
598             int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
599                     ImsMmTelManager::getVoWiFiRoamingModeSetting);
600             assertEquals(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED, newModeResult);
601         } finally {
602             // Set back to default
603             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
604                     (m) -> m.setVoWiFiRoamingModeSetting(oldMode));
605             overrideCarrierConfig(null);
606         }
607     }
608 
609     /**
610      * Test Permissions on various APIs.
611      */
612     @Test
testMethodPermissions()613     public void testMethodPermissions() throws Exception {
614         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
615         ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
616         // setRttCapabilitySetting
617         try {
618             mMmTelManager.setRttCapabilitySetting(false);
619             fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
620         } catch (SecurityException e) {
621             //expected
622         }
623         try {
624             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
625                     (m) -> m.setRttCapabilitySetting(false),
626                     "android.permission.MODIFY_PHONE_STATE");
627         } catch (SecurityException e) {
628             fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
629         }
630         // setVoWiFiNonPersistent
631         try {
632             mMmTelManager.setVoWiFiNonPersistent(true,
633                     ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED);
634             fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
635         } catch (SecurityException e) {
636             //expected
637         }
638         try {
639             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
640                     (m) -> m.setVoWiFiNonPersistent(true,
641                             ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED),
642                     "android.permission.MODIFY_PHONE_STATE");
643         } catch (SecurityException e) {
644             fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
645         }
646 
647         try {
648             mMmTelManager.isVtSettingEnabled();
649             fail("isVtSettingEnabled requires READ_PRECISE_PHONE_STATE permission.");
650         } catch (SecurityException e) {
651             //expected
652         }
653 
654         try {
655             mMmTelManager.isAdvancedCallingSettingEnabled();
656             fail("isAdvancedCallingSettingEnabled requires READ_PRECISE_PHONE_STATE.");
657         } catch (SecurityException e) {
658             //expected
659         }
660 
661         try {
662             mMmTelManager.isVoWiFiRoamingSettingEnabled();
663             fail("isVoWiFiRoamingSettingEnabled requires READ_PRECISE_PHONE_STATE permission.");
664         } catch (SecurityException e) {
665             //expected
666         }
667 
668         try {
669             mMmTelManager.isVoWiFiSettingEnabled();
670             fail("isVoWiFiSettingEnabled requires READ_PRECISE_PHONE_STATE permission.");
671         } catch (SecurityException e) {
672             //expected
673         }
674 
675         try {
676             mMmTelManager.isTtyOverVolteEnabled();
677             fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
678         } catch (SecurityException e) {
679             //expected
680         }
681         try {
682             mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
683                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
684             fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
685         } catch (SecurityException e) {
686             //expected
687         }
688         try {
689             mMmTelManager.getRegistrationState(Runnable::run, (result) -> { });
690             fail("getRegistrationState requires READ_PRECISE_PHONE_STATE permission.");
691         } catch (SecurityException e) {
692             //expected
693         }
694         try {
695             mMmTelManager.getRegistrationTransportType(Runnable::run, (result) -> { });
696             fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
697         } catch (SecurityException e) {
698             //expected
699         }
700 
701         try {
702             mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
703                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
704             fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
705         } catch (SecurityException e) {
706             //expected
707         }
708 
709         try {
710             ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
711                     ImsMmTelManager::isTtyOverVolteEnabled,
712                     "android.permission.READ_PRIVILEGED_PHONE_STATE");
713         } catch (SecurityException e) {
714             fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
715         }
716         try {
717             LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1);
718             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
719                     (m) -> m.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
720                             AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
721                             // Run on the binder thread.
722                             Runnable::run,
723                             resultQueue::offer), ImsException.class,
724                     "android.permission.READ_PRIVILEGED_PHONE_STATE");
725             assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
726         } catch (SecurityException e) {
727             fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
728         } catch (ImsException ignore) {
729             // We are only testing method permissions here, so the actual ImsException does not
730             // matter, since it shows that the permission check passed.
731         }
732         try {
733             LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
734             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
735                     (m) -> m.getRegistrationState(Runnable::run, resultQueue::offer),
736                     ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
737             assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
738         } catch (SecurityException e) {
739             fail("getRegistrationState requires READ_PRIVILEGED_PHONE_STATE permission.");
740         }
741         try {
742             LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
743             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
744                     (m) -> m.getRegistrationTransportType(Runnable::run, resultQueue::offer),
745                     ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
746             assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
747         } catch (SecurityException e) {
748             fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
749         }
750 
751         ImsStateCallback callback = new ImsStateCallback() {
752             @Override
753             public void onUnavailable(int reason) { }
754             @Override
755             public void onAvailable() { }
756             @Override
757             public void onError() { }
758         };
759 
760         try {
761             mMmTelManager.registerImsStateCallback(Runnable::run, callback);
762             fail("registerImsStateCallback requires READ_PRECISE_PHONE_STATE or "
763                     + "READ_PRIVILEGED_PHONE_STATE permission.");
764         } catch (SecurityException e) {
765             //expected
766         } catch (ImsException ie) {
767             fail("registerImsStateCallback requires READ_PRECISE_PHONE_STATE or "
768                     + "READ_PRIVILEGED_PHONE_STATE permission.");
769         }
770 
771         try {
772             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
773                     m -> m.registerImsStateCallback(Runnable::run, callback),
774                     ImsException.class, "android.permission.READ_PRECISE_PHONE_STATE");
775         } catch (SecurityException e) {
776             fail("registerImsStateCallback requires READ_PRECISE_PHONE_STATE permission.");
777         } catch (ImsException ignore) {
778             // don't care, permission check passed
779         }
780 
781         try {
782             mMmTelManager.unregisterImsStateCallback(callback);
783         } catch (SecurityException e) {
784             fail("uregisterImsStateCallback requires no permission.");
785         }
786 
787         try {
788             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
789                     m -> m.registerImsStateCallback(Runnable::run, callback),
790                     ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
791         } catch (SecurityException e) {
792             fail("registerImsStateCallback requires READ_PRIVILEGED_PHONE_STATE permission.");
793         } catch (ImsException ignore) {
794             // don't care, permission check passed
795         }
796 
797         try {
798             mMmTelManager.unregisterImsStateCallback(callback);
799         } catch (SecurityException e) {
800             // unreachable, already passed permission check
801             fail("uregisterImsStateCallback requires no permission.");
802         }
803     }
804 
overrideCarrierConfig(PersistableBundle bundle)805     private void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
806         CarrierConfigManager carrierConfigManager = getContext().getSystemService(
807                 CarrierConfigManager.class);
808         sReceiver.clearQueue();
809         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
810                 (m) -> m.overrideConfig(sTestSub, bundle));
811         sReceiver.waitForCarrierConfigChanged();
812     }
813 
createObserver(Uri observerUri, CountDownLatch latch)814     private ContentObserver createObserver(Uri observerUri, CountDownLatch latch) {
815         ContentObserver observer = new ContentObserver(sHandler) {
816             @Override
817             public void onChange(boolean selfChange, Uri uri) {
818                 if (observerUri.equals(uri)) {
819                     latch.countDown();
820                 }
821             }
822         };
823         getContext().getContentResolver().registerContentObserver(observerUri, true, observer);
824         return observer;
825     }
826 
waitForLatch(CountDownLatch latch, ContentObserver observer)827     private void waitForLatch(CountDownLatch latch, ContentObserver observer) {
828         try {
829             // Wait for the ContentObserver to fire signalling the change.
830             latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
831         } catch (InterruptedException e) {
832             fail("Interrupted Exception waiting for latch countdown:" + e.getMessage());
833         } finally {
834             getContext().getContentResolver().unregisterContentObserver(observer);
835         }
836     }
837 
getContext()838     private static Context getContext() {
839         return InstrumentationRegistry.getInstrumentation().getContext();
840     }
841 
logd(@onNull String log)842     protected static void logd(@NonNull String log) {
843         Rlog.d(TAG, log);
844     }
845 
loge(@onNull String log)846     protected static void loge(@NonNull String log) {
847         Rlog.e(TAG, log);
848     }
849 }
850