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

Commit a6a7e029 authored by Angela Wang's avatar Angela Wang Committed by Android (Google) Code Review
Browse files

Merge "Shows LE audio hearing aid device in a11y settings page (3/3)"

parents 6e242c29 e7a4b1f1
Loading
Loading
Loading
Loading
+76 −53
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.settings.accessibility;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -41,6 +43,7 @@ import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HapClientProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -48,9 +51,12 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.stream.Collectors;

/**
 * Controller that shows and updates the bluetooth device name
@@ -64,23 +70,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
    private final BroadcastReceiver mHearingAidChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
                final int state = intent.getIntExtra(BluetoothHearingAid.EXTRA_STATE,
                        BluetoothHearingAid.STATE_DISCONNECTED);
                if (state == BluetoothHearingAid.STATE_CONNECTED) {
            updateState(mHearingAidPreference);
                } else {
                    mHearingAidPreference
                            .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
                }
            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                        BluetoothAdapter.ERROR);
                if (state != BluetoothAdapter.STATE_ON) {
                    mHearingAidPreference
                            .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
                }
            }
        }
    };

@@ -107,18 +97,25 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC

    @Override
    public int getAvailabilityStatus() {
        return isHearingAidProfileSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
        return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
    }

    @Override
    public void onStart() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        mContext.registerReceiver(mHearingAidChangedReceiver, filter);
        mLocalBluetoothManager.getEventManager().registerCallback(this);
        // Can't get connected hearing aids when hearing aids related profiles are not ready. The
        // profiles will be ready after the services are connected. Needs to add listener and
        // updates the information when all hearing aids related services are connected.
        if (isAnyHearingAidRelatedProfilesNotReady()) {
            mProfileManager.addServiceListener(this);
        }
    }

    @Override
    public void onStop() {
@@ -143,6 +140,9 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC

    @Override
    public CharSequence getSummary() {
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
        }
        final CachedBluetoothDevice device = getConnectedHearingAidDevice();
        if (device == null) {
            return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
@@ -150,26 +150,39 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC

        final int connectedNum = getConnectedHearingAidDeviceNum();
        final CharSequence name = device.getName();
        final int side = device.getDeviceSide();
        final CachedBluetoothDevice subDevice = device.getSubDevice();
        if (connectedNum > 1) {
            return mContext.getString(R.string.accessibility_hearingaid_more_device_summary, name);
        }

        // Check if another side of LE audio hearing aid is connected as a pair
        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
        if (memberDevices.stream().anyMatch(m -> m.isConnected())) {
            return mContext.getString(
                    R.string.accessibility_hearingaid_left_and_right_side_device_summary,
                    name);
        }

        // Check if another side of ASHA hearing aid is connected as a pair
        final CachedBluetoothDevice subDevice = device.getSubDevice();
        if (subDevice != null && subDevice.isConnected()) {
            return mContext.getString(
                    R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
        }
        if (side == HearingAidProfile.DeviceSide.SIDE_INVALID) {

        final int side = device.getDeviceSide();
        if (side == HearingAidProfile.DeviceSide.SIDE_LEFT) {
            return mContext.getString(
                    R.string.accessibility_hearingaid_left_side_device_summary, name);
        } else if (side == HearingAidProfile.DeviceSide.SIDE_RIGHT) {
            return mContext.getString(
                    R.string.accessibility_hearingaid_active_device_summary, name);
        }
        return (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
                ? mContext.getString(
                        R.string.accessibility_hearingaid_left_side_device_summary, name)
                : mContext.getString(
                    R.string.accessibility_hearingaid_right_side_device_summary, name);
        }

        // Invalid side
        return mContext.getString(
                R.string.accessibility_hearingaid_active_device_summary, name);
    }

    @Override
    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
        if (activeDevice == null) {
@@ -183,10 +196,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC

    @Override
    public void onServiceConnected() {
        // Every registered ProfileService will callback. So we need to use isProfileReady() to
        // check is the HearingAidService callback here, not other service.
        // When hearing aids service connected, updating the UI.
        if (mProfileManager.getHearingAidProfile().isProfileReady()) {
        if (!isAnyHearingAidRelatedProfilesNotReady()) {
            updateState(mHearingAidPreference);
            mProfileManager.removeServiceListener(this);
        }
@@ -203,38 +213,51 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC

    @VisibleForTesting
    CachedBluetoothDevice getConnectedHearingAidDevice() {
        if (!isHearingAidProfileSupported()) {
            return null;
        }

        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
        final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
        for (BluetoothDevice obj : deviceList) {
            if (!mCachedDeviceManager.isSubDevice(obj)) {
                return mCachedDeviceManager.findDevice(obj);
            }
        }
        return null;
        final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
        return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
    }

    private int getConnectedHearingAidDeviceNum() {
        if (!isHearingAidProfileSupported()) {
            return 0;
        return getConnectedHearingAidDeviceList().size();
    }

    private List<BluetoothDevice> getConnectedHearingAidDeviceList() {
        if (!isHearingAidSupported()) {
            return new ArrayList<>();
        }
        final List<BluetoothDevice> deviceList = new ArrayList<>();
        final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
        if (hapClientProfile != null) {
            deviceList.addAll(hapClientProfile.getConnectedDevices());
        }
        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
        final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
        return (int) deviceList.stream()
                .filter(device -> !mCachedDeviceManager.isSubDevice(device))
                .count();
        if (hearingAidProfile != null) {
            deviceList.addAll(hearingAidProfile.getConnectedDevices());
        }
        return deviceList.stream()
                .distinct()
                .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
    }

    private boolean isHearingAidProfileSupported() {
    private boolean isHearingAidSupported() {
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            return false;
        }
        final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
        return supportedList.contains(BluetoothProfile.HEARING_AID);
        return supportedList.contains(BluetoothProfile.HEARING_AID)
                || supportedList.contains(BluetoothProfile.HAP_CLIENT);
    }

    private boolean isAnyHearingAidRelatedProfilesNotReady() {
        HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
        if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
            return true;
        }
        HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
        if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
            return true;
        }
        return false;
    }

    private LocalBluetoothManager getLocalBluetoothManager() {
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ public final class HearingAidUtils {
     */
    public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
            @NonNull CachedBluetoothDevice device) {
        if (device.isConnectedHearingAidDevice()
        if (device.isConnectedAshaHearingAidDevice()
                && device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
                && device.getSubDevice() == null) {
            launchHearingAidPairingDialogInternal(fragmentManager, device);
+1 −1
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater
            }
            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
            // It would show in Available Devices group.
            if (cachedDevice.isConnectedHearingAidDevice()
            if (cachedDevice.isConnectedAshaHearingAidDevice()
                    || cachedDevice.isConnectedLeAudioDevice()) {
                Log.d(TAG, "isFilterMatched() device : " +
                        cachedDevice.getName() + ", the profile is connected.");
+2 −2
Original line number Diff line number Diff line
@@ -107,12 +107,12 @@ public class BluetoothDetailsPairOtherController extends BluetoothDetailsControl
    }

    private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
        if (!cachedDevice.isConnectedHearingAidDevice()) {
        if (!cachedDevice.isConnectedAshaHearingAidDevice()) {
            return false;
        }

        final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
        if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
        if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
            return false;
        }

+1 −1
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
            }
            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
            // It would not show in Connected Devices group.
            if (cachedDevice.isConnectedHearingAidDevice()
            if (cachedDevice.isConnectedAshaHearingAidDevice()
                    || cachedDevice.isConnectedLeAudioDevice()) {
                return false;
            }
Loading