android13#settings#bluetooth pair new device

42 阅读9分钟

1.简介

1.1.页面图

image.png

1.2.问题

  • 上下滑动列表的时候,有几率会卡顿,滑动无效,查找下原因。
  • 自己写个demo监听蓝牙相关的广播,发现每次ACTION_DISCOVERY_STARTED的前后会卡。
  • 首先startDiscovery()方法每次时间是12s左右,所以settings里会监听ACTION_DISCOVERY_FINISHED,完事重新开始扫描,参考3.9

1.3.解决

>1.简单处理

  • 最开始,我以为startDiscovery是阻塞的,会卡是它引起的,所以把3.7的代码放入后台线程,结果无效。
  • 然后就看了下3.6,蓝牙设备创建的选项就是这个类。
  • 首先,参考3.1里的配置,我们只显示带名字的蓝牙设备,而扫描出来的大部分不带名字的,那么完全没必要创建3.6的对象,然后在内部判断显示隐藏。
  • 参考3.6.1,设备注册了回调,再看小节8,里边蓝牙设备稍微发生点变化就会回调,太频繁。
  • 最终修改的3.5.1的方法,对于不用显示的蓝牙设备,不再创建对象。
    void createDevicePreference(CachedBluetoothDevice cachedDevice) {
        if (mDeviceListGroup == null) {
            Log.w(TAG, "Trying to create a device preference before the list group/category "
                    + "exists!");
            return;
        }
        //最开始修改的地方,新加的逻辑,不需要显示的不创建对象
        //扫描结果十来个没问题,如果几十个还是会卡。
        if (!mShowDevicesWithoutNames && !cachedDevice.hasHumanReadableName()) {
            Log.w(TAG, "mytest====no need add device : mShowDevicesWithoutNames is false, and hasHumanReadableName is false==="+cachedDevice);
            return;
        }

>2.进一步

  • 补充1里是根据实际情况处理的,毕竟有名字的蓝牙扫描结果不会太多,那么如果没名字的也显示的话,那补充1的修改不就无用了吗?
  • 其实卡壳的根源还是选项刷新太频繁了。参考3.6.2的回调,根据小节8,它的回调是非常频繁的,尤其是重新开始扫描的时候,所以过滤下刷新条件。
    private class BluetoothDevicePreferenceCallback implements CachedBluetoothDevice.Callback {

        @Override
        public void onDeviceAttributesChanged() {
        //只处理名字发生变化的情况,其他的不处理。
        if(nameChanged()){
            onPreferenceAttributesChanged();}
        }
    }

    private String mOldDeviceName;//构造方法里初始化

    private boolean nameChanged() {
        String currentName = mCachedDevice.getName();
        boolean same = TextUtils.equals(mOldDeviceName, currentName);
        if (!same) {
            mOldDeviceName = currentName;
        }
        return !same;
    }

2.BluetoothPairingDetail.java

public class BluetoothPairingDetail extends DeviceListPreferenceFragment implements
        Indexable {

2.1.getPreferenceScreenResId

    protected int getPreferenceScreenResId() {
        return R.xml.bluetooth_pairing_detail;
    }

>1.bluetooth_pairing_detail.xml

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:title="@string/bluetooth_pairing_pref_title">

    <Preference
        android:key="bt_pair_rename_devices"
        android:title="@string/bluetooth_device_name"
        android:summary="@string/summary_placeholder"
        settings:controller="com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController"/>
<!--蓝牙列表数据都是添加到这里的-->
    <com.android.settings.bluetooth.BluetoothProgressCategory
        android:key="available_devices"
        android:title="@string/bluetooth_paired_device_title"/>

    <com.android.settingslib.widget.FooterPreference/>

</PreferenceScreen>

2.2.onStart

    public void onStart() {
        super.onStart();
        if (mLocalManager == null){
            return;
        }
        updateBluetooth();//补充1
        //是否正在扫描中
        mAvailableDevicesCategory.setProgress(mBluetoothAdapter.isDiscovering());
    }

>1.updateBluetooth

    void updateBluetooth() {
        if (mBluetoothAdapter.isEnabled()) {
        //可用的话,更新数据
            updateContent(mBluetoothAdapter.getState());
        } else {//不可用的话,打开蓝牙
            mBluetoothAdapter.enable();
        }
    }

>2.updateContent

    void updateContent(int bluetoothState) {
        switch (bluetoothState) {
            case BluetoothAdapter.STATE_ON:
                mDevicePreferenceMap.clear();//清除缓存数据
                mBluetoothAdapter.enable();
//添加蓝牙设备列表,参考3.4
                addDeviceCategory(mAvailableDevicesCategory,
                        R.string.bluetooth_preference_found_media_devices,
                        BluetoothDeviceFilter.ALL_FILTER, mInitialScanStarted);
                        //底部提示文字处理
                updateFooterPreference(mFooterPreference);
                //这个就是个广播
                mAlwaysDiscoverable.start();
                enableScanning();//补充3
                break;

            case BluetoothAdapter.STATE_OFF:
                finish();//关闭页面
                break;
        }
    }

>3.enableScanning

    void enableScanning() {
        //初始化一次
        if (!mInitialScanStarted) {
        //首次初始化,清空数据
            if (mAvailableDevicesCategory != null) {
                removeAllDevices();
            }
            mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
            mInitialScanStarted = true;
        }
        super.enableScanning();
    }

2.3.onStop

    public void onStop() {
        super.onStop();
        if (mLocalManager == null){
            return;
        }
        //取消广播监听
        mAlwaysDiscoverable.stop();
        //断开连接
        disableScanning();
    }

3.DeviceListPreferenceFragment

public abstract class DeviceListPreferenceFragment extends
        RestrictedDashboardFragment implements BluetoothCallback {

3.1.构造方法

    private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
            "persist.bluetooth.showdeviceswithoutnames";

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLocalManager = Utils.getLocalBtManager(getActivity());
        if (mLocalManager == null) {
            return;
        }
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //默认是不显示没有名字的蓝牙设备的
        mShowDevicesWithoutNames = SystemProperties.getBoolean(
                BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false);

        initPreferencesFromPreferenceScreen();

        mDeviceListGroup = (PreferenceCategory) findPreference(getDeviceListKey());
    }

3.2.onStart

    public void onStart() {
        super.onStart();
        if (mLocalManager == null || isUiRestricted()) return;

        mLocalManager.setForegroundActivity(getActivity());
        //注册蓝牙相关的各种回调
        mLocalManager.getEventManager().registerCallback(this);
    }

3.3.onStop

    public void onStop() {
        super.onStop();
        if (mLocalManager == null || isUiRestricted()) {
            return;
        }

        removeAllDevices();//清除数据
        mLocalManager.setForegroundActivity(null);
        //取消注册
        mLocalManager.getEventManager().unregisterCallback(this);
    }

>1.removeAllDevices

    void removeAllDevices() {
        mDevicePreferenceMap.clear();
        mDeviceListGroup.removeAll();
    }

3.4.addDeviceCategory

    public void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
            BluetoothDeviceFilter.Filter filter, boolean addCachedDevices) {
        cacheRemoveAllPrefs(preferenceGroup);
        //默认的title被改了
        preferenceGroup.setTitle(titleId);
        mDeviceListGroup = preferenceGroup;
        //添加缓存数据
        if (addCachedDevices) {
            setFilter(BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER);
            addCachedDevices();
        }
        setFilter(filter);
        preferenceGroup.setEnabled(true);
        removeCachedPrefs(preferenceGroup);
    }

3.5.onDeviceAdded

  • 3.2注册的回调里有这个方法,发现新的设备后
    public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
        if (mDevicePreferenceMap.get(cachedDevice) != null) {
        //已经添加了
            return;
        }

        //蓝牙已经关闭了
        if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) return;

        if (mFilter.matches(cachedDevice.getDevice())) {
            ThreadUtils.postOnBackgroundThread(() -> createDevicePreference(cachedDevice));//补充1
        }
    }

>1.createDevicePreference

这里就是添加新的蓝牙设备选项

    void createDevicePreference(CachedBluetoothDevice cachedDevice) {
        if (mDeviceListGroup == null) {
            //容器还不存在
            return;
        }

        String key = cachedDevice.getDevice().getAddress();
        BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);

        if (preference == null) {
        //参考3.6
            preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice,
                    mShowDevicesWithoutNames, BluetoothDevicePreference.SortType.TYPE_FIFO);
            preference.setKey(key);
            
            preference.hideSecondTarget(true);
            //加入容器
            mDeviceListGroup.addPreference(preference);
        }

        initDevicePreference(preference);//空实现
        //放入缓存
        mDevicePreferenceMap.put(cachedDevice, preference);
    }

3.6.BluetoothDevicePreference

蓝牙设备选项用的preference

>1.onPreferenceAttributesChanged

    void onPreferenceAttributesChanged() {
//...
//没有名字可以显示标志为true,或者有名字 才可见
        setVisible(mShowDevicesWithoutNames || mCachedDevice.hasHumanReadableName());

        // This could affect ordering, so notify that
        if (mNeedNotifyHierarchyChanged) {
            notifyHierarchyChanged();
        }
    }

>2.BluetoothDevicePreferenceCallback

此回调参考小节8.1.1,蓝牙设备属性变化就会调用,有时候很频繁

    private class BluetoothDevicePreferenceCallback implements CachedBluetoothDevice.Callback {

        @Override
        public void onDeviceAttributesChanged() {
            onPreferenceAttributesChanged();
        }
    }

构造方法里注册的

        mCachedDevice = cachedDevice;
        //这里
        mCallback = new BluetoothDevicePreferenceCallback();
        mCachedDevice.registerCallback(mCallback);

3.7.enableScanning

    void enableScanning() {
        if (!mScanEnabled) {
            startScanning();//补充1
            mScanEnabled = true;
        }
    }

>1.startScanning

  • 蓝牙扫描一次是12s,参考3.9的回调。结束后会重新扫描
    void startScanning() {
        if (!mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.startDiscovery();
        }
    }

3.8.disableScanning

    void disableScanning() {
        if (mScanEnabled) {
            stopScanning();//补充1
            mScanEnabled = false;
        }
    }

>1.stopScanning

    void stopScanning() {
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
    }

3.9.onScanningStateChanged

  • ACTION_DISCOVERY_STARTED 的时候,回调为true
  • ACTION_DISCOVERY_FINISHED 的时候,回调为false
  • 所以每次扫描结束,就会重新开始扫描
    public void onScanningStateChanged(boolean started) {
        if (!started && mScanEnabled) {
            startScanning();//参考3.7.1
        }
    }

4.BluetoothAdapter

4.1.getDefaultAdapter

    public static synchronized BluetoothAdapter getDefaultAdapter() {
        if (sAdapter == null) {
            sAdapter = createAdapter(AttributionSource.myAttributionSource());
        }
        return sAdapter;
    }

>1.myAttributionSource

    public static @NonNull AttributionSource myAttributionSource() {

        final AttributionSource globalSource = ActivityThread.currentAttributionSource();
        if (globalSource != null) {
            return globalSource;
        }

        int uid = Process.myUid();
        if (uid == Process.ROOT_UID) {
            uid = Process.SYSTEM_UID;
        }
        try {
            return new AttributionSource.Builder(uid)
                .setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0])
                .build();
        } catch (Exception ignored) {
        }

        throw new IllegalStateException("Failed to resolve AttributionSource");
    }

4.2.isDiscovering

是否还在扫描中,

  • getSyncTimeout:超时时间是5s,参考BluetoothUtils.java
    public boolean isDiscovering() {
        if (getState() != STATE_ON) {//蓝牙未打开
            return false;
        }
        try {
            mServiceLock.readLock().lock();
            if (mService != null) {
                final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
                //参考4.3.1
                mService.isDiscovering(mAttributionSource, recv);
                //5.3,等待结果并返回
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false);
            }
        } catch (RemoteException | TimeoutException e) {
        } finally {
            mServiceLock.readLock().unlock();
        }
        return false;
    }

4.3.AdapterService.java

>1.isDiscovering

        public void isDiscovering(AttributionSource source, SynchronousResultReceiver receiver) {
            try {//参考5.1
                receiver.send(isDiscovering(source));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        private boolean isDiscovering(AttributionSource attributionSource) {
            AdapterService service = getService();
            if (service == null
                    || !callerIsSystemOrActiveOrManagedUser(service, TAG, "isDiscovering")
                    || !Utils.checkScanPermissionForDataDelivery(
                            service, attributionSource, "AdapterService isDiscovering")) {
                return false;
            }

            return service.mAdapterProperties.isDiscovering();
        }

>2.onCreate

    public void onCreate() {
        super.onCreate();
        initMetricsLogger();
        debugLog("onCreate()");
        mDeviceConfigListener.start();
        mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper());
        mRemoteDevices.init();
        clearDiscoveringPackages();
        mBinder = new AdapterServiceBinder(this);
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        //看这里
        mAdapterProperties = new AdapterProperties(this);

4.4.startDiscovery

    public boolean startDiscovery() {
        android.util.SeempLog.record(58);
        if (getState() != STATE_ON) {
            return false;
        }
        try {
            mServiceLock.readLock().lock();
            if (mService != null) {
                final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
                mService.startDiscovery(mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false);
            }
        } catch (RemoteException | TimeoutException e) {

        } finally {
            mServiceLock.readLock().unlock();
        }
        return false;
    }

4.5.cancelDiscovery

    public boolean cancelDiscovery() {
        if (getState() != STATE_ON) {
            return false;
        }
        try {
            mServiceLock.readLock().lock();
            if (mService != null) {
                final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
                mService.cancelDiscovery(mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false);
            }
        } catch (RemoteException | TimeoutException e) {

        } finally {
            mServiceLock.readLock().unlock();
        }
        return false;
    }

4.6.getScanMode

    public int getScanMode() {
        if (getState() != STATE_ON) {
            return SCAN_MODE_NONE;
        }
        try {
            mServiceLock.readLock().lock();
            if (mService != null) {
                SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
                mService.getScanMode(mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(SCAN_MODE_NONE);
            }
        } catch (TimeoutException e) {

        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } finally {
            mServiceLock.readLock().unlock();
        }
        return SCAN_MODE_NONE;
    }

5.SynchronousResultReceiver

5.1.send

    public void send(@Nullable T resultData) {
    //参考5.2
        complete(new Result<>(resultData));
    }

5.2.complete

    private void complete(Result<T> result) {
        if (mIsCompleted) {
            throw new IllegalStateException("Receiver has already been completed");
        }
        mIsCompleted = true;
        if (mLocal) {
            getFuture().complete(result);
        } else {
            final ISynchronousResultReceiver rr;
            synchronized (this) {
                rr = mReceiver;
            }
            if (rr != null) {
                try {
                    rr.send(result);
                } catch (RemoteException e) {
                }
            }
        }
    }

5.3.awaitResultNoInterrupt

    public @NonNull Result<T> awaitResultNoInterrupt(@NonNull Duration timeout)
            throws TimeoutException {
        final long startWaitNanoTime = SystemClock.elapsedRealtimeNanos();
        Duration remainingTime = timeout;
        while (!remainingTime.isNegative()) {
            try {
            //这种阻塞式的
                Result<T> result = getFuture().get(remainingTime.toMillis(), TimeUnit.MILLISECONDS);
                synchronized (sLock) {
                    releaseLocked();
                    return result;
                }
            } catch (ExecutionException e) {
                // This will NEVER happen.
                throw new AssertionError("Error receiving response", e);
            } catch (InterruptedException e) {
                remainingTime = timeout.minus(
                        Duration.ofNanos(SystemClock.elapsedRealtimeNanos() - startWaitNanoTime));
            }
        }
        synchronized (sLock) {
            releaseLocked();
        }
        throw new TimeoutException();
    }

6.BluetoothEventManager

蓝牙相关的广播都在这个类里注册监听的。

6.1.构造方法

    BluetoothEventManager(LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager, Context context,
            android.os.Handler handler, @Nullable UserHandle userHandle) {
        mLocalAdapter = adapter;
        mDeviceManager = deviceManager;
        mAdapterIntentFilter = new IntentFilter();
        mProfileIntentFilter = new IntentFilter();
        mHandlerMap = new HashMap<>();
        mContext = context;
        mUserHandle = userHandle;
        mReceiverHandler = handler;

        // Bluetooth on/off broadcasts
        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());//补充1
        // Generic connected/not broadcast
        addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
                new ConnectionStateChangedHandler());

        // Discovery broadcasts,参考补充2
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED,
                new ScanningStateChangedHandler(true));
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
                new ScanningStateChangedHandler(false));
                //补充3
        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
        //蓝牙名字或者别名改变,参考补充4
        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
        addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());

        // Pairing broadcasts,配对状态变化,补充5
        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());

>1.AdapterStateChangedHandler

蓝牙状态变化会走,比如打开关闭

    private class AdapterStateChangedHandler implements Handler {
        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                    BluetoothAdapter.ERROR);
            mLocalAdapter.setBluetoothStateInt(state);
            for (BluetoothCallback callback : mCallbacks) {
                callback.onBluetoothStateChanged(state);
            }
            mDeviceManager.onBluetoothStateChanged(state);
        }
    }

>2.ScanningStateChangedHandler

扫描开始,扫描结束会走这里

    private class ScanningStateChangedHandler implements Handler {
        private final boolean mStarted;

        ScanningStateChangedHandler(boolean started) {
            mStarted = started;
        }

        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
            for (BluetoothCallback callback : mCallbacks) {
                callback.onScanningStateChanged(mStarted);
            }
            mDeviceManager.onScanningStateChanged(mStarted);
        }
    }

>3.DeviceFoundHandler

扫描到设备后执行

    private class DeviceFoundHandler implements Handler {
        public void onReceive(Context context, Intent intent,
                BluetoothDevice device) {
            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
            String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
            final boolean isCoordinatedSetMember =
                    intent.getBooleanExtra(BluetoothDevice.EXTRA_IS_COORDINATED_SET_MEMBER, false);
            //参考7.1
            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
            if (cachedDevice == null) {
                cachedDevice = mDeviceManager.addDevice(device);//参考7.2
            } else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
                    && !cachedDevice.getDevice().isConnected()) {
                //已绑定,未连接的设备,直接回调处理
                dispatchDeviceAdded(cachedDevice);
            }
            cachedDevice.setRssi(rssi);
            cachedDevice.setJustDiscovered(true);
            cachedDevice.setIsCoordinatedSetMember(isCoordinatedSetMember);
        }
    }

>4.NameChangedHandler

蓝牙设备名字或者别名发生变化

    private class NameChangedHandler implements Handler {
        public void onReceive(Context context, Intent intent,
                BluetoothDevice device) {
            mDeviceManager.onDeviceNameUpdated(device);//参考7.3
        }
    }

>5.BondStateChangedHandler

蓝牙配对状态的变化

    private class BondStateChangedHandler implements Handler {
        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
            if (device == null) {
                return;
            }
            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
                    BluetoothDevice.ERROR);

            if (mDeviceManager.onBondStateChangedIfProcess(device, bondState)) {
                //设备的绑定状态更改在此函数中处理,并且不希望更新UI
                return;
            }

            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
            if (cachedDevice == null) {
                //缓存里没有的,加入缓存
                cachedDevice = mDeviceManager.addDevice(device);
            }

            if(bondState == BluetoothDevice.BOND_BONDED) {
                int groupId  = intent.getIntExtra(BluetoothDevice.EXTRA_GROUP_ID,
                        BluetoothDevice.ERROR);
                if (groupId != BluetoothDevice.ERROR && groupId >= 0) {
                    updateCacheDeviceInfo(groupId, cachedDevice);
                } else if (intent.getBooleanExtra(BluetoothDevice.EXTRA_IS_PRIVATE_ADDRESS,
                        false)) {
                    updateIgnoreDeviceFlag(cachedDevice);
                }
            }
            for (BluetoothCallback callback : mCallbacks) {
                callback.onDeviceBondStateChanged(cachedDevice, bondState);
            }
            cachedDevice.onBondingStateChanged(bondState);

            if (bondState == BluetoothDevice.BOND_NONE) {
                //看是否需要取消配对
                if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
                        || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                    mDeviceManager.onDeviceUnpaired(cachedDevice);
                }
                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
                        BluetoothDevice.ERROR);

                showUnbondMessage(context, cachedDevice.getName(), reason);
            }
        }

7.CachedBluetoothDeviceManager

7.1.CachedBluetoothDevice

就是看缓存里是否已有对应的device

    public synchronized CachedBluetoothDevice findDevice(BluetoothDevice device) {
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            if (cachedDevice.getDevice().equals(device)) {
            //缓存里已经有了,返回即可。
                return cachedDevice;
            }
            //检查子集是否有缓存的
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (!memberDevices.isEmpty()) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                    if (memberDevice.getDevice().equals(device)) {
                        return memberDevice;
                    }
                }
            }
            //检查子设备是否有助听器
            CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
            if (subDevice != null && subDevice.getDevice().equals(device)) {
                return subDevice;
            }
        }

        return null;
    }

7.2.addDevice

  • CSIP(Coordinated Set Identification Profile)是一种用于蓝牙LE Audio开发的必备文档
    public CachedBluetoothDevice addDevice(BluetoothDevice device) {
        CachedBluetoothDevice newDevice;
        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
        synchronized (this) {
            newDevice = findDevice(device);//验证下是否有旧的,参考7.1
            if (newDevice == null) {
                newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
                //
                mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
                //助听器
                mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
                既不是CSIP设备也不是助听器
                if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
                        && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
                    //那么加入缓存集合
                    mCachedDevices.add(newDevice);
                    //回调处理,参考3.5
                    mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
                }
            }
        }

        return newDevice;
    }

7.3.onDeviceNameUpdated

    public void onDeviceNameUpdated(BluetoothDevice device) {
        CachedBluetoothDevice cachedDevice = findDevice(device);
        if (cachedDevice != null) {
            cachedDevice.refreshName();
        }
    }

7.4.onDeviceDisappeared

蓝牙设备消失

    public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
        cachedDevice.setJustDiscovered(false);//8.5
        return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
    }

7.5.onScanningStateChanged

扫描状态变化

    public synchronized void onScanningStateChanged(boolean started) {
    //扫描结束不处理
        if (!started) return;
        //如果开始新的扫描,清除旧的可见性,反向迭代,因为设备可能被移除
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            cachedDevice.setJustDiscovered(false);//8.5
            //下边就是子设备,成员设备的处理
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (!memberDevices.isEmpty()) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                    memberDevice.setJustDiscovered(false);
                }
                return;
            }
            final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
            if (subDevice != null) {
                subDevice.setJustDiscovered(false);
            }
        }
    }

7.6.onBluetoothStateChanged

    public synchronized void onBluetoothStateChanged(int bluetoothState) {
        //当蓝牙关闭时,我们需要清除非绑定设备,否则,它们最终会出现在下一个BT启用中
        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
                final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
                if (!memberDevices.isEmpty()) {
                    for (CachedBluetoothDevice memberDevice : memberDevices) {
                        if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                            cachedDevice.removeMemberDevice(memberDevice);
                        }
                    }
                } else {
                    CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                    if (subDevice != null) {
                        if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                            cachedDevice.setSubDevice(null);
                        }
                    }
                }
                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                    cachedDevice.setJustDiscovered(false);//8.5
                    mCachedDevices.remove(i);
                }
                //Clear if there any Tws battery info on BT turning OFF
                cachedDevice.mTwspBatteryState = -1;
                cachedDevice.mTwspBatteryLevel = -1;
            }
        }
    }

8.CachedBluetoothDevice.java

8.1.refreshName

    void refreshName() {
        dispatchAttributesChanged();
    }

>1.dispatchAttributesChanged

蓝牙属性改变,进行回调。此方法调用的地方比较多

    void dispatchAttributesChanged() {
        for (Callback callback : mCallbacks) {
            callback.onDeviceAttributesChanged();
        }
    }

8.2.fillData

构造方法里调用

    private void fillData() {
        updateProfiles();
        fetchActiveDevices();
        migratePhonebookPermissionChoice();
        migrateMessagePermissionChoice();
        setLeAudioEnabled();
        dispatchAttributesChanged();//8.1.1
    }

8.3.setName

蓝牙名字发生变化调用

    public void setName(String name) {
        // Prevent getName() to be set to null if setName(null) is called
        if (name != null && !TextUtils.equals(name, getName())) {
            mDevice.setAlias(name);
            dispatchAttributesChanged();
        }
    }

8.4.refresh

连接设备的时候,绑定状态的变化等

    void refresh() {
        ThreadUtils.postOnBackgroundThread(() -> {
            if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
                Uri uri = BluetoothUtils.getUriMetaData(getDevice(),
                        BluetoothDevice.METADATA_MAIN_ICON);
                if (uri != null && mDrawableCache.get(uri.toString()) == null) {
                    mDrawableCache.put(uri.toString(),
                            (BitmapDrawable) BluetoothUtils.getBtDrawableWithDescription(
                                    mContext, this).first);
                }
            }

            ThreadUtils.postOnMainThread(() -> {
                dispatchAttributesChanged();
            });
        });
    }

8.5.setJustDiscovered

  • 蓝牙设备消失,开始扫描,蓝牙关闭会设置为false,参考7.4到7.6
  • 参考6.1.3,发现新设备后会设置为true
    public void setJustDiscovered(boolean justDiscovered) {
        if (mJustDiscovered != justDiscovered) {
            mJustDiscovered = justDiscovered;
            dispatchAttributesChanged();
        }
    }

8.6.onActiveDeviceChanged

    public void onActiveDeviceChanged(boolean isActive, int bluetoothProfile) {
        boolean changed = false;
        switch (bluetoothProfile) {
        case BluetoothProfile.A2DP:
            changed = (mIsActiveDeviceA2dp != isActive);
            mIsActiveDeviceA2dp = isActive;
            break;
        case BluetoothProfile.HEADSET:
            changed = (mIsActiveDeviceHeadset != isActive);
            mIsActiveDeviceHeadset = isActive;
            break;
        case BluetoothProfile.HEARING_AID:
            changed = (mIsActiveDeviceHearingAid != isActive);
            mIsActiveDeviceHearingAid = isActive;
            break;
        case BluetoothProfile.LE_AUDIO:
            changed = (mIsActiveDeviceLeAudio != isActive);
            mIsActiveDeviceLeAudio = isActive;
            break;
        default:

            break;
        }
        if (changed) {
            dispatchAttributesChanged();
        }
    }

8.7.onAudioModeChanged

    void onAudioModeChanged() {
        dispatchAttributesChanged();
    }

8.8.setRssi

    void setRssi(short rssi) {
        if (mRssi != rssi) {
            mRssi = rssi;
            dispatchAttributesChanged();
        }
    

8.9.onUuidChanged

    void onUuidChanged() {
        updateProfiles();
        ParcelUuid[] uuids = mDevice.getUuids();

        long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
        if (ArrayUtils.contains(uuids, BluetoothUuid.HOGP)) {
            timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
        } else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) {
            timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT;
        } else if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO)) {
            timeout = MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT;
        }

        if ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
            connectDevice();
        }

        dispatchAttributesChanged();
    }