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

Commit 274267cd authored by Jack He's avatar Jack He Committed by Android (Google) Code Review
Browse files

Merge changes I64de4bb5,I765f4a82,I2f2054c6,I5fdc54d0,I5dc62758, ... into tm-dev

* changes:
  Csip: Add method for checking group lock status
  Csip: Add more means to get grouped devices
  BassClient: Allow only one pending source operation
  BassClient: Reconnect devices in the background
  BassClient: Fix using Metadata cache
  BassClient: Fix not sending connection change intent
parents f71c7d1a 0351af2c
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -95,7 +95,8 @@ class CsisClientCallbacksImpl : public CsisClientCallbacks {
  }

  void OnDeviceAvailable(const RawAddress& bd_addr, int group_id,
                         int group_size, const bluetooth::Uuid& uuid) override {
                         int group_size, int rank,
                         const bluetooth::Uuid& uuid) override {
    std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
    CallbackEnv sCallbackEnv(__func__);
    if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
@@ -111,7 +112,7 @@ class CsisClientCallbacksImpl : public CsisClientCallbacks {

    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDeviceAvailable,
                                 addr.get(), (jint)group_id, (jint)group_size,
                                 UUID_PARAMS(uuid));
                                 (jint)rank, UUID_PARAMS(uuid));
  }

  void OnSetMemberAvailable(const RawAddress& bd_addr, int group_id) override {
@@ -156,7 +157,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
      env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V");

  method_onDeviceAvailable =
      env->GetMethodID(clazz, "onDeviceAvailable", "([BIIJJ)V");
      env->GetMethodID(clazz, "onDeviceAvailable", "([BIIIJJ)V");

  method_onSetMemberAvailable =
      env->GetMethodID(clazz, "onSetMemberAvailable", "([BI)V");
+6 −24
Original line number Diff line number Diff line
@@ -83,7 +83,6 @@ public class BassClientService extends ProfileService {
    private Map<BluetoothDevice, Integer> mDeviceToSyncHandleMap;
    /*syncHandle, parsed BaseData data*/
    private Map<Integer, BaseData> mSyncHandleToBaseDataMap;
    private Map<Integer, BluetoothLeBroadcastMetadata> mBroadcastSources;
    /*bcastSrcDevice, corresponding PeriodicAdvertisementResult*/
    private Map<BluetoothDevice, PeriodicAdvertisementResult> mPeriodicAdvertisementResultMap;
    private ScanCallback mSearchScanCallback;
@@ -181,25 +180,6 @@ public class BassClientService extends ProfileService {
        return base;
    }

    void updateSourceInternal(int sourceId, BluetoothLeBroadcastMetadata metaData) {
        if (mBroadcastSources == null) {
            return;
        }
        if (metaData != null) {
            // This will replace old metadata with new one
            mBroadcastSources.put(sourceId, metaData);
        } else {
            mBroadcastSources.remove(sourceId);
        }
    }

    BluetoothLeBroadcastMetadata getSourceInternal(int sourceId) {
        if (mBroadcastSources != null) {
            return mBroadcastSources.get(sourceId);
        }
        return null;
    }

    void setActiveSyncedSource(BluetoothDevice scanDelegator, BluetoothDevice sourceDevice) {
        log("setActiveSyncedSource: scanDelegator" + scanDelegator
                + ":: sourceDevice:" + sourceDevice);
@@ -283,10 +263,6 @@ public class BassClientService extends ProfileService {
            mActiveSourceMap.clear();
            mActiveSourceMap = null;
        }
        if (mBroadcastSources != null) {
            mBroadcastSources.clear();
            mBroadcastSources = null;
        }
        if (mBassUtils != null) {
            mBassUtils.cleanUp();
            mBassUtils = null;
@@ -765,6 +741,9 @@ public class BassClientService extends ProfileService {
                    BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
            return;
        }
        if (stateMachine.hasPendingSourceOperation()) {
            throw new IllegalStateException("addSource: source operation already pending");
        }
        if (!hasRoomForBroadcastSourceAddition(sink)) {
            log("addSource: device has no room");
            mCallbacks.notifySourceAddFailed(sink, sourceMetadata,
@@ -808,6 +787,9 @@ public class BassClientService extends ProfileService {
                    BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
            return;
        }
        if (stateMachine.hasPendingSourceOperation()) {
            throw new IllegalStateException("modifySource: source operation already pending");
        }
        Message message = stateMachine.obtainMessage(BassClientStateMachine.UPDATE_BCAST_SOURCE);
        message.arg1 = sourceId;
        message.obj = updatedMetadata;
+59 −8
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@
 */
package com.android.bluetooth.bass_client;

import static android.Manifest.permission.BLUETOOTH_CONNECT;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
@@ -65,6 +67,7 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothLeAudioCodecConfigMetadata;
import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastChannel;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
@@ -76,6 +79,7 @@ import android.bluetooth.le.PeriodicAdvertisingManager;
import android.bluetooth.le.PeriodicAdvertisingReport;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.content.Intent;
import android.os.Binder;
import android.os.Looper;
import android.os.Message;
@@ -83,6 +87,7 @@ import android.os.ParcelUuid;
import android.provider.DeviceConfig;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.internal.annotations.VisibleForTesting;
@@ -136,6 +141,7 @@ public class BassClientStateMachine extends StateMachine {
    private final Map<Integer, BluetoothLeBroadcastReceiveState>
            mBluetoothLeBroadcastReceiveStates =
            new HashMap<Integer, BluetoothLeBroadcastReceiveState>();
    private final Map<Integer, BluetoothLeBroadcastMetadata> mCurrentMetadata = new HashMap();
    private final Disconnected mDisconnected = new Disconnected();
    private final Connected mConnected = new Connected();
    private final Connecting mConnecting = new Connecting();
@@ -236,6 +242,24 @@ public class BassClientStateMachine extends StateMachine {
        mPendingOperation = -1;
        mPendingSourceId = -1;
        mPendingMetadata = null;
        mCurrentMetadata.clear();
    }

    Boolean hasPendingSourceOperation() {
        return mPendingMetadata != null;
    }

    BluetoothLeBroadcastMetadata getCurrentBroadcastMetadata(Integer sourceId) {
        return mCurrentMetadata.getOrDefault(sourceId, null);
    }

    private void setCurrentBroadcastMetadata(Integer sourceId,
            BluetoothLeBroadcastMetadata metadata) {
        if (metadata != null) {
            mCurrentMetadata.put(sourceId, metadata);
        } else {
            mCurrentMetadata.remove(sourceId);
        }
    }

    BluetoothLeBroadcastReceiveState getBroadcastReceiveStateForSourceDevice(
@@ -724,7 +748,7 @@ public class BassClientStateMachine extends StateMachine {
                mService.getCallbacks().notifySourceAdded(mDevice,
                        recvState.getSourceId(), BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                if (mPendingMetadata != null) {
                    mService.updateSourceInternal(recvState.getSourceId(), mPendingMetadata);
                    setCurrentBroadcastMetadata(recvState.getSourceId(), mPendingMetadata);
                }
                checkAndUpdateBroadcastCode(recvState);
                processPASyncState(recvState);
@@ -734,13 +758,13 @@ public class BassClientStateMachine extends StateMachine {
                    BluetoothDevice removedDevice = oldRecvState.getSourceDevice();
                    log("sourceInfo removal" + removedDevice);
                    cancelActiveSync(removedDevice);
                    mService.updateSourceInternal(oldRecvState.getSourceId(), null);
                    setCurrentBroadcastMetadata(oldRecvState.getSourceId(), null);
                    mService.getCallbacks().notifySourceRemoved(mDevice,
                            oldRecvState.getSourceId(),
                            BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                } else {
                    log("update to an existing recvState");
                    mService.updateSourceInternal(recvState.getSourceId(), mPendingMetadata);
                    setCurrentBroadcastMetadata(recvState.getSourceId(), mPendingMetadata);
                    mService.getCallbacks().notifySourceModified(mDevice,
                            recvState.getSourceId(), BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                    checkAndUpdateBroadcastCode(recvState);
@@ -959,6 +983,7 @@ public class BassClientStateMachine extends StateMachine {
        }
        mPendingOperation = -1;
        mPendingMetadata = null;
        mCurrentMetadata.clear();
    }

    @VisibleForTesting
@@ -975,6 +1000,16 @@ public class BassClientStateMachine extends StateMachine {
            } else {
                broadcastConnectionState(
                        mDevice, mLastConnectionState, BluetoothProfile.STATE_DISCONNECTED);
                if (mLastConnectionState != BluetoothProfile.STATE_DISCONNECTED) {
                    // Reconnect in background if not disallowed by the service
                    if (mService.okToConnect(mDevice)) {
                        mBluetoothGatt = mDevice.connectGatt(mService, true,
                                mGattCallback, BluetoothDevice.TRANSPORT_LE,
                                (BluetoothDevice.PHY_LE_1M_MASK
                                        | BluetoothDevice.PHY_LE_2M_MASK
                                        | BluetoothDevice.PHY_LE_CODED_MASK), null);
                    }
                }
            }
        }

@@ -1011,7 +1046,15 @@ public class BassClientStateMachine extends StateMachine {
                    }
                    break;
                case DISCONNECT:
                    Log.w(TAG, "Disconnected: DISCONNECT ignored: " + mDevice);
                    // Disconnect if there's an ongoing background connection
                    if (mBluetoothGatt != null) {
                        log("Cancelling the background connection to " + mDevice);
                        mBluetoothGatt.disconnect();
                        mBluetoothGatt.close();
                        mBluetoothGatt = null;
                    } else {
                        Log.d(TAG, "Disconnected: DISCONNECT ignored: " + mDevice);
                    }
                    break;
                case CONNECTION_STATE_CHANGED:
                    int state = (int) message.obj;
@@ -1289,8 +1332,8 @@ public class BassClientStateMachine extends StateMachine {
        res[1] = (byte) recvState.getSourceId();
        log("convertRecvStateToSetBroadcastCodeByteArray: Source device : "
                + recvState.getSourceDevice());
        BluetoothLeBroadcastMetadata metaData = mService.getSourceInternal(
                recvState.getSourceId());
        BluetoothLeBroadcastMetadata metaData =
                getCurrentBroadcastMetadata(recvState.getSourceId());
        if (metaData == null) {
            Log.e(TAG, "Fail to find broadcast source, sourceId = "
                    + recvState.getSourceId());
@@ -1350,7 +1393,7 @@ public class BassClientStateMachine extends StateMachine {
                    + messageWhatToString(getCurrentMessage().what));
            removeDeferredMessages(CONNECT);
            if (mLastConnectionState == BluetoothProfile.STATE_CONNECTED) {
                log("CONNECTED->CONNTECTED: Ignore");
                log("CONNECTED->CONNECTED: Ignore");
            } else {
                broadcastConnectionState(mDevice, mLastConnectionState,
                        BluetoothProfile.STATE_CONNECTED);
@@ -1747,9 +1790,17 @@ public class BassClientStateMachine extends StateMachine {
        log("broadcastConnectionState " + device + ": " + fromState + "->" + toState);
        if (fromState == BluetoothProfile.STATE_CONNECTED
                && toState == BluetoothProfile.STATE_CONNECTED) {
            log("CONNECTED->CONNTECTED: Ignore");
            log("CONNECTED->CONNECTED: Ignore");
            return;
        }

        Intent intent = new Intent(BluetoothLeBroadcastAssistant.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, toState);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        mService.sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());
    }

    int getConnectionState() {
+2 −1
Original line number Diff line number Diff line
@@ -149,13 +149,14 @@ public class CsipSetCoordinatorNativeInterface {
    /** Device availability */
    @VisibleForTesting
    public void onDeviceAvailable(
            byte[] address, int groupId, int groupSize, long uuidLsb, long uuidMsb) {
            byte[] address, int groupId, int groupSize, int rank, long uuidLsb, long uuidMsb) {
        UUID uuid = new UUID(uuidMsb, uuidLsb);
        CsipSetCoordinatorStackEvent event = new CsipSetCoordinatorStackEvent(
                CsipSetCoordinatorStackEvent.EVENT_TYPE_DEVICE_AVAILABLE);
        event.device = getDevice(address);
        event.valueInt1 = groupId;
        event.valueInt2 = groupSize;
        event.valueInt3 = rank;
        event.valueUuid1 = uuid;

        if (DBG) {
+47 −13
Original line number Diff line number Diff line
@@ -52,11 +52,9 @@ import com.android.modules.utils.SynchronousResultReceiver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -87,7 +85,8 @@ public class CsipSetCoordinatorService extends ProfileService {
            new HashMap<>();

    private final Map<Integer, ParcelUuid> mGroupIdToUuidMap = new HashMap<>();
    private final Map<BluetoothDevice, Set<Integer>> mDeviceGroupIdMap = new ConcurrentHashMap<>();
    private final Map<BluetoothDevice, Map<Integer, Integer>> mDeviceGroupIdRankMap =
            new ConcurrentHashMap<>();
    private final Map<Integer, Integer> mGroupIdToGroupSize = new HashMap<>();
    private final Map<ParcelUuid, Map<Executor, IBluetoothCsipSetCoordinatorCallback>> mCallbacks =
            new HashMap<>();
@@ -201,7 +200,7 @@ public class CsipSetCoordinatorService extends ProfileService {
            }
        }

        mDeviceGroupIdMap.clear();
        mDeviceGroupIdRankMap.clear();
        mCallbacks.clear();
        mGroupIdToGroupSize.clear();
        mGroupIdToUuidMap.clear();
@@ -554,6 +553,17 @@ public class CsipSetCoordinatorService extends ProfileService {
        }
    }

    /**
     * Check whether a given group is currently locked.
     * @param groupId unique group identifier
     * @return true if group is currently locked, otherwise false.
     *
     * @hide
     */
    public boolean isGroupLocked(int groupId) {
        return mLocks.containsKey(groupId);
    }

    /**
     * Get collection of group IDs for a given UUID
     * @param uuid
@@ -573,13 +583,37 @@ public class CsipSetCoordinatorService extends ProfileService {
     * @return map of group id and related uuids.
     */
    public Map<Integer, ParcelUuid> getGroupUuidMapByDevice(BluetoothDevice device) {
        Set<Integer> device_groups = mDeviceGroupIdMap.getOrDefault(device, new HashSet<>());
        Map<Integer, Integer> device_groups =
                mDeviceGroupIdRankMap.getOrDefault(device, new HashMap<>());
        return mGroupIdToUuidMap.entrySet()
                .stream()
                .filter(e -> device_groups.contains(e.getKey()))
                .filter(e -> device_groups.containsKey(e.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * Get grouped devices
     * @param groupId group ID
     * @return related list of devices sorted from the lowest to the highest rank value.
     */
    public @NonNull List<BluetoothDevice> getGroupDevicesOrdered(int groupId) {
        final Map<BluetoothDevice, Integer> deviceRankMap = new HashMap();
        for (Map.Entry<BluetoothDevice, ?> entry : mDeviceGroupIdRankMap.entrySet()) {
            Map<Integer, Integer> rankMap = (Map<Integer, Integer>) entry.getValue();
            BluetoothDevice device = entry.getKey();
            if (rankMap.containsKey(groupId)) {
                deviceRankMap.put(device, rankMap.get(groupId));
            }
        }

        // Return device list sorted by descending rank order
        return deviceRankMap.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByValue())
                .map(e -> e.getKey())
                .collect(Collectors.toList());
    }

    /**
     * Get group desired size
     * @param groupId group ID
@@ -590,18 +624,18 @@ public class CsipSetCoordinatorService extends ProfileService {
                IBluetoothCsipSetCoordinator.CSIS_GROUP_SIZE_UNKNOWN);
    }

    private void handleDeviceAvailable(BluetoothDevice device, int groupId, UUID uuid) {
    private void handleDeviceAvailable(BluetoothDevice device, int groupId, int rank, UUID uuid) {
        ParcelUuid parcel_uuid = new ParcelUuid(uuid);
        if (!getAllGroupIds(parcel_uuid).contains(groupId)) {
            mGroupIdToUuidMap.put(groupId, parcel_uuid);
        }

        if (!mDeviceGroupIdMap.containsKey(device)) {
            mDeviceGroupIdMap.put(device, new HashSet<Integer>());
        if (!mDeviceGroupIdRankMap.containsKey(device)) {
            mDeviceGroupIdRankMap.put(device, new HashMap<Integer, Integer>());
        }

        Set<Integer> all_device_groups = mDeviceGroupIdMap.get(device);
        all_device_groups.add(groupId);
        Map<Integer, Integer> all_device_groups = mDeviceGroupIdRankMap.get(device);
        all_device_groups.put(groupId, rank);
    }

    private void executeCallback(Executor exec, IBluetoothCsipSetCoordinatorCallback callback,
@@ -700,7 +734,7 @@ public class CsipSetCoordinatorService extends ProfileService {
            intent.putExtra(
                    BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_TYPE_UUID, stackEvent.valueUuid1);

            handleDeviceAvailable(device, groupId, stackEvent.valueUuid1);
            handleDeviceAvailable(device, groupId, stackEvent.valueInt3, stackEvent.valueUuid1);
        } else if (stackEvent.type
                == CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE) {
            Objects.requireNonNull(device, "Device should never be null, event: " + stackEvent);
@@ -808,7 +842,7 @@ public class CsipSetCoordinatorService extends ProfileService {
            return;
        }

        mDeviceGroupIdMap.remove(device);
        mDeviceGroupIdRankMap.remove(device);

        synchronized (mStateMachines) {
            CsipSetCoordinatorStateMachine sm = mStateMachines.get(device);
Loading