1 /* 2 * Copyright (C) 2023 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.satellite.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import android.Manifest; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.bluetooth.BluetoothAdapter; 29 import android.content.BroadcastReceiver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.PackageManager; 33 import android.database.ContentObserver; 34 import android.net.wifi.WifiManager; 35 import android.nfc.NfcAdapter; 36 import android.os.Handler; 37 import android.os.Looper; 38 import android.os.OutcomeReceiver; 39 import android.provider.Settings; 40 import android.telephony.Rlog; 41 import android.telephony.SubscriptionInfo; 42 import android.telephony.SubscriptionManager; 43 import android.telephony.TelephonyManager; 44 import android.telephony.cts.TelephonyManagerTest.ServiceStateRadioStateListener; 45 import android.telephony.satellite.EnableRequestAttributes; 46 import android.telephony.satellite.NtnSignalStrength; 47 import android.telephony.satellite.NtnSignalStrengthCallback; 48 import android.telephony.satellite.PointingInfo; 49 import android.telephony.satellite.SatelliteCapabilities; 50 import android.telephony.satellite.SatelliteCapabilitiesCallback; 51 import android.telephony.satellite.SatelliteCommunicationAllowedStateCallback; 52 import android.telephony.satellite.SatelliteDatagram; 53 import android.telephony.satellite.SatelliteDatagramCallback; 54 import android.telephony.satellite.SatelliteManager; 55 import android.telephony.satellite.SatelliteModemStateCallback; 56 import android.telephony.satellite.SatelliteProvisionStateCallback; 57 import android.telephony.satellite.SatelliteSupportedStateCallback; 58 import android.telephony.satellite.SatelliteTransmissionUpdateCallback; 59 import android.text.TextUtils; 60 import android.util.Log; 61 import android.uwb.UwbManager; 62 63 import androidx.test.InstrumentationRegistry; 64 65 import com.android.compatibility.common.util.ShellIdentityUtils; 66 67 import java.util.ArrayList; 68 import java.util.List; 69 import java.util.concurrent.CountDownLatch; 70 import java.util.concurrent.LinkedBlockingQueue; 71 import java.util.concurrent.Semaphore; 72 import java.util.concurrent.TimeUnit; 73 import java.util.concurrent.atomic.AtomicReference; 74 import java.util.function.Consumer; 75 76 public class SatelliteManagerTestBase { 77 protected static String TAG = "SatelliteManagerTestBase"; 78 79 protected static final String TOKEN = "TEST_TOKEN"; 80 protected static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5); 81 /** 82 * Since SST sets waiting time up to 10 seconds for the power off radio, the timer waiting for 83 * radio power state change should be greater than 10 seconds. 84 */ 85 protected static final long EXTERNAL_DEPENDENT_TIMEOUT = TimeUnit.SECONDS.toMillis(15); 86 87 protected static SatelliteManager sSatelliteManager; 88 protected static TelephonyManager sTelephonyManager = null; 89 90 protected UwbManager mUwbManager = null; 91 protected NfcAdapter mNfcAdapter = null; 92 protected BluetoothAdapter mBluetoothAdapter = null; 93 protected WifiManager mWifiManager = null; 94 beforeAllTestsBase()95 protected static void beforeAllTestsBase() { 96 sSatelliteManager = getContext().getSystemService(SatelliteManager.class); 97 sTelephonyManager = getContext().getSystemService(TelephonyManager.class); 98 turnRadioOn(); 99 } 100 afterAllTestsBase()101 protected static void afterAllTestsBase() { 102 sSatelliteManager = null; 103 sTelephonyManager = null; 104 } 105 shouldTestSatellite()106 protected static boolean shouldTestSatellite() { 107 if (!getContext().getPackageManager().hasSystemFeature( 108 PackageManager.FEATURE_TELEPHONY_SATELLITE)) { 109 logd("Skipping tests because FEATURE_TELEPHONY_SATELLITE is not available"); 110 return false; 111 } 112 try { 113 getContext().getSystemService(TelephonyManager.class) 114 .getHalVersion(TelephonyManager.HAL_SERVICE_RADIO); 115 } catch (IllegalStateException e) { 116 logd("Skipping tests because Telephony service is null, exception=" + e); 117 return false; 118 } 119 return true; 120 } 121 shouldTestSatelliteWithMockService()122 protected static boolean shouldTestSatelliteWithMockService() { 123 if (!getContext().getPackageManager().hasSystemFeature( 124 PackageManager.FEATURE_TELEPHONY)) { 125 logd("Skipping tests because FEATURE_TELEPHONY is not available"); 126 return false; 127 } 128 try { 129 getContext().getSystemService(TelephonyManager.class) 130 .getHalVersion(TelephonyManager.HAL_SERVICE_RADIO); 131 } catch (IllegalStateException e) { 132 logd("Skipping tests because Telephony service is null, exception=" + e); 133 return false; 134 } 135 return true; 136 } 137 getContext()138 protected static Context getContext() { 139 return InstrumentationRegistry.getContext(); 140 } 141 grantSatellitePermission()142 protected static void grantSatellitePermission() { 143 InstrumentationRegistry.getInstrumentation().getUiAutomation() 144 .adoptShellPermissionIdentity(Manifest.permission.SATELLITE_COMMUNICATION); 145 } 146 revokeSatellitePermission()147 protected static void revokeSatellitePermission() { 148 InstrumentationRegistry.getInstrumentation().getUiAutomation() 149 .dropShellPermissionIdentity(); 150 } 151 152 protected static class SatelliteTransmissionUpdateCallbackTest implements 153 SatelliteTransmissionUpdateCallback { 154 155 protected static final class DatagramStateChangeArgument { 156 protected int state; 157 protected int pendingCount; 158 protected int errorCode; 159 DatagramStateChangeArgument(int state, int pendingCount, int errorCode)160 DatagramStateChangeArgument(int state, int pendingCount, int errorCode) { 161 this.state = state; 162 this.pendingCount = pendingCount; 163 this.errorCode = errorCode; 164 } 165 166 @Override equals(Object other)167 public boolean equals(Object other) { 168 if (this == other) return true; 169 if (other == null || getClass() != other.getClass()) return false; 170 DatagramStateChangeArgument that = (DatagramStateChangeArgument) other; 171 return state == that.state 172 && pendingCount == that.pendingCount 173 && errorCode == that.errorCode; 174 } 175 176 @Override toString()177 public String toString() { 178 return ("state: " + state + " pendingCount: " + pendingCount 179 + " errorCode: " + errorCode); 180 } 181 } 182 183 public PointingInfo mPointingInfo; 184 private final Semaphore mPositionChangeSemaphore = new Semaphore(0); 185 private List<DatagramStateChangeArgument> mSendDatagramStateChanges = new ArrayList<>(); 186 private final Object mSendDatagramStateChangesLock = new Object(); 187 private final Semaphore mSendSemaphore = new Semaphore(0); 188 private List<DatagramStateChangeArgument> mReceiveDatagramStateChanges = new ArrayList<>(); 189 private final Object mReceiveDatagramStateChangesLock = new Object(); 190 private final Semaphore mReceiveSemaphore = new Semaphore(0); 191 192 @Override onSatellitePositionChanged(PointingInfo pointingInfo)193 public void onSatellitePositionChanged(PointingInfo pointingInfo) { 194 logd("onSatellitePositionChanged: pointingInfo=" + pointingInfo); 195 mPointingInfo = pointingInfo; 196 197 try { 198 mPositionChangeSemaphore.release(); 199 } catch (Exception e) { 200 loge("onSatellitePositionChanged: Got exception, ex=" + e); 201 } 202 } 203 204 @Override onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode)205 public void onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode) { 206 logd("onSendDatagramStateChanged: state=" + state + ", sendPendingCount=" 207 + sendPendingCount + ", errorCode=" + errorCode); 208 synchronized (mSendDatagramStateChangesLock) { 209 mSendDatagramStateChanges.add(new DatagramStateChangeArgument(state, 210 sendPendingCount, errorCode)); 211 } 212 213 try { 214 mSendSemaphore.release(); 215 } catch (Exception e) { 216 loge("onSendDatagramStateChanged: Got exception, ex=" + e); 217 } 218 } 219 220 @Override onSendDatagramStateChanged( int datagramType, int state, int sendPendingCount, int errorCode)221 public void onSendDatagramStateChanged( 222 int datagramType, int state, int sendPendingCount, int errorCode) { 223 logd("onSendDatagramStateChanged:datagramType=" + datagramType + ", state=" + state 224 + ", sendPendingCount=" + sendPendingCount + ", errorCode=" + errorCode); 225 } 226 227 @Override onReceiveDatagramStateChanged( int state, int receivePendingCount, int errorCode)228 public void onReceiveDatagramStateChanged( 229 int state, int receivePendingCount, int errorCode) { 230 logd("onReceiveDatagramStateChanged: state=" + state + ", " 231 + "receivePendingCount=" + receivePendingCount + ", errorCode=" + errorCode); 232 synchronized (mReceiveDatagramStateChangesLock) { 233 mReceiveDatagramStateChanges.add(new DatagramStateChangeArgument(state, 234 receivePendingCount, errorCode)); 235 } 236 237 try { 238 mReceiveSemaphore.release(); 239 } catch (Exception e) { 240 loge("onReceiveDatagramStateChanged: Got exception, ex=" + e); 241 } 242 } 243 waitUntilOnSatellitePositionChanged(int expectedNumberOfEvents)244 public boolean waitUntilOnSatellitePositionChanged(int expectedNumberOfEvents) { 245 for (int i = 0; i < expectedNumberOfEvents; i++) { 246 try { 247 if (!mPositionChangeSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 248 loge("Timeout to receive onSatellitePositionChanged() callback"); 249 return false; 250 } 251 } catch (Exception ex) { 252 loge("SatelliteTransmissionUpdateCallback " 253 + "waitUntilOnSatellitePositionChanged: Got exception=" + ex); 254 return false; 255 } 256 } 257 return true; 258 } 259 waitUntilOnSendDatagramStateChanged(int expectedNumberOfEvents)260 public boolean waitUntilOnSendDatagramStateChanged(int expectedNumberOfEvents) { 261 logd("waitUntilOnSendDatagramStateChanged expectedNumberOfEvents:" + expectedNumberOfEvents); 262 for (int i = 0; i < expectedNumberOfEvents; i++) { 263 try { 264 if (!mSendSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 265 loge("Timeout to receive onSendDatagramStateChanged() callback"); 266 return false; 267 } 268 } catch (Exception ex) { 269 loge("SatelliteTransmissionUpdateCallback " 270 + "waitUntilOnSendDatagramStateChanged: Got exception=" + ex); 271 return false; 272 } 273 } 274 return true; 275 } 276 waitUntilOnReceiveDatagramStateChanged(int expectedNumberOfEvents)277 public boolean waitUntilOnReceiveDatagramStateChanged(int expectedNumberOfEvents) { 278 for (int i = 0; i < expectedNumberOfEvents; i++) { 279 try { 280 if (!mReceiveSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 281 loge("Timeout to receive onReceiveDatagramStateChanged()"); 282 return false; 283 } 284 } catch (Exception ex) { 285 loge("SatelliteTransmissionUpdateCallback " 286 + "waitUntilOnReceiveDatagramStateChanged: Got exception=" + ex); 287 return false; 288 } 289 } 290 return true; 291 } 292 clearPointingInfo()293 public void clearPointingInfo() { 294 mPointingInfo = null; 295 mPositionChangeSemaphore.drainPermits(); 296 } 297 clearSendDatagramStateChanges()298 public void clearSendDatagramStateChanges() { 299 synchronized (mSendDatagramStateChangesLock) { 300 logd("clearSendDatagramStateChanges"); 301 mSendDatagramStateChanges.clear(); 302 mSendSemaphore.drainPermits(); 303 } 304 } 305 clearReceiveDatagramStateChanges()306 public void clearReceiveDatagramStateChanges() { 307 synchronized (mReceiveDatagramStateChangesLock) { 308 logd("clearReceiveDatagramStateChanges"); 309 mReceiveDatagramStateChanges.clear(); 310 mReceiveSemaphore.drainPermits(); 311 } 312 } 313 314 @Nullable getSendDatagramStateChange(int index)315 public DatagramStateChangeArgument getSendDatagramStateChange(int index) { 316 synchronized (mSendDatagramStateChangesLock) { 317 if (index < mSendDatagramStateChanges.size()) { 318 return mSendDatagramStateChanges.get(index); 319 } else { 320 Log.e(TAG, "getSendDatagramStateChange: invalid index= " + index 321 + " mSendDatagramStateChanges.size= " 322 + mSendDatagramStateChanges.size()); 323 return null; 324 } 325 } 326 } 327 328 @Nullable getReceiveDatagramStateChange(int index)329 public DatagramStateChangeArgument getReceiveDatagramStateChange(int index) { 330 synchronized (mReceiveDatagramStateChangesLock) { 331 if (index < mReceiveDatagramStateChanges.size()) { 332 return mReceiveDatagramStateChanges.get(index); 333 } else { 334 Log.e(TAG, "getReceiveDatagramStateChange: invalid index= " + index 335 + " mReceiveDatagramStateChanges.size= " 336 + mReceiveDatagramStateChanges.size()); 337 return null; 338 } 339 } 340 } 341 getNumOfSendDatagramStateChanges()342 public int getNumOfSendDatagramStateChanges() { 343 synchronized (mSendDatagramStateChangesLock) { 344 logd("getNumOfSendDatagramStateChanges size:" + mSendDatagramStateChanges.size()); 345 return mSendDatagramStateChanges.size(); 346 } 347 } 348 getNumOfReceiveDatagramStateChanges()349 public int getNumOfReceiveDatagramStateChanges() { 350 synchronized (mReceiveDatagramStateChangesLock) { 351 return mReceiveDatagramStateChanges.size(); 352 } 353 } 354 } 355 356 protected static class SatelliteProvisionStateCallbackTest implements 357 SatelliteProvisionStateCallback { 358 public boolean isProvisioned = false; 359 private List<Boolean> mProvisionedStates = new ArrayList<>(); 360 private final Object mProvisionedStatesLock = new Object(); 361 private final Semaphore mSemaphore = new Semaphore(0); 362 363 @Override onSatelliteProvisionStateChanged(boolean provisioned)364 public void onSatelliteProvisionStateChanged(boolean provisioned) { 365 logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned); 366 isProvisioned = provisioned; 367 synchronized (mProvisionedStatesLock) { 368 mProvisionedStates.add(provisioned); 369 } 370 try { 371 mSemaphore.release(); 372 } catch (Exception ex) { 373 loge("onSatelliteProvisionStateChanged: Got exception, ex=" + ex); 374 } 375 } 376 waitUntilResult(int expectedNumberOfEvents)377 public boolean waitUntilResult(int expectedNumberOfEvents) { 378 for (int i = 0; i < expectedNumberOfEvents; i++) { 379 try { 380 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 381 loge("Timeout to receive onSatelliteProvisionStateChanged"); 382 return false; 383 } 384 } catch (Exception ex) { 385 loge("onSatelliteProvisionStateChanged: Got exception=" + ex); 386 return false; 387 } 388 } 389 return true; 390 } 391 clearProvisionedStates()392 public void clearProvisionedStates() { 393 synchronized (mProvisionedStatesLock) { 394 mProvisionedStates.clear(); 395 mSemaphore.drainPermits(); 396 } 397 } 398 getTotalCountOfProvisionedStates()399 public int getTotalCountOfProvisionedStates() { 400 synchronized (mProvisionedStatesLock) { 401 return mProvisionedStates.size(); 402 } 403 } 404 getProvisionedState(int index)405 public boolean getProvisionedState(int index) { 406 synchronized (mProvisionedStatesLock) { 407 if (index < mProvisionedStates.size()) { 408 return mProvisionedStates.get(index); 409 } 410 } 411 loge("getProvisionedState: invalid index=" + index); 412 return false; 413 } 414 } 415 416 protected static class SatelliteModemStateCallbackTest implements SatelliteModemStateCallback { 417 public int modemState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; 418 private List<Integer> mModemStates = new ArrayList<>(); 419 private final Object mModemStatesLock = new Object(); 420 private final Semaphore mSemaphore = new Semaphore(0); 421 private final Semaphore mModemOffSemaphore = new Semaphore(0); 422 423 @Override onSatelliteModemStateChanged(int state)424 public void onSatelliteModemStateChanged(int state) { 425 Log.d(TAG, "onSatelliteModemStateChanged: state=" + state); 426 modemState = state; 427 synchronized (mModemStatesLock) { 428 mModemStates.add(state); 429 } 430 try { 431 mSemaphore.release(); 432 } catch (Exception ex) { 433 Log.e(TAG, "onSatelliteModemStateChanged: Got exception, ex=" + ex); 434 } 435 436 if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF) { 437 try { 438 mModemOffSemaphore.release(); 439 } catch (Exception ex) { 440 Log.e(TAG, "onSatelliteModemStateChanged: Got exception in " 441 + "releasing mModemOffSemaphore, ex=" + ex); 442 } 443 } 444 } 445 waitUntilResult(int expectedNumberOfEvents)446 public boolean waitUntilResult(int expectedNumberOfEvents) { 447 for (int i = 0; i < expectedNumberOfEvents; i++) { 448 try { 449 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 450 Log.e(TAG, "Timeout to receive onSatelliteModemStateChanged"); 451 return false; 452 } 453 } catch (Exception ex) { 454 Log.e(TAG, "onSatelliteModemStateChanged: Got exception=" + ex); 455 return false; 456 } 457 } 458 return true; 459 } 460 waitUntilModemOff()461 public boolean waitUntilModemOff() { 462 try { 463 if (!mModemOffSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 464 Log.e(TAG, "Timeout to receive satellite modem off event"); 465 return false; 466 } 467 } catch (Exception ex) { 468 Log.e(TAG, "Waiting for satellite modem off event: Got exception=" + ex); 469 return false; 470 } 471 return true; 472 } 473 waitUntilModemOff(long timeoutMillis)474 public boolean waitUntilModemOff(long timeoutMillis) { 475 try { 476 if (!mModemOffSemaphore.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS)) { 477 Log.e(TAG, "Timeout to receive satellite modem off event"); 478 return false; 479 } 480 } catch (Exception ex) { 481 Log.e(TAG, "Waiting for satellite modem off event: Got exception=" + ex); 482 return false; 483 } 484 return true; 485 } 486 clearModemStates()487 public void clearModemStates() { 488 synchronized (mModemStatesLock) { 489 Log.d(TAG, "onSatelliteModemStateChanged: clearModemStates"); 490 mModemStates.clear(); 491 mSemaphore.drainPermits(); 492 mModemOffSemaphore.drainPermits(); 493 } 494 } 495 getModemState(int index)496 public int getModemState(int index) { 497 synchronized (mModemStatesLock) { 498 if (index < mModemStates.size()) { 499 return mModemStates.get(index); 500 } else { 501 Log.e(TAG, "getModemState: invalid index=" + index 502 + ", mModemStates.size=" + mModemStates.size()); 503 return -1; 504 } 505 } 506 } 507 getTotalCountOfModemStates()508 public int getTotalCountOfModemStates() { 509 synchronized (mModemStatesLock) { 510 return mModemStates.size(); 511 } 512 } 513 } 514 515 protected static class SatelliteDatagramCallbackTest implements SatelliteDatagramCallback { 516 public SatelliteDatagram mDatagram; 517 public final List<SatelliteDatagram> mDatagramList = new ArrayList<>(); 518 public long mDatagramId; 519 private final Semaphore mSemaphore = new Semaphore(0); 520 521 @Override onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram, int pendingCount, Consumer<Void> callback)522 public void onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram, 523 int pendingCount, Consumer<Void> callback) { 524 logd("onSatelliteDatagramReceived: datagramId=" + datagramId + ", datagram=" 525 + datagram + ", pendingCount=" + pendingCount); 526 mDatagram = datagram; 527 mDatagramList.add(datagram); 528 mDatagramId = datagramId; 529 if (callback != null) { 530 logd("onSatelliteDatagramReceived: callback.accept() datagramId=" + datagramId); 531 callback.accept(null); 532 } else { 533 logd("onSatelliteDatagramReceived: callback is null datagramId=" + datagramId); 534 } 535 536 try { 537 mSemaphore.release(); 538 } catch (Exception e) { 539 loge("onSatelliteDatagramReceived: Got exception, ex=" + e); 540 } 541 } 542 waitUntilResult(int expectedNumberOfEvents)543 public boolean waitUntilResult(int expectedNumberOfEvents) { 544 for (int i = 0; i < expectedNumberOfEvents; i++) { 545 try { 546 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 547 loge("Timeout to receive onSatelliteDatagramReceived"); 548 return false; 549 } 550 } catch (Exception ex) { 551 loge("onSatelliteDatagramReceived: Got exception=" + ex); 552 return false; 553 } 554 } 555 return true; 556 } 557 } 558 559 protected static class NtnSignalStrengthCallbackTest implements NtnSignalStrengthCallback { 560 public NtnSignalStrength mNtnSignalStrength; 561 private final Semaphore mSemaphore = new Semaphore(0); 562 563 @Override onNtnSignalStrengthChanged(@onNull NtnSignalStrength ntnSignalStrength)564 public void onNtnSignalStrengthChanged(@NonNull NtnSignalStrength ntnSignalStrength) { 565 logd("onNtnSignalStrengthChanged: ntnSignalStrength=" + ntnSignalStrength); 566 mNtnSignalStrength = new NtnSignalStrength(ntnSignalStrength); 567 568 try { 569 mSemaphore.release(); 570 } catch (Exception e) { 571 loge("onNtnSignalStrengthChanged: Got exception, ex=" + e); 572 } 573 } 574 waitUntilResult(int expectedNumberOfEvents)575 public boolean waitUntilResult(int expectedNumberOfEvents) { 576 for (int i = 0; i < expectedNumberOfEvents; i++) { 577 try { 578 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 579 loge("Timeout to receive onNtnSignalStrengthChanged"); 580 return false; 581 } 582 } catch (Exception ex) { 583 loge("onNtnSignalStrengthChanged: Got exception=" + ex); 584 return false; 585 } 586 } 587 return true; 588 } 589 } 590 591 protected static class SatelliteCapabilitiesCallbackTest implements 592 SatelliteCapabilitiesCallback { 593 public SatelliteCapabilities mSatelliteCapabilities; 594 private final Semaphore mSemaphore = new Semaphore(0); 595 596 @Override onSatelliteCapabilitiesChanged( @onNull SatelliteCapabilities satelliteCapabilities)597 public void onSatelliteCapabilitiesChanged( 598 @NonNull SatelliteCapabilities satelliteCapabilities) { 599 logd("onSatelliteCapabilitiesChanged: satelliteCapabilities=" + satelliteCapabilities); 600 mSatelliteCapabilities = satelliteCapabilities; 601 602 try { 603 mSemaphore.release(); 604 } catch (Exception e) { 605 loge("onSatelliteCapabilitiesChanged: Got exception, ex=" + e); 606 } 607 } 608 waitUntilResult(int expectedNumberOfEvents)609 public boolean waitUntilResult(int expectedNumberOfEvents) { 610 for (int i = 0; i < expectedNumberOfEvents; i++) { 611 try { 612 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 613 loge("Timeout to receive onSatelliteCapabilitiesChanged"); 614 return false; 615 } 616 } catch (Exception ex) { 617 loge("onSatelliteCapabilitiesChanged: Got exception=" + ex); 618 return false; 619 } 620 } 621 return true; 622 } 623 } 624 625 protected static class SatelliteSupportedStateCallbackTest implements 626 SatelliteSupportedStateCallback { 627 public boolean isSupported = false; 628 private List<Boolean> mSupportedStates = new ArrayList<>(); 629 private final Object mSupportedStatesLock = new Object(); 630 private final Semaphore mSemaphore = new Semaphore(0); 631 632 @Override onSatelliteSupportedStateChanged(boolean supported)633 public void onSatelliteSupportedStateChanged(boolean supported) { 634 logd("onSatelliteSupportedStateChanged: supported=" + supported); 635 isSupported = supported; 636 synchronized (mSupportedStatesLock) { 637 mSupportedStates.add(supported); 638 } 639 try { 640 mSemaphore.release(); 641 } catch (Exception ex) { 642 loge("onSatelliteSupportedStateChanged: Got exception, ex=" + ex); 643 } 644 } 645 waitUntilResult(int expectedNumberOfEvents)646 public boolean waitUntilResult(int expectedNumberOfEvents) { 647 for (int i = 0; i < expectedNumberOfEvents; i++) { 648 try { 649 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 650 loge("Timeout to receive onSatelliteSupportedStateChanged"); 651 return false; 652 } 653 } catch (Exception ex) { 654 loge("onSatelliteSupportedStateChanged: Got exception=" + ex); 655 return false; 656 } 657 } 658 return true; 659 } 660 clearSupportedStates()661 public void clearSupportedStates() { 662 synchronized (mSupportedStatesLock) { 663 mSupportedStates.clear(); 664 mSemaphore.drainPermits(); 665 } 666 } 667 getTotalCountOfSupportedStates()668 public int getTotalCountOfSupportedStates() { 669 synchronized (mSupportedStatesLock) { 670 return mSupportedStates.size(); 671 } 672 } 673 getSupportedState(int index)674 public Boolean getSupportedState(int index) { 675 synchronized (mSupportedStatesLock) { 676 if (index < mSupportedStates.size()) { 677 return mSupportedStates.get(index); 678 } 679 } 680 loge("getSupportedState: invalid index=" + index); 681 return null; 682 } 683 } 684 685 protected static class SatelliteCommunicationAllowedStateCallbackTest implements 686 SatelliteCommunicationAllowedStateCallback { 687 public boolean isAllowed = false; 688 private final Semaphore mSemaphore = new Semaphore(0); 689 690 @Override onSatelliteCommunicationAllowedStateChanged(boolean allowed)691 public void onSatelliteCommunicationAllowedStateChanged(boolean allowed) { 692 logd("onSatelliteCommunicationAllowedStateChanged: isAllowed=" + allowed); 693 isAllowed = allowed; 694 695 try { 696 mSemaphore.release(); 697 } catch (Exception e) { 698 loge("onSatelliteCommunicationAllowedStateChanged: Got exception, ex=" + e); 699 } 700 } 701 waitUntilResult(int expectedNumberOfEvents)702 public boolean waitUntilResult(int expectedNumberOfEvents) { 703 for (int i = 0; i < expectedNumberOfEvents; i++) { 704 try { 705 if (!mSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { 706 loge("Timeout to receive onSatelliteCommunicationAllowedStateChanged"); 707 return false; 708 } 709 } catch (Exception ex) { 710 loge("onNtnSignalStrengthChanged: Got exception=" + ex); 711 return false; 712 } 713 } 714 return true; 715 } 716 } 717 718 protected static class SatelliteModeRadiosUpdater extends ContentObserver implements 719 AutoCloseable { 720 private final Context mContext; 721 private final Semaphore mSemaphore = new Semaphore(0); 722 private String mExpectedSatelliteModeRadios = ""; 723 private final Object mLock = new Object(); 724 SatelliteModeRadiosUpdater(Context context)725 public SatelliteModeRadiosUpdater(Context context) { 726 super(new Handler(Looper.getMainLooper())); 727 mContext = context; 728 mContext.getContentResolver().registerContentObserver( 729 Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS), false, this); 730 InstrumentationRegistry.getInstrumentation().getUiAutomation() 731 .adoptShellPermissionIdentity(Manifest.permission.SATELLITE_COMMUNICATION, 732 Manifest.permission.WRITE_SECURE_SETTINGS, 733 Manifest.permission.NETWORK_SETTINGS, 734 Manifest.permission.ACCESS_FINE_LOCATION, 735 Manifest.permission.READ_PRIVILEGED_PHONE_STATE, 736 Manifest.permission.UWB_PRIVILEGED); 737 } 738 739 @Override onChange(boolean selfChange)740 public void onChange(boolean selfChange) { 741 String newSatelliteModeRadios = Settings.Global.getString( 742 mContext.getContentResolver(), Settings.Global.SATELLITE_MODE_RADIOS); 743 synchronized (mLock) { 744 if (TextUtils.equals(mExpectedSatelliteModeRadios, newSatelliteModeRadios)) { 745 logd("SatelliteModeRadiosUpdater: onChange, newSatelliteModeRadios=" 746 + newSatelliteModeRadios); 747 try { 748 mSemaphore.release(); 749 } catch (Exception ex) { 750 loge("SatelliteModeRadiosUpdater: onChange, ex=" + ex); 751 } 752 } 753 } 754 } 755 756 @Override close()757 public void close() throws Exception { 758 mContext.getContentResolver().unregisterContentObserver(this); 759 InstrumentationRegistry.getInstrumentation().getUiAutomation() 760 .dropShellPermissionIdentity(); 761 } 762 setSatelliteModeRadios(String expectedSatelliteModeRadios)763 public boolean setSatelliteModeRadios(String expectedSatelliteModeRadios) { 764 logd("setSatelliteModeRadios: expectedSatelliteModeRadios=" 765 + expectedSatelliteModeRadios); 766 String originalSatelliteModeRadios = Settings.Global.getString( 767 mContext.getContentResolver(), Settings.Global.SATELLITE_MODE_RADIOS); 768 if (TextUtils.equals(expectedSatelliteModeRadios, originalSatelliteModeRadios)) { 769 logd("setSatelliteModeRadios: satellite radios mode is already as expected"); 770 return true; 771 } 772 773 setExpectedSatelliteModeRadios(expectedSatelliteModeRadios); 774 clearSemaphorePermits(); 775 Settings.Global.putString(mContext.getContentResolver(), 776 Settings.Global.SATELLITE_MODE_RADIOS, expectedSatelliteModeRadios); 777 return waitForModeChanged(); 778 } 779 clearSemaphorePermits()780 private void clearSemaphorePermits() { 781 mSemaphore.drainPermits(); 782 } 783 waitForModeChanged()784 private boolean waitForModeChanged() { 785 logd("SatelliteModeRadiosUpdater: waitForModeChanged start"); 786 try { 787 if (!mSemaphore.tryAcquire(EXTERNAL_DEPENDENT_TIMEOUT, TimeUnit.MILLISECONDS)) { 788 loge("SatelliteModeRadiosUpdater: Timeout to wait for mode changed"); 789 return false; 790 } 791 } catch (InterruptedException e) { 792 loge("SatelliteModeRadiosUpdater: waitForModeChanged, e=" + e); 793 return false; 794 } 795 return true; 796 } 797 setExpectedSatelliteModeRadios(String expectedSatelliteModeRadios)798 private void setExpectedSatelliteModeRadios(String expectedSatelliteModeRadios) { 799 synchronized (mLock) { 800 mExpectedSatelliteModeRadios = expectedSatelliteModeRadios; 801 } 802 logd("SatelliteModeRadiosUpdater: mExpectedSatelliteModeRadios=" 803 + mExpectedSatelliteModeRadios); 804 } 805 } 806 provisionSatellite()807 protected static boolean provisionSatellite() { 808 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 809 String mText = "This is test provision data."; 810 byte[] testProvisionData = mText.getBytes(); 811 812 sSatelliteManager.provisionService( 813 TOKEN, testProvisionData, null, getContext().getMainExecutor(), error::offer); 814 Integer errorCode; 815 try { 816 errorCode = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 817 } catch (InterruptedException ex) { 818 loge("provisionSatellite ex=" + ex); 819 return false; 820 } 821 if (errorCode == null || errorCode != SatelliteManager.SATELLITE_RESULT_SUCCESS) { 822 loge("provisionSatellite failed with errorCode=" + errorCode); 823 return false; 824 } 825 return true; 826 } 827 deprovisionSatellite()828 protected static boolean deprovisionSatellite() { 829 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 830 831 sSatelliteManager.deprovisionService( 832 TOKEN, getContext().getMainExecutor(), error::offer); 833 Integer errorCode; 834 try { 835 errorCode = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 836 } catch (InterruptedException ex) { 837 loge("deprovisionSatellite ex=" + ex); 838 return false; 839 } 840 if (errorCode == null || errorCode != SatelliteManager.SATELLITE_RESULT_SUCCESS) { 841 loge("deprovisionSatellite failed with errorCode=" + errorCode); 842 return false; 843 } 844 return true; 845 } 846 isSatelliteProvisioned()847 protected static boolean isSatelliteProvisioned() { 848 final AtomicReference<Boolean> provisioned = new AtomicReference<>(); 849 final AtomicReference<Integer> errorCode = new AtomicReference<>(); 850 CountDownLatch latch = new CountDownLatch(1); 851 OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver = 852 new OutcomeReceiver<>() { 853 @Override 854 public void onResult(Boolean result) { 855 provisioned.set(result); 856 latch.countDown(); 857 } 858 859 @Override 860 public void onError(SatelliteManager.SatelliteException exception) { 861 errorCode.set(exception.getErrorCode()); 862 latch.countDown(); 863 } 864 }; 865 866 sSatelliteManager.requestIsProvisioned( 867 getContext().getMainExecutor(), receiver); 868 try { 869 assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); 870 } catch (InterruptedException ex) { 871 loge("isSatelliteProvisioned ex=" + ex); 872 return false; 873 } 874 875 Integer error = errorCode.get(); 876 Boolean isProvisioned = provisioned.get(); 877 if (error == null) { 878 assertNotNull(isProvisioned); 879 return isProvisioned; 880 } else { 881 assertNull(isProvisioned); 882 logd("isSatelliteProvisioned error=" + error); 883 return false; 884 } 885 } 886 isSatelliteEnabled()887 protected static boolean isSatelliteEnabled() { 888 final AtomicReference<Boolean> enabled = new AtomicReference<>(); 889 final AtomicReference<Integer> errorCode = new AtomicReference<>(); 890 CountDownLatch latch = new CountDownLatch(1); 891 OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver = 892 new OutcomeReceiver<>() { 893 @Override 894 public void onResult(Boolean result) { 895 enabled.set(result); 896 latch.countDown(); 897 } 898 899 @Override 900 public void onError(SatelliteManager.SatelliteException exception) { 901 errorCode.set(exception.getErrorCode()); 902 latch.countDown(); 903 } 904 }; 905 906 907 sSatelliteManager.requestIsEnabled( 908 getContext().getMainExecutor(), receiver); 909 try { 910 assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); 911 } catch (InterruptedException ex) { 912 loge("isSatelliteEnabled ex=" + ex); 913 return false; 914 } 915 916 Integer error = errorCode.get(); 917 Boolean isEnabled = enabled.get(); 918 if (error == null) { 919 assertNotNull(isEnabled); 920 return isEnabled; 921 } else { 922 assertNull(isEnabled); 923 logd("isSatelliteEnabled error=" + error); 924 return false; 925 } 926 } 927 isSatelliteDemoModeEnabled()928 protected static boolean isSatelliteDemoModeEnabled() { 929 final AtomicReference<Boolean> enabled = new AtomicReference<>(); 930 final AtomicReference<Integer> errorCode = new AtomicReference<>(); 931 CountDownLatch latch = new CountDownLatch(1); 932 OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver = 933 new OutcomeReceiver<>() { 934 @Override 935 public void onResult(Boolean result) { 936 enabled.set(result); 937 latch.countDown(); 938 } 939 940 @Override 941 public void onError(SatelliteManager.SatelliteException exception) { 942 errorCode.set(exception.getErrorCode()); 943 latch.countDown(); 944 } 945 }; 946 947 sSatelliteManager.requestIsDemoModeEnabled( 948 getContext().getMainExecutor(), receiver); 949 try { 950 assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); 951 } catch (InterruptedException ex) { 952 loge("isSatelliteDemoModeEnabled ex=" + ex); 953 return false; 954 } 955 956 Integer error = errorCode.get(); 957 Boolean isEnabled = enabled.get(); 958 if (error == null) { 959 assertNotNull(isEnabled); 960 return isEnabled; 961 } else { 962 assertNull(isEnabled); 963 logd("isSatelliteEnabled error=" + error); 964 return false; 965 } 966 } 967 requestSatelliteEnabled(boolean enabled)968 protected static void requestSatelliteEnabled(boolean enabled) { 969 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 970 sSatelliteManager.requestEnabled(new EnableRequestAttributes.Builder(enabled).build(), 971 getContext().getMainExecutor(), error::offer); 972 Integer errorCode; 973 try { 974 errorCode = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 975 } catch (InterruptedException ex) { 976 fail("requestSatelliteEnabled failed with ex=" + ex); 977 return; 978 } 979 assertNotNull(errorCode); 980 assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, (long) errorCode); 981 } 982 requestSatelliteEnabled(boolean enabled, long timeoutMillis)983 protected static void requestSatelliteEnabled(boolean enabled, long timeoutMillis) { 984 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 985 sSatelliteManager.requestEnabled(new EnableRequestAttributes.Builder(enabled).build(), 986 getContext().getMainExecutor(), error::offer); 987 Integer errorCode; 988 try { 989 errorCode = error.poll(timeoutMillis, TimeUnit.MILLISECONDS); 990 } catch (InterruptedException ex) { 991 fail("requestSatelliteEnabled failed with ex=" + ex); 992 return; 993 } 994 assertNotNull(errorCode); 995 assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, (long) errorCode); 996 } 997 requestSatelliteEnabledWithResult(boolean enabled, long timeoutMillis)998 protected static int requestSatelliteEnabledWithResult(boolean enabled, long timeoutMillis) { 999 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 1000 sSatelliteManager.requestEnabled(new EnableRequestAttributes.Builder(enabled).build(), 1001 getContext().getMainExecutor(), error::offer); 1002 Integer errorCode = null; 1003 try { 1004 errorCode = error.poll(timeoutMillis, TimeUnit.MILLISECONDS); 1005 } catch (InterruptedException ex) { 1006 fail("requestSatelliteEnabled failed with ex=" + ex); 1007 } 1008 assertNotNull(errorCode); 1009 return errorCode; 1010 } 1011 requestSatelliteEnabledForDemoMode(boolean enabled)1012 protected static void requestSatelliteEnabledForDemoMode(boolean enabled) { 1013 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 1014 sSatelliteManager.requestEnabled( 1015 new EnableRequestAttributes.Builder(enabled) 1016 .setDemoMode(true) 1017 .setEmergencyMode(true) 1018 .build(), 1019 getContext().getMainExecutor(), error::offer); 1020 Integer errorCode; 1021 try { 1022 errorCode = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 1023 } catch (InterruptedException ex) { 1024 fail("requestSatelliteEnabled failed with ex=" + ex); 1025 return; 1026 } 1027 assertNotNull(errorCode); 1028 assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, (long) errorCode); 1029 } 1030 requestSatelliteEnabled(boolean enabled, boolean demoEnabled, int expectedError)1031 protected static void requestSatelliteEnabled(boolean enabled, boolean demoEnabled, 1032 int expectedError) { 1033 LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1); 1034 sSatelliteManager.requestEnabled( 1035 new EnableRequestAttributes.Builder(enabled).setDemoMode(demoEnabled).build(), 1036 getContext().getMainExecutor(), error::offer); 1037 Integer errorCode; 1038 try { 1039 errorCode = error.poll(TIMEOUT, TimeUnit.MILLISECONDS); 1040 } catch (InterruptedException ex) { 1041 fail("requestSatelliteEnabled failed with ex=" + ex); 1042 return; 1043 } 1044 assertNotNull(errorCode); 1045 assertEquals(expectedError, (long) errorCode); 1046 } 1047 isSatelliteSupported()1048 protected static boolean isSatelliteSupported() { 1049 final AtomicReference<Boolean> supported = new AtomicReference<>(); 1050 final AtomicReference<Integer> errorCode = new AtomicReference<>(); 1051 CountDownLatch latch = new CountDownLatch(1); 1052 OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver = 1053 new OutcomeReceiver<>() { 1054 @Override 1055 public void onResult(Boolean result) { 1056 supported.set(result); 1057 latch.countDown(); 1058 } 1059 1060 @Override 1061 public void onError(SatelliteManager.SatelliteException exception) { 1062 errorCode.set(exception.getErrorCode()); 1063 latch.countDown(); 1064 } 1065 }; 1066 1067 sSatelliteManager.requestIsSupported(getContext().getMainExecutor(), 1068 receiver); 1069 try { 1070 assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); 1071 } catch (InterruptedException ex) { 1072 loge("isSatelliteSupported ex=" + ex); 1073 return false; 1074 } 1075 1076 Integer error = errorCode.get(); 1077 Boolean isSupported = supported.get(); 1078 if (error == null) { 1079 assertNotNull(isSupported); 1080 logd("isSatelliteSupported isSupported=" + isSupported); 1081 return isSupported; 1082 } else { 1083 assertNull(isSupported); 1084 logd("isSatelliteSupported error=" + error); 1085 return false; 1086 } 1087 } 1088 turnRadioOff()1089 protected static void turnRadioOff() { 1090 ServiceStateRadioStateListener callback = new ServiceStateRadioStateListener( 1091 sTelephonyManager.getServiceState(), sTelephonyManager.getRadioPowerState()); 1092 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(sTelephonyManager, 1093 tm -> tm.registerTelephonyCallback(Runnable::run, callback)); 1094 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(sTelephonyManager, 1095 tm -> tm.requestRadioPowerOffForReason(TelephonyManager.RADIO_POWER_REASON_USER), 1096 android.Manifest.permission.MODIFY_PHONE_STATE); 1097 callback.waitForRadioStateIntent(TelephonyManager.RADIO_POWER_OFF); 1098 } 1099 turnRadioOn()1100 protected static void turnRadioOn() { 1101 ServiceStateRadioStateListener callback = new ServiceStateRadioStateListener( 1102 sTelephonyManager.getServiceState(), sTelephonyManager.getRadioPowerState()); 1103 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(sTelephonyManager, 1104 tm -> tm.registerTelephonyCallback(Runnable::run, callback)); 1105 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(sTelephonyManager, 1106 tm -> tm.clearRadioPowerOffForReason(TelephonyManager.RADIO_POWER_REASON_USER), 1107 android.Manifest.permission.MODIFY_PHONE_STATE); 1108 callback.waitForRadioStateIntent(TelephonyManager.RADIO_POWER_ON); 1109 } 1110 1111 protected class UwbAdapterStateCallback implements UwbManager.AdapterStateCallback { 1112 private final Semaphore mUwbSemaphore = new Semaphore(0); 1113 private final Object mUwbExpectedStateLock = new Object(); 1114 private boolean mUwbExpectedState = false; 1115 toString(int state)1116 public String toString(int state) { 1117 switch (state) { 1118 case UwbManager.AdapterStateCallback.STATE_DISABLED: 1119 return "Disabled"; 1120 1121 case UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE: 1122 return "Inactive"; 1123 1124 case UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE: 1125 return "Active"; 1126 1127 default: 1128 return ""; 1129 } 1130 } 1131 1132 @Override onStateChanged(int state, int reason)1133 public void onStateChanged(int state, int reason) { 1134 logd("UwbAdapterStateCallback onStateChanged() called, state = " + toString(state)); 1135 logd("Adapter state changed reason " + String.valueOf(reason)); 1136 1137 synchronized (mUwbExpectedStateLock) { 1138 if (mUwbExpectedState == mUwbManager.isUwbEnabled()) { 1139 try { 1140 mUwbSemaphore.release(); 1141 } catch (Exception e) { 1142 loge("UwbAdapterStateCallback onStateChanged(): Got exception, ex=" + e); 1143 } 1144 } 1145 } 1146 } 1147 waitUntilOnUwbStateChanged()1148 public boolean waitUntilOnUwbStateChanged() { 1149 synchronized (mUwbExpectedStateLock) { 1150 if (mUwbExpectedState == mUwbManager.isUwbEnabled()) { 1151 return true; 1152 } 1153 } 1154 1155 try { 1156 if (!mUwbSemaphore.tryAcquire(EXTERNAL_DEPENDENT_TIMEOUT, 1157 TimeUnit.MILLISECONDS)) { 1158 loge("UwbAdapterStateCallback Timeout to receive " 1159 + "onStateChanged() callback"); 1160 return false; 1161 } 1162 } catch (Exception ex) { 1163 loge("UwbAdapterStateCallback waitUntilOnUwbStateChanged: Got exception=" + ex); 1164 return false; 1165 } 1166 return true; 1167 } 1168 setUwbExpectedState(boolean expectedState)1169 public void setUwbExpectedState(boolean expectedState) { 1170 synchronized (mUwbExpectedStateLock) { 1171 mUwbExpectedState = expectedState; 1172 mUwbSemaphore.drainPermits(); 1173 } 1174 } 1175 } 1176 1177 protected class BTWifiNFCStateReceiver extends BroadcastReceiver { 1178 private final Semaphore mBTSemaphore = new Semaphore(0); 1179 private final Object mBTExpectedStateLock = new Object(); 1180 private boolean mBTExpectedState = false; 1181 1182 private final Semaphore mNfcSemaphore = new Semaphore(0); 1183 private final Object mNfcExpectedStateLock = new Object(); 1184 private boolean mNfcExpectedState = false; 1185 1186 private final Semaphore mWifiSemaphore = new Semaphore(0); 1187 private final Object mWifiExpectedStateLock = new Object(); 1188 private boolean mWifiExpectedState = false; 1189 1190 @Override onReceive(Context context, Intent intent)1191 public void onReceive(Context context, Intent intent) { 1192 final String action = intent.getAction(); 1193 if (action == null) { 1194 logd("BTWifiNFCStateReceiver NULL action for intent " + intent); 1195 return; 1196 } 1197 logd("BTWifiNFCStateReceiver onReceive: action = " + action); 1198 1199 switch (action) { 1200 case BluetoothAdapter.ACTION_STATE_CHANGED: 1201 int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 1202 BluetoothAdapter.ERROR); 1203 logd("Bluetooth state updated to " + btState); 1204 1205 synchronized (mBTExpectedStateLock) { 1206 if (mBTExpectedState == mBluetoothAdapter.isEnabled()) { 1207 try { 1208 mBTSemaphore.release(); 1209 } catch (Exception e) { 1210 loge("BTWifiNFCStateReceiver onReceive(): Got exception, ex=" + e); 1211 } 1212 } 1213 } 1214 break; 1215 1216 case NfcAdapter.ACTION_ADAPTER_STATE_CHANGED: 1217 int nfcState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1); 1218 logd("Nfc state updated to " + nfcState); 1219 1220 synchronized (mNfcExpectedStateLock) { 1221 if (mNfcExpectedState == mNfcAdapter.isEnabled()) { 1222 try { 1223 mNfcSemaphore.release(); 1224 } catch (Exception e) { 1225 loge("BTWifiNFCStateReceiver onReceive(): Got exception, ex=" + e); 1226 } 1227 } 1228 } 1229 break; 1230 1231 case WifiManager.WIFI_STATE_CHANGED_ACTION: 1232 int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 1233 WifiManager.WIFI_STATE_UNKNOWN); 1234 logd("Wifi state updated to " + wifiState); 1235 1236 synchronized (mWifiExpectedStateLock) { 1237 if (mWifiExpectedState == mWifiManager.isWifiEnabled()) { 1238 try { 1239 mWifiSemaphore.release(); 1240 } catch (Exception e) { 1241 loge("BTWifiNFCStateReceiver onReceive(): Got exception, ex=" + e); 1242 } 1243 } 1244 } 1245 break; 1246 default: 1247 break; 1248 } 1249 } 1250 waitUntilOnBTStateChanged()1251 public boolean waitUntilOnBTStateChanged() { 1252 logd("waitUntilOnBTStateChanged"); 1253 synchronized (mBTExpectedStateLock) { 1254 if (mBTExpectedState == mBluetoothAdapter.isEnabled()) { 1255 return true; 1256 } 1257 } 1258 1259 try { 1260 if (!mBTSemaphore.tryAcquire(EXTERNAL_DEPENDENT_TIMEOUT, 1261 TimeUnit.MILLISECONDS)) { 1262 loge("BTWifiNFCStateReceiver waitUntilOnBTStateChanged: " 1263 + "Timeout to receive onStateChanged() callback"); 1264 return false; 1265 } 1266 } catch (Exception ex) { 1267 loge("BTWifiNFCStateReceiver waitUntilOnBTStateChanged: Got exception=" + ex); 1268 return false; 1269 } 1270 return true; 1271 } 1272 waitUntilOnNfcStateChanged()1273 public boolean waitUntilOnNfcStateChanged() { 1274 synchronized (mNfcExpectedStateLock) { 1275 if (mNfcExpectedState == mNfcAdapter.isEnabled()) { 1276 return true; 1277 } 1278 } 1279 1280 try { 1281 if (!mNfcSemaphore.tryAcquire(EXTERNAL_DEPENDENT_TIMEOUT, 1282 TimeUnit.MILLISECONDS)) { 1283 loge("BTWifiNFCStateReceiver waitUntilOnNfcStateChanged: " 1284 + "Timeout to receive onStateChanged() callback"); 1285 return false; 1286 } 1287 } catch (Exception ex) { 1288 loge("BTWifiNFCStateReceiver waitUntilOnNfcStateChanged: Got exception=" + ex); 1289 return false; 1290 } 1291 return true; 1292 } 1293 waitUntilOnWifiStateChanged()1294 public boolean waitUntilOnWifiStateChanged() { 1295 synchronized (mWifiExpectedStateLock) { 1296 if (mWifiExpectedState == mWifiManager.isWifiEnabled()) { 1297 return true; 1298 } 1299 } 1300 1301 try { 1302 if (!mWifiSemaphore.tryAcquire(EXTERNAL_DEPENDENT_TIMEOUT, 1303 TimeUnit.MILLISECONDS)) { 1304 loge("BTWifiNFCStateReceiver waitUntilOnWifiStateChanged: " 1305 + "Timeout to receive onStateChanged() callback"); 1306 return false; 1307 } 1308 } catch (Exception ex) { 1309 loge("BTWifiNFCStateReceiver waitUntilOnWifiStateChanged: Got exception=" + ex); 1310 return false; 1311 } 1312 return true; 1313 } 1314 setBTExpectedState(boolean expectedState)1315 public void setBTExpectedState(boolean expectedState) { 1316 synchronized (mBTExpectedStateLock) { 1317 mBTExpectedState = expectedState; 1318 mBTSemaphore.drainPermits(); 1319 } 1320 } 1321 setWifiExpectedState(boolean expectedState)1322 public void setWifiExpectedState(boolean expectedState) { 1323 synchronized (mWifiExpectedStateLock) { 1324 mWifiExpectedState = expectedState; 1325 mWifiSemaphore.drainPermits(); 1326 } 1327 } 1328 setNfcExpectedState(boolean expectedState)1329 public void setNfcExpectedState(boolean expectedState) { 1330 synchronized (mNfcExpectedStateLock) { 1331 mNfcExpectedState = expectedState; 1332 mNfcSemaphore.drainPermits(); 1333 } 1334 } 1335 } 1336 logd(@onNull String log)1337 protected static void logd(@NonNull String log) { 1338 Rlog.d(TAG, log); 1339 } 1340 loge(@onNull String log)1341 protected static void loge(@NonNull String log) { 1342 Rlog.e(TAG, log); 1343 } 1344 assertSatelliteEnabledInSettings(boolean enabled)1345 protected static void assertSatelliteEnabledInSettings(boolean enabled) { 1346 int satelliteModeEnabled = Settings.Global.getInt(getContext().getContentResolver(), 1347 Settings.Global.SATELLITE_MODE_ENABLED, 0); 1348 if (enabled) { 1349 assertEquals(satelliteModeEnabled, 1); 1350 } else { 1351 assertEquals(satelliteModeEnabled, 0); 1352 } 1353 logd("requestSatelliteEnabled: " + enabled 1354 + " : satelliteModeEnabled from settings: " + satelliteModeEnabled); 1355 } 1356 waitFor(long timeoutMillis)1357 protected static void waitFor(long timeoutMillis) { 1358 Object delayTimeout = new Object(); 1359 synchronized (delayTimeout) { 1360 try { 1361 delayTimeout.wait(timeoutMillis); 1362 } catch (InterruptedException ex) { 1363 // Ignore the exception 1364 logd("waitFor: delayTimeout ex=" + ex); 1365 } 1366 } 1367 } 1368 1369 // Get default active subscription ID. getActiveSubIDForCarrierSatelliteTest()1370 protected int getActiveSubIDForCarrierSatelliteTest() { 1371 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 1372 SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 1373 List<SubscriptionInfo> infos = ShellIdentityUtils.invokeMethodWithShellPermissions(sm, 1374 SubscriptionManager::getActiveSubscriptionInfoList); 1375 1376 int defaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId(); 1377 if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 1378 && isSubIdInInfoList(infos, defaultSubId)) { 1379 return defaultSubId; 1380 } 1381 1382 defaultSubId = SubscriptionManager.getDefaultSubscriptionId(); 1383 if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 1384 && isSubIdInInfoList(infos, defaultSubId)) { 1385 return defaultSubId; 1386 } 1387 1388 // Couldn't resolve a default. We can try to resolve a default using the active 1389 // subscriptions. 1390 if (!infos.isEmpty()) { 1391 return infos.get(0).getSubscriptionId(); 1392 } 1393 // There must be at least one active subscription. 1394 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1395 } 1396 isSubIdInInfoList(List<SubscriptionInfo> infos, int subId)1397 private static boolean isSubIdInInfoList(List<SubscriptionInfo> infos, int subId) { 1398 return infos.stream().anyMatch(info -> info.getSubscriptionId() == subId); 1399 } 1400 } 1401