Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dae4bc50 authored by Pranav Madapurmath's avatar Pranav Madapurmath Committed by Android (Google) Code Review
Browse files

Merge "Use communication device callback and fix reinitialization routing" into main

parents 8398bb2b 410f0107
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -107,3 +107,14 @@ flag {
    purpose: PURPOSE_BUGFIX
  }
}

# OWNER=pmadapurmath TARGET=25Q1
flag {
  name: "new_audio_path_speaker_broadcast_and_unfocused_routing"
  namespace: "telecom"
  description: "Replace the speaker broadcasts with the communication device changed listener and resolve baseline routing issues when a call ends."
  bug: "353419513"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+2 −1
Original line number Diff line number Diff line
@@ -318,7 +318,8 @@ public class AudioRoute {
    // sending SPEAKER_OFF, or disconnecting SCO).
    void onOrigRouteAsPendingRoute(boolean active, PendingAudioRoute pendingAudioRoute,
            AudioManager audioManager, BluetoothRouteManager bluetoothRouteManager) {
        Log.i(this, "onOrigRouteAsPendingRoute: active (%b), type (%d)", active, mAudioRouteType);
        Log.i(this, "onOrigRouteAsPendingRoute: active (%b), type (%s)", active,
                DEVICE_TYPE_STRINGS.get(mAudioRouteType));
        if (active) {
            int result = clearCommunicationDevice(pendingAudioRoute, bluetoothRouteManager,
                    audioManager);
+46 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.telecom;

import static com.android.server.telecom.AudioRoute.BT_AUDIO_ROUTE_TYPES;
import static com.android.server.telecom.AudioRoute.DEVICE_INFO_TYPE_TO_AUDIO_ROUTE_TYPE;
import static com.android.server.telecom.AudioRoute.TYPE_INVALID;
import static com.android.server.telecom.AudioRoute.TYPE_SPEAKER;

@@ -63,6 +64,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CallAudioRouteController implements CallAudioRouteAdapter {
    private static final AudioRoute DUMMY_ROUTE = new AudioRoute(TYPE_INVALID, null, null);
@@ -107,6 +110,8 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
    private PendingAudioRoute mPendingAudioRoute;
    private AudioRoute.Factory mAudioRouteFactory;
    private StatusBarNotifier mStatusBarNotifier;
    private AudioManager.OnCommunicationDeviceChangedListener mCommunicationDeviceListener;
    private ExecutorService mCommunicationDeviceChangedExecutor;
    private FeatureFlags mFeatureFlags;
    private int mFocusType;
    private int mCallSupportedRouteMask = -1;
@@ -200,10 +205,12 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        handlerThread.start();

        // Register broadcast receivers
        if (!mFeatureFlags.newAudioPathSpeakerBroadcastAndUnfocusedRouting()) {
            IntentFilter speakerChangedFilter = new IntentFilter(
                    AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED);
            speakerChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
            context.registerReceiver(mSpeakerPhoneChangeReceiver, speakerChangedFilter);
        }

        IntentFilter micMuteChangedFilter = new IntentFilter(
                AudioManager.ACTION_MICROPHONE_MUTE_CHANGED);
@@ -214,6 +221,31 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        muteChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        context.registerReceiver(mMuteChangeReceiver, muteChangedFilter);

        // Register AudioManager#onCommunicationDeviceChangedListener listener to receive updates
        // to communication device (via AudioManager#setCommunicationDevice). This is a replacement
        // to using broadcasts in the hopes of improving performance.
        mCommunicationDeviceChangedExecutor = Executors.newSingleThreadExecutor();
        mCommunicationDeviceListener = new AudioManager.OnCommunicationDeviceChangedListener() {
            @Override
            public void onCommunicationDeviceChanged(AudioDeviceInfo device) {
                @AudioRoute.AudioRouteType int audioType = device != null
                        ? DEVICE_INFO_TYPE_TO_AUDIO_ROUTE_TYPE.get(device.getType())
                        : TYPE_INVALID;
                Log.i(this, "onCommunicationDeviceChanged: %d", audioType);
                if (device != null && device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
                    sendMessageWithSessionInfo(SPEAKER_ON);
                } else if (mPendingAudioRoute != null && mPendingAudioRoute.getOrigRoute() != null
                        && mPendingAudioRoute.getOrigRoute().getType() == AudioRoute.TYPE_SPEAKER) {
                    sendMessageWithSessionInfo(SPEAKER_OFF);
                }
            }
        };
        if (mFeatureFlags.newAudioPathSpeakerBroadcastAndUnfocusedRouting()) {
            mAudioManager.addOnCommunicationDeviceChangedListener(
                    mCommunicationDeviceChangedExecutor,
                    mCommunicationDeviceListener);
        }

        // Create handler
        mHandler = new Handler(handlerThread.getLooper()) {
            @Override
@@ -798,11 +830,11 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        boolean currentRouteNeedsUpdate = mCurrentRoute.getType() == type;
        if (mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
            if (pendingRouteNeedsUpdate) {
                pendingRouteNeedsUpdate &= mPendingAudioRoute.getDestRoute().getBluetoothAddress()
                pendingRouteNeedsUpdate = mPendingAudioRoute.getDestRoute().getBluetoothAddress()
                        .equals(previouslyActiveDeviceAddress);
            }
            if (currentRouteNeedsUpdate) {
                currentRouteNeedsUpdate &= mCurrentRoute.getBluetoothAddress()
                currentRouteNeedsUpdate = mCurrentRoute.getBluetoothAddress()
                        .equals(previouslyActiveDeviceAddress);
            }
        }
@@ -852,8 +884,13 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {

                    // Reset mute state after call ends.
                    handleMuteChanged(false);
                    // Route back to inactive route.
                    routeTo(false, mCurrentRoute);
                    // Ensure we reset call audio state at the end of the call (i.e. if we're on
                    // speaker, route back to earpiece). If we're on BT, remain on BT if it's still
                    // connected.
                    AudioRoute route = mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()
                            ? calculateBaselineRoute(true, null)
                            : mCurrentRoute;
                    routeTo(false, route);
                    // Clear pending messages
                    mPendingAudioRoute.clearPendingMessages();
                    clearRingingBluetoothAddress();
@@ -1173,7 +1210,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        }

        // Get corresponding audio route
        @AudioRoute.AudioRouteType int type = AudioRoute.DEVICE_INFO_TYPE_TO_AUDIO_ROUTE_TYPE.get(
        @AudioRoute.AudioRouteType int type = DEVICE_INFO_TYPE_TO_AUDIO_ROUTE_TYPE.get(
                deviceAttr.getType());
        if (BT_AUDIO_ROUTE_TYPES.contains(type)) {
            return getBluetoothRoute(type, deviceAttr.getAddress());
+27 −0
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
        when(mFeatureFlags.ignoreAutoRouteToWatchDevice()).thenReturn(false);
        when(mFeatureFlags.useRefactoredAudioRouteSwitching()).thenReturn(true);
        when(mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()).thenReturn(false);
        when(mFeatureFlags.newAudioPathSpeakerBroadcastAndUnfocusedRouting()).thenReturn(false);
    }

    @After
@@ -1031,6 +1032,32 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
        BLUETOOTH_DEVICES.remove(scoDevice);
    }

    @Test
    @SmallTest
    public void verifyRouteReinitializedAfterCallEnd() {
        when(mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()).thenReturn(true);
        mController.initialize();
        mController.setActive(true);

        // Switch to speaker
        mController.sendMessageWithSessionInfo(SPEAKER_ON);
        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));

        // Verify that call audio route is reinitialized to default (in this case, earpiece) when
        // call audio focus is lost.
        mController.sendMessageWithSessionInfo(SWITCH_FOCUS, NO_FOCUS, 0);
        mController.sendMessageWithSessionInfo(SPEAKER_OFF);
        expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));
    }

    private void verifyConnectBluetoothDevice(int audioType) {
        mController.initialize();
        mController.setActive(true);