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

Commit 96a0be67 authored by Christine Hallstrom's avatar Christine Hallstrom
Browse files

Handle audio route restrictions set on calls

When a call restricts audio routes, it will move the audio route to a
supported route if available. The supported routes are determined initially
and re-evaluated when the call becomes the foreground call.

This is a cherry-pick of abandoned ag/1520954

Bug: 32958838
Change-Id: Ie30847c995839516507df0c70178a591c39f6cdd
parent d1d23ce4
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.Trace;
import android.provider.ContactsContract.Contacts;
import android.telecom.CallAudioState;
import android.telecom.Conference;
import android.telecom.DisconnectCause;
import android.telecom.Connection;
@@ -319,6 +320,8 @@ public class Call implements CreateConnectionResponse {

    private int mConnectionProperties;

    private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;

    private boolean mIsConference = false;

    private final boolean mShouldAttachToExistingConnection;
@@ -1075,6 +1078,16 @@ public class Call implements CreateConnectionResponse {
        }
    }

    int getSupportedAudioRoutes() {
        return mSupportedAudioRoutes;
    }

    void setSupportedAudioRoutes(int audioRoutes) {
        if (mSupportedAudioRoutes != audioRoutes) {
            mSupportedAudioRoutes = audioRoutes;
        }
    }

    @VisibleForTesting
    public Call getParentCall() {
        return mParentCall;
@@ -1199,6 +1212,7 @@ public class Call implements CreateConnectionResponse {

        setConnectionCapabilities(connection.getConnectionCapabilities());
        setConnectionProperties(connection.getConnectionProperties());
        setSupportedAudioRoutes(connection.getSupportedAudioRoutes());
        setVideoProvider(connection.getVideoProvider());
        setVideoState(connection.getVideoState());
        setRingbackRequested(connection.isRingbackRequested());
+66 −13
Original line number Diff line number Diff line
@@ -205,6 +205,16 @@ public class CallAudioRouteStateMachine extends StateMachine {
        Log.endSession();
    }

    private int getCurrentCallSupportedRoutes() {
        int supportedRoutes = CallAudioState.ROUTE_ALL;

        if (mCallsManager.getForegroundCall() != null) {
            supportedRoutes &= mCallsManager.getForegroundCall().getSupportedAudioRoutes();
        }

        return supportedRoutes;
    }

    abstract class AudioState extends State {
        @Override
        public void enter() {
@@ -222,31 +232,34 @@ public class CallAudioRouteStateMachine extends StateMachine {

        @Override
        public boolean processMessage(Message msg) {
            int addedRoutes = 0;
            int removedRoutes = 0;

            switch (msg.what) {
                case CONNECT_WIRED_HEADSET:
                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
                            "Wired headset connected");
                    mAvailableRoutes &= ~ROUTE_EARPIECE;
                    mAvailableRoutes |= ROUTE_WIRED_HEADSET;
                    return NOT_HANDLED;
                    removedRoutes |= ROUTE_EARPIECE;
                    addedRoutes |= ROUTE_WIRED_HEADSET;
                    break;
                case CONNECT_BLUETOOTH:
                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
                            "Bluetooth connected");
                    mAvailableRoutes |= ROUTE_BLUETOOTH;
                    return NOT_HANDLED;
                    addedRoutes |= ROUTE_BLUETOOTH;
                    break;
                case DISCONNECT_WIRED_HEADSET:
                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
                            "Wired headset disconnected");
                    mAvailableRoutes &= ~ROUTE_WIRED_HEADSET;
                    removedRoutes |= ROUTE_WIRED_HEADSET;
                    if (mDoesDeviceSupportEarpieceRoute) {
                        mAvailableRoutes |= ROUTE_EARPIECE;
                        addedRoutes |= ROUTE_EARPIECE;
                    }
                    return NOT_HANDLED;
                    break;
                case DISCONNECT_BLUETOOTH:
                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,
                            "Bluetooth disconnected");
                    mAvailableRoutes &= ~ROUTE_BLUETOOTH;
                    return NOT_HANDLED;
                    removedRoutes |= ROUTE_BLUETOOTH;
                    break;
                case SWITCH_BASELINE_ROUTE:
                    sendInternalMessage(calculateBaselineRouteMessage(false));
                    return HANDLED;
@@ -259,6 +272,14 @@ public class CallAudioRouteStateMachine extends StateMachine {
                default:
                    return NOT_HANDLED;
            }

            if (addedRoutes != 0 || removedRoutes != 0) {
                mAvailableRoutes = modifyRoutes(mAvailableRoutes, removedRoutes, addedRoutes, true);
                mDeviceSupportedRoutes = modifyRoutes(mDeviceSupportedRoutes, removedRoutes,
                        addedRoutes, false);
            }

            return NOT_HANDLED;
        }

        // Behavior will depend on whether the state is an active one or a quiescent one.
@@ -266,6 +287,18 @@ public class CallAudioRouteStateMachine extends StateMachine {
        abstract public boolean isActive();
    }

    private int modifyRoutes(int base, int remove, int add, boolean considerCurrentCall) {
        base &= ~remove;

        if (considerCurrentCall) {
            add &= getCurrentCallSupportedRoutes();
        }

        base |= add;

        return base;
    }

    class ActiveEarpieceRoute extends EarpieceRoute {
        @Override
        public String getName() {
@@ -1112,6 +1145,7 @@ public class CallAudioRouteStateMachine extends StateMachine {
     * A few pieces of hidden state. Used to avoid exponential explosion of number of explicit
     * states
     */
    private int mDeviceSupportedRoutes;
    private int mAvailableRoutes;
    private int mAudioFocusType;
    private boolean mWasOnSpeaker;
@@ -1201,9 +1235,15 @@ public class CallAudioRouteStateMachine extends StateMachine {
    }

    public void initialize(CallAudioState initState) {
        if ((initState.getRoute() & getCurrentCallSupportedRoutes()) == 0) {
            Log.e(this, new IllegalArgumentException(), "Route " + initState.getRoute()
                    + "specified when supported call routes are:" + getCurrentCallSupportedRoutes());
        }

        mCurrentCallAudioState = initState;
        mLastKnownCallAudioState = initState;
        mAvailableRoutes = initState.getSupportedRouteMask();
        mDeviceSupportedRoutes = initState.getSupportedRouteMask();
        mAvailableRoutes = mDeviceSupportedRoutes;
        mIsMuted = initState.isMuted();
        mWasOnSpeaker = false;

@@ -1261,6 +1301,7 @@ public class CallAudioRouteStateMachine extends StateMachine {
                }
                return;
            case UPDATE_SYSTEM_AUDIO_ROUTE:
                updateRouteForForegroundCall();
                resendSystemAudioState();
                return;
            case RUN_RUNNABLE:
@@ -1458,7 +1499,7 @@ public class CallAudioRouteStateMachine extends StateMachine {
    }

    private CallAudioState getInitialAudioState() {
        int supportedRouteMask = calculateSupportedRoutes();
        int supportedRouteMask = calculateSupportedRoutes() & getCurrentCallSupportedRoutes();
        final int route;

        if ((supportedRouteMask & ROUTE_BLUETOOTH) != 0) {
@@ -1523,7 +1564,8 @@ public class CallAudioRouteStateMachine extends StateMachine {

    private void reinitialize() {
        CallAudioState initState = getInitialAudioState();
        mAvailableRoutes = initState.getSupportedRouteMask();
        mDeviceSupportedRoutes = initState.getSupportedRouteMask();
        mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();
        mIsMuted = initState.isMuted();
        setMuteOn(mIsMuted);
        mWasOnSpeaker = false;
@@ -1531,4 +1573,15 @@ public class CallAudioRouteStateMachine extends StateMachine {
        mLastKnownCallAudioState = initState;
        transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute()));
    }

    private void updateRouteForForegroundCall() {
        mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();

        CallAudioState currentState = getCurrentCallAudioState();

        // Move to baseline route in the case the current route is no longer available.
        if ((mAvailableRoutes & currentState.getRoute()) == 0) {
            sendInternalMessage(calculateBaselineRouteMessage(false));
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ public class ParcelableCallUtils {
        }
        int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
        int properties = convertConnectionToCallProperties(call.getConnectionProperties());
        int supportedAudioRoutes = call.getSupportedAudioRoutes();

        if (call.isConference()) {
            properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
        }
@@ -157,6 +159,7 @@ public class ParcelableCallUtils {
                call.getCannedSmsResponses(),
                capabilities,
                properties,
                supportedAudioRoutes,
                connectTimeMillis,
                handle,
                call.getHandlePresentation(),
+14 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telecom.CallAudioState;
import android.telecom.ConnectionService;
import android.telecom.DefaultDialerManager;
import android.telecom.PhoneAccount;
@@ -1507,6 +1508,7 @@ public class PhoneAccountRegistrar {
        private static final String ADDRESS = "handle";
        private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
        private static final String CAPABILITIES = "capabilities";
        private static final String SUPPORTED_AUDIO_ROUTES = "supported_audio_routes";
        private static final String ICON_RES_ID = "icon_res_id";
        private static final String ICON_PACKAGE_NAME = "icon_package_name";
        private static final String ICON_BITMAP = "icon_bitmap";
@@ -1542,6 +1544,8 @@ public class PhoneAccountRegistrar {
                writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
                writeBundle(EXTRAS, o.getExtras(), serializer);
                writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
                writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString(
                        o.getSupportedAudioRoutes()), serializer);

                serializer.endTag(null, CLASS_PHONE_ACCOUNT);
            }
@@ -1555,6 +1559,7 @@ public class PhoneAccountRegistrar {
                Uri address = null;
                Uri subscriptionAddress = null;
                int capabilities = 0;
                int supportedAudioRoutes = 0;
                int iconResId = PhoneAccount.NO_RESOURCE_ID;
                String iconPackageName = null;
                Bitmap iconBitmap = null;
@@ -1613,6 +1618,9 @@ public class PhoneAccountRegistrar {
                        enabled = "true".equalsIgnoreCase(parser.getText());
                    } else if (parser.getName().equals(EXTRAS)) {
                        extras = readBundle(parser);
                    } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) {
                        parser.next();
                        supportedAudioRoutes = Integer.parseInt(parser.getText());
                    }
                }

@@ -1671,10 +1679,16 @@ public class PhoneAccountRegistrar {
                    }
                }

                if (version < 9) {
                    // Set supported audio routes to all by default
                    supportedAudioRoutes = CallAudioState.ROUTE_ALL;
                }

                PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
                        .setAddress(address)
                        .setSubscriptionAddress(subscriptionAddress)
                        .setCapabilities(capabilities)
                        .setSupportedAudioRoutes(supportedAudioRoutes)
                        .setShortDescription(shortDescription)
                        .setSupportedUriSchemes(supportedUriSchemes)
                        .setHighlightColor(highlightColor)
+2 −0
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ public class ConnectionServiceFixture implements TestFixture<IConnectionService>
        int addressPresentation;
        int capabilities;
        int properties;
        int supportedAudioRoutes;
        StatusHints statusHints;
        DisconnectCause disconnectCause;
        String conferenceId;
@@ -594,6 +595,7 @@ public class ConnectionServiceFixture implements TestFixture<IConnectionService>
                c.state,
                c.capabilities,
                c.properties,
                c.supportedAudioRoutes,
                c.request.getAddress(),
                c.addressPresentation,
                c.callerDisplayName,