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