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