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

Commit e0fad4a0 authored by Rahul Sabnis's avatar Rahul Sabnis
Browse files

Make BluetoothHeadset APIs used by Telecom into System APIs and update

service code to match.

Tag: #feature
Bug: 195156304
Test: Manual
Merged-In: I8af246091ae49c8f9cf34c1f4a894b3a66a28cf8
Change-Id: I8af246091ae49c8f9cf34c1f4a894b3a66a28cf8
parent e976dc12
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -102,7 +102,6 @@ import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService;
import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService;
@@ -3331,10 +3330,10 @@ public class AdapterService extends Service {
            HashSet<Class> leAudioUnicastProfiles = Config.geLeAudioUnicastProfiles();

            if (supportedProfileServices.containsAll(leAudioUnicastProfiles)) {
                return BluetoothStatusCodes.SUCCESS;
                return BluetoothStatusCodes.FEATURE_SUPPORTED;
            }

            return BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED;
            return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
        }

        @Override
@@ -3352,10 +3351,10 @@ public class AdapterService extends Service {
            }

            if (service.isLeAudioBroadcastSourceSupported()) {
                return BluetoothStatusCodes.SUCCESS;
                return BluetoothStatusCodes.FEATURE_SUPPORTED;
            }

            return BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED;
            return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
        }

        @Override
@@ -3373,10 +3372,10 @@ public class AdapterService extends Service {
            }

            if (service.isLeAudioBroadcastAssistantSupported()) {
                return BluetoothStatusCodes.SUCCESS;
                return BluetoothStatusCodes.FEATURE_SUPPORTED;
            }

            return BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED;
            return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
        }

        @Override
+12 −7
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.bluetooth.hfp;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothManager;
@@ -73,7 +72,12 @@ public class BluetoothHeadsetProxy {
        return mBluetoothHeadset.getAudioState(device);
    }

    public boolean connectAudio() {
    /**
     * Proxy function that calls {@link BluetoothHeadset#connectAudio()}.
     *
     * @return whether the connection request was successful
     */
    public int connectAudio() {
        return mBluetoothHeadset.connectAudio();
    }

@@ -85,11 +89,12 @@ public class BluetoothHeadsetProxy {
        return mBluetoothHeadset.getActiveDevice();
    }

    public boolean isAudioOn() {
        return mBluetoothHeadset.isAudioOn();
    }

    public boolean disconnectAudio() {
    /**
     * Proxy function that calls {@link BluetoothHeadset#disconnectAudio()}.
     *
     * @return whether the disconnection request was successful
     */
    public int disconnectAudio() {
        return mBluetoothHeadset.disconnectAudio();
    }

+62 −53
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothHeadset;
import android.content.AttributionSource;
@@ -692,6 +693,7 @@ public class HeadsetService extends ProfileService {
                HeadsetService service = getService(source);
                boolean defaultValue = false;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.isAudioConnected(device);
                }
                receiver.send(defaultValue);
@@ -707,6 +709,7 @@ public class HeadsetService extends ProfileService {
                HeadsetService service = getService(source);
                int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.getAudioState(device);
                }
                receiver.send(defaultValue);
@@ -719,8 +722,9 @@ public class HeadsetService extends ProfileService {
        public void connectAudio(AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                HeadsetService service = getService(source);
                boolean defaultValue = false;
                int defaultValue = BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.connectAudio();
                }
                receiver.send(defaultValue);
@@ -733,8 +737,9 @@ public class HeadsetService extends ProfileService {
        public void disconnectAudio(AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                HeadsetService service = getService(source);
                boolean defaultValue = false;
                int defaultValue = BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.disconnectAudio();
                }
                receiver.send(defaultValue);
@@ -893,6 +898,7 @@ public class HeadsetService extends ProfileService {
                HeadsetService service = getService(source);
                boolean defaultValue = false;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.isInbandRingingEnabled();
                }
                receiver.send(defaultValue);
@@ -1133,7 +1139,7 @@ public class HeadsetService extends ProfileService {
            // Audio should not be on when no audio mode is active
            if (isAudioOn()) {
                // Disconnect audio so that API user can try later
                boolean status = disconnectAudio();
                int status = disconnectAudio();
                Log.w(TAG, "startVoiceRecognition: audio is still active, please wait for audio to"
                        + " be disconnected, disconnectAudio() returned " + status
                        + ", active device is " + mActiveDevice);
@@ -1338,8 +1344,10 @@ public class HeadsetService extends ProfileService {
                }
            }
            if (getAudioState(mActiveDevice) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                if (!disconnectAudio(mActiveDevice)) {
                    Log.w(TAG, "removeActiveDevice: disconnectAudio failed on " + mActiveDevice);
                int disconnectStatus = disconnectAudio(mActiveDevice);
                if (disconnectStatus != BluetoothStatusCodes.SUCCESS) {
                    Log.w(TAG, "removeActiveDevice: disconnectAudio failed on " + mActiveDevice
                            + " with status code " + disconnectStatus);
                }
            }
            mActiveDevice = null;
@@ -1377,9 +1385,10 @@ public class HeadsetService extends ProfileService {
            BluetoothDevice previousActiveDevice = mActiveDevice;
            mActiveDevice = device;
            if (getAudioState(previousActiveDevice) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                if (!disconnectAudio(previousActiveDevice)) {
                int disconnectStatus = disconnectAudio(previousActiveDevice);
                if (disconnectStatus != BluetoothStatusCodes.SUCCESS) {
                    Log.e(TAG, "setActiveDevice: fail to disconnectAudio from "
                            + previousActiveDevice);
                            + previousActiveDevice + " with status code " + disconnectStatus);
                    if (previousActiveDevice == null) {
                        removeActiveDevice();
                    } else {
@@ -1391,8 +1400,10 @@ public class HeadsetService extends ProfileService {
                broadcastActiveDevice(mActiveDevice);
            } else if (shouldPersistAudio()) {
                broadcastActiveDevice(mActiveDevice);
                if (!connectAudio(mActiveDevice)) {
                    Log.e(TAG, "setActiveDevice: fail to connectAudio to " + mActiveDevice);
                int connectStatus = connectAudio(mActiveDevice);
                if (connectStatus != BluetoothStatusCodes.SUCCESS) {
                    Log.e(TAG, "setActiveDevice: fail to connectAudio to " + mActiveDevice
                            + " with status code " + connectStatus);
                    if (previousActiveDevice == null) {
                        removeActiveDevice();
                    } else {
@@ -1419,45 +1430,46 @@ public class HeadsetService extends ProfileService {
        }
    }

    boolean connectAudio() {
    int connectAudio() {
        synchronized (mStateMachines) {
            BluetoothDevice device = mActiveDevice;
            if (device == null) {
                Log.w(TAG, "connectAudio: no active device, " + Utils.getUidPidString());
                return false;
                return BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES;
            }
            return connectAudio(device);
        }
    }

    boolean connectAudio(BluetoothDevice device) {
    int connectAudio(BluetoothDevice device) {
        Log.i(TAG, "connectAudio: device=" + device + ", " + Utils.getUidPidString());
        synchronized (mStateMachines) {
            if (!isScoAcceptable(device)) {
                Log.w(TAG, "connectAudio, rejected SCO request to " + device);
                return false;
            }
            final HeadsetStateMachine stateMachine = mStateMachines.get(device);
            if (stateMachine == null) {
                Log.w(TAG, "connectAudio: device " + device + " was never connected/connecting");
                return false;
                return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED;
            }
            int scoConnectionAllowedState = isScoAcceptable(device);
            if (scoConnectionAllowedState != BluetoothStatusCodes.SUCCESS) {
                Log.w(TAG, "connectAudio, rejected SCO request to " + device);
                return scoConnectionAllowedState;
            }
            if (stateMachine.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
                Log.w(TAG, "connectAudio: profile not connected");
                return false;
                return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED;
            }
            if (stateMachine.getAudioState() != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                logD("connectAudio: audio is not idle for device " + device);
                return true;
                return BluetoothStatusCodes.SUCCESS;
            }
            if (isAudioOn()) {
                Log.w(TAG, "connectAudio: audio is not idle, current audio devices are "
                        + Arrays.toString(getNonIdleAudioDevices().toArray()));
                return false;
                return BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED;
            }
            stateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, device);
        }
        return true;
        return BluetoothStatusCodes.SUCCESS;
    }

    private List<BluetoothDevice> getNonIdleAudioDevices() {
@@ -1472,38 +1484,30 @@ public class HeadsetService extends ProfileService {
        return devices;
    }

    boolean disconnectAudio() {
        boolean result = false;
    int disconnectAudio() {
        synchronized (mStateMachines) {
            for (BluetoothDevice device : getNonIdleAudioDevices()) {
                if (disconnectAudio(device)) {
                    result = true;
                } else {
                    Log.e(TAG, "disconnectAudio() from " + device + " failed");
                }
            List<BluetoothDevice> activeAudioDevices = getNonIdleAudioDevices();
            BluetoothDevice activeAudioDevice =
                    activeAudioDevices.get(activeAudioDevices.size() - 1);
            return disconnectAudio(activeAudioDevice);
        }
    }
        if (!result) {
            logD("disconnectAudio() no active audio connection");
        }
        return result;
    }

    boolean disconnectAudio(BluetoothDevice device) {
    int disconnectAudio(BluetoothDevice device) {
        synchronized (mStateMachines) {
            Log.i(TAG, "disconnectAudio: device=" + device + ", " + Utils.getUidPidString());
            final HeadsetStateMachine stateMachine = mStateMachines.get(device);
            if (stateMachine == null) {
                Log.w(TAG, "disconnectAudio: device " + device + " was never connected/connecting");
                return false;
                return BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED;
            }
            if (stateMachine.getAudioState() == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                Log.w(TAG, "disconnectAudio, audio is already disconnected for " + device);
                return false;
                return BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED;
            }
            stateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO, device);
        }
        return true;
        return BluetoothStatusCodes.SUCCESS;
    }

    boolean isVirtualCallStarted() {
@@ -1533,7 +1537,7 @@ public class HeadsetService extends ProfileService {
            // Audio should not be on when no audio mode is active
            if (isAudioOn()) {
                // Disconnect audio so that API user can try later
                boolean status = disconnectAudio();
                int status = disconnectAudio();
                Log.w(TAG, "startScoUsingVirtualVoiceCall: audio is still active, please wait for "
                        + "audio to be disconnected, disconnectAudio() returned " + status
                        + ", active device is " + mActiveDevice);
@@ -1695,7 +1699,7 @@ public class HeadsetService extends ProfileService {
            // Audio should not be on when no audio mode is active
            if (isAudioOn()) {
                // Disconnect audio so that user can try later
                boolean status = disconnectAudio();
                int status = disconnectAudio();
                Log.w(TAG, "startVoiceRecognitionByHeadset: audio is still active, please wait for"
                        + " audio to be disconnected, disconnectAudio() returned " + status
                        + ", active device is " + mActiveDevice);
@@ -1750,9 +1754,10 @@ public class HeadsetService extends ProfileService {
                mVoiceRecognitionTimeoutEvent = null;
            }
            if (mVoiceRecognitionStarted) {
                if (!disconnectAudio()) {
                int disconnectStatus = disconnectAudio();
                if (disconnectStatus != BluetoothStatusCodes.SUCCESS) {
                    Log.w(TAG, "stopVoiceRecognitionByHeadset: failed to disconnect audio from "
                            + fromDevice);
                            + fromDevice + " with status code " + disconnectStatus);
                }
                mVoiceRecognitionStarted = false;
            }
@@ -1956,10 +1961,12 @@ public class HeadsetService extends ProfileService {
                if (fromState != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                    if (mActiveDevice != null && !mActiveDevice.equals(device)
                            && shouldPersistAudio()) {
                        if (!connectAudio(mActiveDevice)) {
                        int connectStatus = connectAudio(mActiveDevice);
                        if (connectStatus != BluetoothStatusCodes.SUCCESS) {
                            Log.w(TAG, "onAudioStateChangedFromStateMachine, failed to connect"
                                    + " audio to new " + "active device " + mActiveDevice
                                    + ", after " + device + " is disconnected from SCO");
                                    + ", after " + device + " is disconnected from SCO due to"
                                    + " status code " + connectStatus);
                        }
                    }
                }
@@ -2033,36 +2040,38 @@ public class HeadsetService extends ProfileService {
    }

    /**
     * Checks if SCO should be connected at current system state
     * Checks if SCO should be connected at current system state. Returns
     * {@link BluetoothStatusCodes#SUCCESS} if SCO is allowed to be connected or an error code on
     * failure.
     *
     * @param device device for SCO to be connected
     * @return true if SCO is allowed to be connected
     * @return whether SCO can be connected
     */
    public boolean isScoAcceptable(BluetoothDevice device) {
    public int isScoAcceptable(BluetoothDevice device) {
        synchronized (mStateMachines) {
            if (device == null || !device.equals(mActiveDevice)) {
                Log.w(TAG, "isScoAcceptable: rejected SCO since " + device
                        + " is not the current active device " + mActiveDevice);
                return false;
                return BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE;
            }
            if (mForceScoAudio) {
                return true;
                return BluetoothStatusCodes.SUCCESS;
            }
            if (!mAudioRouteAllowed) {
                Log.w(TAG, "isScoAcceptable: rejected SCO since audio route is not allowed");
                return false;
                return BluetoothStatusCodes.ERROR_AUDIO_ROUTE_BLOCKED;
            }
            if (mVoiceRecognitionStarted || mVirtualCallStarted) {
                return true;
                return BluetoothStatusCodes.SUCCESS;
            }
            if (shouldCallAudioBeActive()) {
                return true;
                return BluetoothStatusCodes.SUCCESS;
            }
            Log.w(TAG, "isScoAcceptable: rejected SCO, inCall=" + mSystemInterface.isInCall()
                    + ", voiceRecognition=" + mVoiceRecognitionStarted + ", ringing="
                    + mSystemInterface.isRinging() + ", inbandRinging=" + isInbandRingingEnabled()
                    + ", isVirtualCallStarted=" + mVirtualCallStarted);
            return false;
            return BluetoothStatusCodes.ERROR_CALL_ACTIVE;
        }
    }

+3 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.hfp.BluetoothHfpProtoEnums;
import android.content.Intent;
import android.media.AudioManager;
@@ -1110,7 +1111,7 @@ public class HeadsetStateMachine extends StateMachine {
            stateLogD("processAudioEvent, state=" + state);
            switch (state) {
                case HeadsetHalConstants.AUDIO_STATE_CONNECTED:
                    if (!mHeadsetService.isScoAcceptable(mDevice)) {
                    if (mHeadsetService.isScoAcceptable(mDevice) != BluetoothStatusCodes.SUCCESS) {
                        stateLogW("processAudioEvent: reject incoming audio connection");
                        if (!mNativeInterface.disconnectAudio(mDevice)) {
                            stateLogE("processAudioEvent: failed to disconnect audio");
@@ -1124,7 +1125,7 @@ public class HeadsetStateMachine extends StateMachine {
                    transitionTo(mAudioOn);
                    break;
                case HeadsetHalConstants.AUDIO_STATE_CONNECTING:
                    if (!mHeadsetService.isScoAcceptable(mDevice)) {
                    if (mHeadsetService.isScoAcceptable(mDevice) != BluetoothStatusCodes.SUCCESS) {
                        stateLogW("processAudioEvent: reject incoming pending audio connection");
                        if (!mNativeInterface.disconnectAudio(mDevice)) {
                            stateLogE("processAudioEvent: failed to disconnect pending audio");
+32 −16

File changed.

Preview size limit exceeded, changes collapsed.

Loading