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

Commit 9e75cb28 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "VolumeControl: rm impossible null handler" into main am: fd72ab75

parents de22747a fd72ab75
Loading
Loading
Loading
Loading
+100 −138
Original line number Diff line number Diff line
@@ -19,6 +19,14 @@ package com.android.bluetooth.vc;

import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.bluetooth.BluetoothDevice.BOND_BONDED;
import static android.bluetooth.BluetoothDevice.BOND_NONE;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;

import static java.util.Objects.requireNonNull;

@@ -31,7 +39,6 @@ import android.bluetooth.IBluetoothLeAudio;
import android.bluetooth.IBluetoothVolumeControl;
import android.bluetooth.IBluetoothVolumeControlCallback;
import android.content.AttributionSource;
import android.content.Context;
import android.media.AudioManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -70,27 +77,28 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class VolumeControlService extends ProfileService {
    private static final String TAG = "VolumeControlService";
    private static final String TAG = VolumeControlService.class.getSimpleName();

    // Timeout for state machine thread join, to prevent potential ANR.
    private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000;

    private static final int LE_AUDIO_MAX_VOL = 255;
    /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior.
     * User Set Volume Setting means that remote keeps volume in its cache. */
    @VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01;

    private static VolumeControlService sVolumeControlService;

    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private Handler mHandler = null;

    @VisibleForTesting
    @GuardedBy("mCallbacks")
    final RemoteCallbackList<IBluetoothVolumeControlCallback> mCallbacks =
            new RemoteCallbackList<>();

    VolumeControlNativeInterface mVolumeControlNativeInterface;
    @VisibleForTesting AudioManager mAudioManager;
    private final AdapterService mAdapterService;
    private final AudioManager mAudioManager;
    private final DatabaseManager mDatabaseManager;
    private final Handler mHandler;
    private final HandlerThread mStateMachinesThread;
    private final Looper mStateMachinesLooper;
    private final VolumeControlNativeInterface mNativeInterface;

    private final Map<BluetoothDevice, VolumeControlStateMachine> mStateMachines = new HashMap<>();
    private final Map<BluetoothDevice, VolumeControlOffsetDescriptor> mAudioOffsets =
@@ -100,15 +108,34 @@ public class VolumeControlService extends ProfileService {
    private final Map<Integer, Boolean> mGroupMuteCache = new HashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceVolumeCache = new HashMap<>();

    /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior.
     * User Set Volume Setting means that remote keeps volume in its cache.
     */
    @VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01;

    @VisibleForTesting ServiceFactory mFactory = new ServiceFactory();

    public VolumeControlService(Context ctx) {
        super(ctx);
    public VolumeControlService(AdapterService adapterService) {
        this(adapterService, null, VolumeControlNativeInterface.getInstance());
    }

    @VisibleForTesting
    VolumeControlService(
            AdapterService adapterService,
            Looper looper,
            VolumeControlNativeInterface nativeInterface) {
        super(requireNonNull(adapterService));
        mAdapterService = adapterService;
        mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
        mNativeInterface = requireNonNull(nativeInterface);
        mAudioManager = requireNonNull(getSystemService(AudioManager.class));
        if (looper == null) {
            mHandler = new Handler(requireNonNull(Looper.getMainLooper()));
            mStateMachinesThread = new HandlerThread("VolumeControlService.StateMachines");
            mStateMachinesThread.start();
            mStateMachinesLooper = mStateMachinesThread.getLooper();
        } else {
            mHandler = new Handler(looper);
            mStateMachinesThread = null;
            mStateMachinesLooper = looper;
        }
        setVolumeControlService(this);
        mNativeInterface.init();
    }

    public static boolean isEnabled() {
@@ -120,45 +147,9 @@ public class VolumeControlService extends ProfileService {
        return new BluetoothVolumeControlBinder(this);
    }

    @Override
    public void start() {
        Log.d(TAG, "start()");
        if (sVolumeControlService != null) {
            throw new IllegalStateException("start() called twice");
        }

        // Get AdapterService, VolumeControlNativeInterface, DatabaseManager, AudioManager.
        // None of them can be null.
        mAdapterService = requireNonNull(AdapterService.getAdapterService());
        mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
        mVolumeControlNativeInterface = requireNonNull(VolumeControlNativeInterface.getInstance());
        mAudioManager = requireNonNull(getSystemService(AudioManager.class));

        // Start handler thread for state machines
        mHandler = new Handler(Looper.getMainLooper());
        mStateMachines.clear();
        mStateMachinesThread = new HandlerThread("VolumeControlService.StateMachines");
        mStateMachinesThread.start();

        mAudioOffsets.clear();
        mGroupVolumeCache.clear();
        mGroupMuteCache.clear();
        mDeviceVolumeCache.clear();

        // Mark service as started
        setVolumeControlService(this);

        // Initialize native interface
        mVolumeControlNativeInterface.init();
    }

    @Override
    public void stop() {
        Log.d(TAG, "stop()");
        if (sVolumeControlService == null) {
            Log.w(TAG, "stop() called before start()");
            return;
        }

        // Mark service as stopped
        setVolumeControlService(null);
@@ -167,7 +158,6 @@ public class VolumeControlService extends ProfileService {
        synchronized (mStateMachines) {
            for (VolumeControlStateMachine sm : mStateMachines.values()) {
                sm.doQuit();
                sm.cleanup();
            }
            mStateMachines.clear();
        }
@@ -176,43 +166,25 @@ public class VolumeControlService extends ProfileService {
            try {
                mStateMachinesThread.quitSafely();
                mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
                mStateMachinesThread = null;
            } catch (InterruptedException e) {
                // Do not rethrow as we are shutting down anyway
            }
        }

        // Unregister handler and remove all queued messages.
        if (mHandler != null) {
        mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }

        // Cleanup native interface
        mVolumeControlNativeInterface.cleanup();
        mVolumeControlNativeInterface = null;
        mNativeInterface.cleanup();

        mAudioOffsets.clear();
        mGroupVolumeCache.clear();
        mGroupMuteCache.clear();
        mDeviceVolumeCache.clear();

        // Clear AdapterService, VolumeControlNativeInterface
        mAudioManager = null;
        mVolumeControlNativeInterface = null;
        mAdapterService = null;

        synchronized (mCallbacks) {
            if (mCallbacks != null) {
            mCallbacks.kill();
        }
    }
    }

    @Override
    public void cleanup() {
        Log.d(TAG, "cleanup()");
    }

    /**
     * Get the VolumeControlService instance
@@ -244,7 +216,7 @@ public class VolumeControlService extends ProfileService {
            return false;
        }

        if (getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
        if (getConnectionPolicy(device) == CONNECTION_POLICY_FORBIDDEN) {
            return false;
        }
        final ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device);
@@ -260,7 +232,7 @@ public class VolumeControlService extends ProfileService {
            if (smConnect == null) {
                Log.e(TAG, "Cannot connect to " + device + " : no state machine");
            }
            smConnect.sendMessage(VolumeControlStateMachine.CONNECT);
            smConnect.sendMessage(VolumeControlStateMachine.MESSAGE_CONNECT);
        }

        return true;
@@ -274,7 +246,7 @@ public class VolumeControlService extends ProfileService {
        synchronized (mStateMachines) {
            VolumeControlStateMachine sm = getOrCreateStateMachine(device);
            if (sm != null) {
                sm.sendMessage(VolumeControlStateMachine.DISCONNECT);
                sm.sendMessage(VolumeControlStateMachine.MESSAGE_DISCONNECT);
            }
        }

@@ -317,11 +289,11 @@ public class VolumeControlService extends ProfileService {
        int bondState = mAdapterService.getBondState(device);
        // Allow this connection only if the device is bonded. Any attempt to connect while
        // bonding would potentially lead to an unauthorized connection.
        if (bondState != BluetoothDevice.BOND_BONDED) {
        if (bondState != BOND_BONDED) {
            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
            return false;
        } else if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_UNKNOWN
                && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
        } else if (connectionPolicy != CONNECTION_POLICY_UNKNOWN
                && connectionPolicy != CONNECTION_POLICY_ALLOWED) {
            // Otherwise, reject the connection if connectionPolicy is not valid.
            Log.w(TAG, "okToConnect: return false, connectionPolicy=" + connectionPolicy);
            return false;
@@ -344,7 +316,7 @@ public class VolumeControlService extends ProfileService {
                if (!Utils.arrayContains(featureUuids, BluetoothUuid.VOLUME_CONTROL)) {
                    continue;
                }
                int connectionState = BluetoothProfile.STATE_DISCONNECTED;
                int connectionState = STATE_DISCONNECTED;
                VolumeControlStateMachine sm = mStateMachines.get(device);
                if (sm != null) {
                    connectionState = sm.getConnectionState();
@@ -380,7 +352,7 @@ public class VolumeControlService extends ProfileService {
        synchronized (mStateMachines) {
            VolumeControlStateMachine sm = mStateMachines.get(device);
            if (sm == null) {
                return BluetoothProfile.STATE_DISCONNECTED;
                return STATE_DISCONNECTED;
            }
            return sm.getConnectionState();
        }
@@ -404,9 +376,9 @@ public class VolumeControlService extends ProfileService {
        Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
        mDatabaseManager.setProfileConnectionPolicy(
                device, BluetoothProfile.VOLUME_CONTROL, connectionPolicy);
        if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
        if (connectionPolicy == CONNECTION_POLICY_ALLOWED) {
            connect(device);
        } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
        } else if (connectionPolicy == CONNECTION_POLICY_FORBIDDEN) {
            disconnect(device);
        }
        return true;
@@ -465,7 +437,7 @@ public class VolumeControlService extends ProfileService {
            return;
        }

        mVolumeControlNativeInterface.setExtAudioOutVolumeOffset(device, instanceId, volumeOffset);
        mNativeInterface.setExtAudioOutVolumeOffset(device, instanceId, volumeOffset);
    }

    void setDeviceVolume(BluetoothDevice device, int volume, boolean isGroupOp) {
@@ -489,7 +461,7 @@ public class VolumeControlService extends ProfileService {
        } else {
            Log.i(TAG, "Setting individual device volume");
            mDeviceVolumeCache.put(device, volume);
            mVolumeControlNativeInterface.setVolume(device, volume);
            mNativeInterface.setVolume(device, volume);
        }
    }

@@ -500,7 +472,7 @@ public class VolumeControlService extends ProfileService {
        }

        mGroupVolumeCache.put(groupId, volume);
        mVolumeControlNativeInterface.setGroupVolume(groupId, volume);
        mNativeInterface.setGroupVolume(groupId, volume);

        // We only receive the volume change and mute state needs to be acquired manually
        Boolean isGroupMute = mGroupMuteCache.getOrDefault(groupId, false);
@@ -508,7 +480,7 @@ public class VolumeControlService extends ProfileService {

        /* Note: AudioService keeps volume levels for each stream and for each device type,
         * however it stores the mute state only for the stream type but not for each individual
         * device type. When active device changes, it's volume level gets aplied, but mute state
         * device type. When active device changes, it's volume level gets applied, but mute state
         * is not, but can be either derived from the volume level or just unmuted like for A2DP.
         * Also setting volume level > 0 to audio system will implicitly unmute the stream.
         * However LeAudio devices can keep their volume level high, while keeping it mute so we
@@ -580,21 +552,21 @@ public class VolumeControlService extends ProfileService {
    }

    public void mute(BluetoothDevice device) {
        mVolumeControlNativeInterface.mute(device);
        mNativeInterface.mute(device);
    }

    public void muteGroup(int groupId) {
        mGroupMuteCache.put(groupId, true);
        mVolumeControlNativeInterface.muteGroup(groupId);
        mNativeInterface.muteGroup(groupId);
    }

    public void unmute(BluetoothDevice device) {
        mVolumeControlNativeInterface.unmute(device);
        mNativeInterface.unmute(device);
    }

    public void unmuteGroup(int groupId) {
        mGroupMuteCache.put(groupId, false);
        mVolumeControlNativeInterface.unmuteGroup(groupId);
        mNativeInterface.unmuteGroup(groupId);
    }

    void notifyNewCallbackOfKnownVolumeInfo(IBluetoothVolumeControlCallback callback) {
@@ -670,7 +642,7 @@ public class VolumeControlService extends ProfileService {
            if (sm == null) {
                return;
            }
            if (sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
            if (sm.getConnectionState() != STATE_CONNECTED) {
                return;
            }
        }
@@ -680,7 +652,7 @@ public class VolumeControlService extends ProfileService {
        synchronized (mStateMachines) {
            VolumeControlStateMachine sm = mStateMachines.get(device);
            if (sm != null) {
                can_change_volume = (sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED);
                can_change_volume = (sm.getConnectionState() == STATE_CONNECTED);
            }
        }

@@ -691,15 +663,15 @@ public class VolumeControlService extends ProfileService {
                            groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
            if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
                Log.i(TAG, "Setting value:" + groupVolume + " to " + device);
                mVolumeControlNativeInterface.setVolume(device, groupVolume);
                mNativeInterface.setVolume(device, groupVolume);
            }

            Boolean isGroupMuted = mGroupMuteCache.getOrDefault(groupId, false);
            Log.i(TAG, "Setting mute:" + isGroupMuted + " to " + device);
            if (isGroupMuted) {
                mVolumeControlNativeInterface.mute(device);
                mNativeInterface.mute(device);
            } else {
                mVolumeControlNativeInterface.unmute(device);
                mNativeInterface.unmute(device);
            }
        }
    }
@@ -865,21 +837,20 @@ public class VolumeControlService extends ProfileService {
                synchronized (mStateMachines) {
                    VolumeControlStateMachine sm = mStateMachines.get(device);
                    if (sm != null) {
                        can_change_volume =
                                (sm.getConnectionState() == BluetoothProfile.STATE_CONNECTED);
                        can_change_volume = (sm.getConnectionState() == STATE_CONNECTED);
                    }
                }

                if (can_change_volume && (groupVolume != volume)) {
                    Log.i(TAG, "Setting value:" + groupVolume + " to " + device);
                    mVolumeControlNativeInterface.setVolume(device, groupVolume);
                    mNativeInterface.setVolume(device, groupVolume);
                }
                if (can_change_volume && (groupMute != mute)) {
                    Log.i(TAG, "Setting mute:" + groupMute + " to " + device);
                    if (groupMute) {
                        mVolumeControlNativeInterface.mute(device);
                        mNativeInterface.mute(device);
                    } else {
                        mVolumeControlNativeInterface.unmute(device);
                        mNativeInterface.unmute(device);
                    }
                }
            } else {
@@ -925,19 +896,16 @@ public class VolumeControlService extends ProfileService {

        Log.d(TAG, "Volume mode: " + mode + "0: normal, 1: ring, 2,3: call");

        switch (mode) {
            case AudioManager.MODE_IN_COMMUNICATION:
            case AudioManager.MODE_IN_CALL:
                return AudioManager.STREAM_VOICE_CALL;
            case AudioManager.MODE_RINGTONE:
        return switch (mode) {
            case AudioManager.MODE_IN_CALL, AudioManager.MODE_IN_COMMUNICATION -> {
                yield AudioManager.STREAM_VOICE_CALL;
            }
            case AudioManager.MODE_RINGTONE -> {
                Log.d(TAG, " Update during ringtone applied to voice call");
                return AudioManager.STREAM_VOICE_CALL;
            case AudioManager.MODE_NORMAL:
            default:
                // other conditions will influence the stream type choice, read on...
                break;
                yield AudioManager.STREAM_VOICE_CALL;
            }
        return AudioManager.STREAM_MUSIC;
            default -> AudioManager.STREAM_MUSIC;
        };
    }

    void handleExternalOutputs(BluetoothDevice device, int numberOfExternalOutputs) {
@@ -1277,12 +1245,9 @@ public class VolumeControlService extends ProfileService {
                if (stackEvent.type
                        == VolumeControlStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
                    switch (stackEvent.valueInt1) {
                        case VolumeControlStackEvent.CONNECTION_STATE_CONNECTED:
                        case VolumeControlStackEvent.CONNECTION_STATE_CONNECTING:
                        case STATE_CONNECTED, STATE_CONNECTING -> {
                            sm = getOrCreateStateMachine(device);
                            break;
                        default:
                            break;
                        }
                    }
                }
            }
@@ -1290,7 +1255,7 @@ public class VolumeControlService extends ProfileService {
                Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
                return;
            }
            sm.sendMessage(VolumeControlStateMachine.STACK_EVENT, stackEvent);
            sm.sendMessage(VolumeControlStateMachine.MESSAGE_STACK_EVENT, stackEvent);
        }
    }

@@ -1307,11 +1272,9 @@ public class VolumeControlService extends ProfileService {

            Log.d(TAG, "Creating a new state machine for " + device);
            sm =
                    VolumeControlStateMachine.make(
                            device,
                            this,
                            mVolumeControlNativeInterface,
                            mStateMachinesThread.getLooper());
                    new VolumeControlStateMachine(
                            this, device, mNativeInterface, mStateMachinesLooper);
            sm.start();
            mStateMachines.put(device, sm);
            return sm;
        }
@@ -1392,7 +1355,7 @@ public class VolumeControlService extends ProfileService {
    void bondStateChanged(BluetoothDevice device, int bondState) {
        Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState);
        // Remove state machine if the bonding for a device is removed
        if (bondState != BluetoothDevice.BOND_NONE) {
        if (bondState != BOND_NONE) {
            return;
        }

@@ -1401,7 +1364,7 @@ public class VolumeControlService extends ProfileService {
            if (sm == null) {
                return;
            }
            if (sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) {
            if (sm.getConnectionState() != STATE_DISCONNECTED) {
                Log.i(TAG, "Disconnecting device because it was unbonded.");
                disconnect(device);
                return;
@@ -1421,7 +1384,6 @@ public class VolumeControlService extends ProfileService {
            }
            Log.i(TAG, "removeStateMachine: removing state machine for device: " + device);
            sm.doQuit();
            sm.cleanup();
            mStateMachines.remove(device);
        }
    }
@@ -1450,13 +1412,13 @@ public class VolumeControlService extends ProfileService {
        }

        // Check if the device is disconnected - if unbond, remove the state machine
        if (toState == BluetoothProfile.STATE_DISCONNECTED) {
        if (toState == STATE_DISCONNECTED) {
            int bondState = mAdapterService.getBondState(device);
            if (bondState == BluetoothDevice.BOND_NONE) {
            if (bondState == BOND_NONE) {
                Log.d(TAG, device + " is unbond. Remove state machine");
                removeStateMachine(device);
            }
        } else if (toState == BluetoothProfile.STATE_CONNECTED) {
        } else if (toState == STATE_CONNECTED) {
            // Restore the group volume if it was changed while the device was not yet connected.
            CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService();
            if (csipClient != null) {
@@ -1466,14 +1428,14 @@ public class VolumeControlService extends ProfileService {
                            mGroupVolumeCache.getOrDefault(
                                    groupId, IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME);
                    if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
                        mVolumeControlNativeInterface.setVolume(device, groupVolume);
                        mNativeInterface.setVolume(device, groupVolume);
                    }

                    Boolean groupMute = mGroupMuteCache.getOrDefault(groupId, false);
                    if (groupMute) {
                        mVolumeControlNativeInterface.mute(device);
                        mNativeInterface.mute(device);
                    } else {
                        mVolumeControlNativeInterface.unmute(device);
                        mNativeInterface.unmute(device);
                    }
                }
            } else {
@@ -1554,7 +1516,7 @@ public class VolumeControlService extends ProfileService {

            VolumeControlService service = getService(source);
            if (service == null) {
                return BluetoothProfile.STATE_DISCONNECTED;
                return STATE_DISCONNECTED;
            }

            return service.getConnectionState(device);
@@ -1580,7 +1542,7 @@ public class VolumeControlService extends ProfileService {

            VolumeControlService service = getService(source);
            if (service == null) {
                return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
                return CONNECTION_POLICY_UNKNOWN;
            }

            service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+3 −31
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
package com.android.bluetooth.vc;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;

public class VolumeControlStackEvent {
    // Event types for STACK_EVENT message (coming from native)
@@ -34,13 +35,6 @@ public class VolumeControlStackEvent {
    public static final int EVENT_TYPE_EXT_AUDIO_IN_DESCR_CHANGED = 10;
    public static final int EVENT_TYPE_EXT_AUDIO_IN_GAIN_PROPS_CHANGED = 11;

    // Do not modify without updating the HAL bt_vc_aid.h files.
    // Match up with enum class ConnectionState of bt_vc_aid.h.
    static final int CONNECTION_STATE_DISCONNECTED = 0;
    static final int CONNECTION_STATE_CONNECTING = 1;
    static final int CONNECTION_STATE_CONNECTED = 2;
    static final int CONNECTION_STATE_DISCONNECTING = 3;

    public int type;
    public BluetoothDevice device;
    public int valueInt1;
@@ -108,18 +102,7 @@ public class VolumeControlStackEvent {
    private static String eventTypeValue1ToString(int type, int value) {
        switch (type) {
            case EVENT_TYPE_CONNECTION_STATE_CHANGED:
                switch (value) {
                    case CONNECTION_STATE_DISCONNECTED:
                        return "CONNECTION_STATE_DISCONNECTED";
                    case CONNECTION_STATE_CONNECTING:
                        return "CONNECTION_STATE_CONNECTING";
                    case CONNECTION_STATE_CONNECTED:
                        return "CONNECTION_STATE_CONNECTED";
                    case CONNECTION_STATE_DISCONNECTING:
                        return "CONNECTION_STATE_DISCONNECTING";
                    default:
                        return "UNKNOWN";
                }
                return BluetoothProfile.getConnectionStateName(value);
            case EVENT_TYPE_VOLUME_STATE_CHANGED:
                return "{group_id:" + value + "}";
            case EVENT_TYPE_DEVICE_AVAILABLE:
@@ -143,18 +126,7 @@ public class VolumeControlStackEvent {
    private static String eventTypeValue2ToString(int type, int value) {
        switch (type) {
            case EVENT_TYPE_CONNECTION_STATE_CHANGED:
                switch (value) {
                    case CONNECTION_STATE_DISCONNECTED:
                        return "CONNECTION_STATE_DISCONNECTED";
                    case CONNECTION_STATE_CONNECTING:
                        return "CONNECTION_STATE_CONNECTING";
                    case CONNECTION_STATE_CONNECTED:
                        return "CONNECTION_STATE_CONNECTED";
                    case CONNECTION_STATE_DISCONNECTING:
                        return "CONNECTION_STATE_DISCONNECTING";
                    default:
                        return "UNKNOWN";
                }
                return BluetoothProfile.getConnectionStateName(value);
            case EVENT_TYPE_VOLUME_STATE_CHANGED:
                return "{volume:" + value + "}";
            case EVENT_TYPE_DEVICE_AVAILABLE:
+130 −210

File changed.

Preview size limit exceeded, changes collapsed.

+3 −1
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothProfile;

import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
@@ -55,7 +57,7 @@ public class VolumeControlNativeInterfaceTest {

    @Test
    public void onConnectionStateChanged() {
        int state = VolumeControlStackEvent.CONNECTION_STATE_CONNECTED;
        int state = BluetoothProfile.STATE_CONNECTED;
        byte[] address = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};

        mNativeInterface.onConnectionStateChanged(state, address);
+410 −748

File changed.

Preview size limit exceeded, changes collapsed.

Loading