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

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

Update service code to match new HFP audio state System APIs

Tag: #feature
Bug: 195156304
Test: Manual
Ignore-AOSP-First: Resolving merge conflict
Change-Id: I8af246091ae49c8f9cf34c1f4a894b3a66a28cf8
parent 6236a268
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ import com.android.bluetooth.BluetoothStatsLog;
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;
@@ -2447,10 +2446,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
@@ -2461,10 +2460,10 @@ public class AdapterService extends Service {
            }

            if (service.mAdapterProperties.isLePeriodicAdvertisingSyncTransferSenderSupported()) {
                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;
@@ -683,6 +684,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);
@@ -698,6 +700,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);
@@ -710,8 +713,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);
@@ -724,8 +728,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);
@@ -882,6 +887,7 @@ public class HeadsetService extends ProfileService {
                HeadsetService service = getService(source);
                boolean defaultValue = false;
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    defaultValue = service.isInbandRingingEnabled();
                }
                receiver.send(defaultValue);
@@ -1122,7 +1128,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);
@@ -1327,8 +1333,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;
@@ -1366,9 +1374,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 {
@@ -1380,8 +1389,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 {
@@ -1408,45 +1419,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() {
@@ -1461,38 +1473,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() {
@@ -1522,7 +1526,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);
@@ -1684,7 +1688,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);
@@ -1739,9 +1743,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;
            }
@@ -1943,10 +1948,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);
                        }
                    }
                }
@@ -2020,36 +2027,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