Merge "Resolve flaky audio routing CUJ tests" into main
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 97129be..29e67bb 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -65,6 +65,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -120,6 +121,8 @@
private boolean mAvailableRoutesUpdated;
private final Object mLock = new Object();
private final TelecomSystem.SyncRoot mTelecomLock;
+ private CountDownLatch mAudioOperationsCompleteLatch;
+ private CountDownLatch mAudioActiveCompleteLatch;
private final BroadcastReceiver mSpeakerPhoneChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -442,6 +445,12 @@
} else {
mCurrentRoute = DUMMY_ROUTE;
}
+ // Audio ops will only ever be completed if there's a call placed and it gains
+ // ACTIVE/RINGING focus, hence why the initial value is 0.
+ mAudioOperationsCompleteLatch = new CountDownLatch(0);
+ // This latch will be count down when ACTIVE/RINGING focus is gained. This is determined
+ // when the routing goes active.
+ mAudioActiveCompleteLatch = new CountDownLatch(1);
mIsActive = false;
mCallAudioState = new CallAudioState(mIsMute, ROUTE_MAP.get(mCurrentRoute.getType()),
supportMask, null, new HashSet<>());
@@ -1127,6 +1136,21 @@
mIsPending = false;
mPendingAudioRoute.clearPendingMessages();
onCurrentRouteChanged();
+ if (mIsActive) {
+ // Reinitialize the audio ops complete latch since the routing went active. We
+ // should always expect operations to complete after this point.
+ if (mAudioOperationsCompleteLatch.getCount() == 0) {
+ mAudioOperationsCompleteLatch = new CountDownLatch(1);
+ }
+ mAudioActiveCompleteLatch.countDown();
+ } else {
+ // Reinitialize the active routing latch when audio ops are complete so that it can
+ // once again be processed when a new call is placed/received.
+ if (mAudioActiveCompleteLatch.getCount() == 0) {
+ mAudioActiveCompleteLatch = new CountDownLatch(1);
+ }
+ mAudioOperationsCompleteLatch.countDown();
+ }
if (mFeatureFlags.telecomMetricsSupport()) {
mMetricsController.getAudioRouteStats().onRouteExit(mPendingAudioRoute, true);
}
@@ -1659,4 +1683,12 @@
sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE,
btAddressToExclude);
}
+
+ public CountDownLatch getAudioOperationsCompleteLatch() {
+ return mAudioOperationsCompleteLatch;
+ }
+
+ public CountDownLatch getAudioActiveCompleteLatch() {
+ return mAudioActiveCompleteLatch;
+ }
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index a8ddf86..39cd379 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -379,6 +379,7 @@
Analytics.THIRD_PARTY_PHONE);
}
+ private static final long WAIT_FOR_AUDIO_UPDATE_TIMEOUT = 4000L;
/**
* The main call repository. Keeps an instance of all live calls. New incoming and outgoing
* calls are added to the map and removed when the calls move to the disconnected state.
@@ -513,6 +514,7 @@
private final IncomingCallFilterGraphProvider mIncomingCallFilterGraphProvider;
private final CallAudioWatchdog mCallAudioWatchDog;
+ private final CallAudioRouteAdapter mCallAudioRouteAdapter;
private final ConnectionServiceFocusManager.CallsManagerRequester mRequester =
new ConnectionServiceFocusManager.CallsManagerRequester() {
@@ -691,12 +693,11 @@
mDtmfLocalTonePlayer =
new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy());
- CallAudioRouteAdapter callAudioRouteAdapter;
// TODO: add another flag check when
// bluetoothDeviceManager.getBluetoothHeadset().isScoManagedByAudio()
// available and return true
if (!featureFlags.useRefactoredAudioRouteSwitching()) {
- callAudioRouteAdapter = callAudioRouteStateMachineFactory.create(
+ mCallAudioRouteAdapter = callAudioRouteStateMachineFactory.create(
context,
this,
bluetoothManager,
@@ -709,17 +710,17 @@
featureFlags
);
} else {
- callAudioRouteAdapter = new CallAudioRouteController(context, this, audioServiceFactory,
- new AudioRoute.Factory(), wiredHeadsetManager, mBluetoothRouteManager,
- statusBarNotifier, featureFlags, metricsController);
+ mCallAudioRouteAdapter = new CallAudioRouteController(context, this,
+ audioServiceFactory, new AudioRoute.Factory(), wiredHeadsetManager,
+ mBluetoothRouteManager, statusBarNotifier, featureFlags, metricsController);
}
- callAudioRouteAdapter.initialize();
- bluetoothStateReceiver.setCallAudioRouteAdapter(callAudioRouteAdapter);
- bluetoothDeviceManager.setCallAudioRouteAdapter(callAudioRouteAdapter);
+ mCallAudioRouteAdapter.initialize();
+ bluetoothStateReceiver.setCallAudioRouteAdapter(mCallAudioRouteAdapter);
+ bluetoothDeviceManager.setCallAudioRouteAdapter(mCallAudioRouteAdapter);
CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter =
new CallAudioRoutePeripheralAdapter(
- callAudioRouteAdapter,
+ mCallAudioRouteAdapter,
bluetoothManager,
wiredHeadsetManager,
mDockManager,
@@ -755,7 +756,7 @@
mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager,
mTimeoutsAdapter, mLock);
}
- mCallAudioManager = new CallAudioManager(callAudioRouteAdapter,
+ mCallAudioManager = new CallAudioManager(mCallAudioRouteAdapter,
this, callAudioModeStateMachineFactory.create(systemStateHelper,
(AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE),
featureFlags, communicationDeviceTracker),
@@ -7121,4 +7122,23 @@
public CallsManagerCallSequencingAdapter getCallSequencingAdapter() {
return mCallSequencingAdapter;
}
+
+ public void waitForAudioToUpdate(boolean expectActive) {
+ Log.i(this, "waitForAudioToUpdate");
+ if (mFeatureFlags.useRefactoredAudioRouteSwitching()) {
+ try {
+ CallAudioRouteController audioRouteController =
+ (CallAudioRouteController) mCallAudioRouteAdapter;
+ if (expectActive) {
+ audioRouteController.getAudioActiveCompleteLatch().await(
+ WAIT_FOR_AUDIO_UPDATE_TIMEOUT, TimeUnit.MILLISECONDS);
+ } else {
+ audioRouteController.getAudioOperationsCompleteLatch().await(
+ WAIT_FOR_AUDIO_UPDATE_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ } catch (InterruptedException e) {
+ Log.w(this, e.toString());
+ }
+ }
+ }
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 72cb297..ef8210d 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -2952,6 +2952,10 @@
}
}
+ @Override
+ public void waitForAudioToUpdate(boolean expectActive) {
+ mCallsManager.waitForAudioToUpdate(expectActive);
+ }
/**
* Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
* calls for a given {@code packageName} and {@code userHandle}.
diff --git a/src/com/android/server/telecom/TelecomShellCommand.java b/src/com/android/server/telecom/TelecomShellCommand.java
index e840b2a..2e955a9 100644
--- a/src/com/android/server/telecom/TelecomShellCommand.java
+++ b/src/com/android/server/telecom/TelecomShellCommand.java
@@ -67,6 +67,10 @@
private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode";
private static final String COMMAND_IS_NON_IN_CALL_SERVICE_BOUND =
"is-non-ui-in-call-service-bound";
+ private static final String COMMAND_WAIT_FOR_AUDIO_OPS_COMPLETION =
+ "wait-for-audio-ops-complete";
+ private static final String COMMAND_WAIT_FOR_AUDIO_ACTIVE_COMPLETION =
+ "wait-for-audio-active";
/**
* Change the system dialer package name if a package name was specified,
@@ -192,6 +196,12 @@
case COMMAND_SET_METRICS_TEST_DISABLED:
mTelecomService.setMetricsTestMode(false);
break;
+ case COMMAND_WAIT_FOR_AUDIO_OPS_COMPLETION:
+ mTelecomService.waitForAudioToUpdate(false);
+ break;
+ case COMMAND_WAIT_FOR_AUDIO_ACTIVE_COMPLETION:
+ mTelecomService.waitForAudioToUpdate(true);
+ break;
default:
return handleDefaultCommands(command);
}