Merge changes from topic "ha-new-pairing" into main
* changes: New hearing device pairing page (2/2): MFi devices New hearing device pairing page (1/2)
This commit is contained in:
@@ -36,9 +36,9 @@ import com.android.settingslib.search.SearchIndexable;
|
||||
/** Accessibility settings for hearing aids. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPreferenceFragment {
|
||||
|
||||
private static final String TAG = "AccessibilityHearingAidsFragment";
|
||||
private static final String KEY_HEARING_OPTIONS_CATEGORY = "hearing_options_category";
|
||||
public static final String KEY_HEARING_DEVICE_ADD_BT_DEVICES = "hearing_device_add_bt_devices";
|
||||
private static final int SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX = 20;
|
||||
private String mFeatureName;
|
||||
|
||||
|
||||
58
src/com/android/settings/accessibility/ArrowPreference.java
Normal file
58
src/com/android/settings/accessibility/ArrowPreference.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.TypedArrayUtils;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* A settings preference with colored rounded rectangle background and an arrow icon on the right
|
||||
*/
|
||||
public class ArrowPreference extends Preference {
|
||||
|
||||
public ArrowPreference(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ArrowPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, TypedArrayUtils.getAttr(context,
|
||||
androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle));
|
||||
}
|
||||
|
||||
public ArrowPreference(@NonNull Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public ArrowPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayoutResource(R.layout.arrow_preference);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.bluetooth.le.BluetoothLeScanner;
|
||||
import android.bluetooth.le.ScanCallback;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.bluetooth.le.ScanRecord;
|
||||
import android.bluetooth.le.ScanResult;
|
||||
import android.bluetooth.le.ScanSettings;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothDevicePreference;
|
||||
import com.android.settings.bluetooth.BluetoothProgressCategory;
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.HearingAidInfo;
|
||||
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This fragment shows all scanned hearing devices through BLE scanning. Users can
|
||||
* pair them in this page.
|
||||
*/
|
||||
public class HearingDevicePairingFragment extends RestrictedDashboardFragment implements
|
||||
BluetoothCallback {
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
private static final String TAG = "HearingDevicePairingFragment";
|
||||
private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
|
||||
"persist.bluetooth.showdeviceswithoutnames";
|
||||
private static final String KEY_AVAILABLE_HEARING_DEVICES = "available_hearing_devices";
|
||||
|
||||
LocalBluetoothManager mLocalManager;
|
||||
@Nullable
|
||||
BluetoothAdapter mBluetoothAdapter;
|
||||
@Nullable
|
||||
CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
|
||||
private boolean mShowDevicesWithoutNames;
|
||||
@Nullable
|
||||
private BluetoothProgressCategory mAvailableHearingDeviceGroup;
|
||||
|
||||
@Nullable
|
||||
BluetoothDevice mSelectedDevice;
|
||||
final List<BluetoothDevice> mSelectedDeviceList = new ArrayList<>();
|
||||
final List<BluetoothGatt> mConnectingGattList = new ArrayList<>();
|
||||
final Map<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
|
||||
new HashMap<>();
|
||||
|
||||
private List<ScanFilter> mLeScanFilters;
|
||||
|
||||
public HearingDevicePairingFragment() {
|
||||
super(DISALLOW_CONFIG_BLUETOOTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mLocalManager = Utils.getLocalBtManager(getActivity());
|
||||
if (mLocalManager == null) {
|
||||
Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
return;
|
||||
}
|
||||
mBluetoothAdapter = getSystemService(BluetoothManager.class).getAdapter();
|
||||
mCachedDeviceManager = mLocalManager.getCachedDeviceManager();
|
||||
mShowDevicesWithoutNames = SystemProperties.getBoolean(
|
||||
BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false);
|
||||
|
||||
initPreferencesFromPreferenceScreen();
|
||||
initHearingDeviceLeScanFilters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
use(ViewAllBluetoothDevicesPreferenceController.class).init(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (mLocalManager == null || mBluetoothAdapter == null || isUiRestricted()) {
|
||||
return;
|
||||
}
|
||||
mLocalManager.setForegroundActivity(getActivity());
|
||||
mLocalManager.getEventManager().registerCallback(this);
|
||||
if (mBluetoothAdapter.isEnabled()) {
|
||||
startScanning();
|
||||
} else {
|
||||
// Turn on bluetooth if it is disabled
|
||||
mBluetoothAdapter.enable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (mLocalManager == null || isUiRestricted()) {
|
||||
return;
|
||||
}
|
||||
stopScanning();
|
||||
removeAllDevices();
|
||||
for (BluetoothGatt gatt: mConnectingGattList) {
|
||||
gatt.disconnect();
|
||||
}
|
||||
mLocalManager.setForegroundActivity(null);
|
||||
mLocalManager.getEventManager().unregisterCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
if (preference instanceof BluetoothDevicePreference) {
|
||||
stopScanning();
|
||||
BluetoothDevicePreference devicePreference = (BluetoothDevicePreference) preference;
|
||||
mSelectedDevice = devicePreference.getCachedDevice().getDevice();
|
||||
if (mSelectedDevice != null) {
|
||||
mSelectedDeviceList.add(mSelectedDevice);
|
||||
}
|
||||
devicePreference.onClicked();
|
||||
return true;
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDeleted(@NonNull CachedBluetoothDevice cachedDevice) {
|
||||
removeDevice(cachedDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBluetoothStateChanged(int bluetoothState) {
|
||||
switch (bluetoothState) {
|
||||
case BluetoothAdapter.STATE_ON:
|
||||
startScanning();
|
||||
showBluetoothTurnedOnToast();
|
||||
break;
|
||||
case BluetoothAdapter.STATE_OFF:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceBondStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
|
||||
int bondState) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onDeviceBondStateChanged: " + cachedDevice.getName() + ", state = "
|
||||
+ bondState);
|
||||
}
|
||||
if (bondState == BluetoothDevice.BOND_BONDED) {
|
||||
// If one device is connected(bonded), then close this fragment.
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
return;
|
||||
} else if (bondState == BluetoothDevice.BOND_BONDING) {
|
||||
// Set the bond entry where binding process starts for logging hearing aid device info
|
||||
final int pageId = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
|
||||
.getAttribution(getActivity());
|
||||
final int bondEntry = AccessibilityStatsLogUtils.convertToHearingAidInfoBondEntry(
|
||||
pageId);
|
||||
HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
|
||||
}
|
||||
if (mSelectedDevice != null) {
|
||||
BluetoothDevice device = cachedDevice.getDevice();
|
||||
if (mSelectedDevice.equals(device) && bondState == BluetoothDevice.BOND_NONE) {
|
||||
// If current selected device failed to bond, restart scanning
|
||||
startScanning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
|
||||
int state, int bluetoothProfile) {
|
||||
// This callback is used to handle the case that bonded device is connected in pairing list.
|
||||
// 1. If user selected multiple bonded devices in pairing list, after connected
|
||||
// finish this page.
|
||||
// 2. If the bonded devices auto connected in paring list, after connected it will be
|
||||
// removed from paring list.
|
||||
if (cachedDevice.isConnected()) {
|
||||
final BluetoothDevice device = cachedDevice.getDevice();
|
||||
if (device != null && mSelectedDeviceList.contains(device)) {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
} else {
|
||||
removeDevice(cachedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.HEARING_AID_PAIRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.hearing_device_pairing_fragment;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
void addDevice(CachedBluetoothDevice cachedDevice) {
|
||||
if (mBluetoothAdapter == null) {
|
||||
return;
|
||||
}
|
||||
// Do not create new preference while the list shows one of the state messages
|
||||
if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
|
||||
return;
|
||||
}
|
||||
if (mDevicePreferenceMap.get(cachedDevice) != null) {
|
||||
return;
|
||||
}
|
||||
String key = cachedDevice.getDevice().getAddress();
|
||||
BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);
|
||||
if (preference == null) {
|
||||
preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice,
|
||||
mShowDevicesWithoutNames, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
||||
preference.setKey(key);
|
||||
preference.hideSecondTarget(true);
|
||||
}
|
||||
if (mAvailableHearingDeviceGroup != null) {
|
||||
mAvailableHearingDeviceGroup.addPreference(preference);
|
||||
}
|
||||
mDevicePreferenceMap.put(cachedDevice, preference);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Add device. device: " + cachedDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void removeDevice(CachedBluetoothDevice cachedDevice) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "removeDevice: " + cachedDevice);
|
||||
}
|
||||
BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
|
||||
if (mAvailableHearingDeviceGroup != null && preference != null) {
|
||||
mAvailableHearingDeviceGroup.removePreference(preference);
|
||||
}
|
||||
}
|
||||
|
||||
void startScanning() {
|
||||
if (mCachedDeviceManager != null) {
|
||||
mCachedDeviceManager.clearNonBondedDevices();
|
||||
}
|
||||
removeAllDevices();
|
||||
startLeScanning();
|
||||
}
|
||||
|
||||
void stopScanning() {
|
||||
stopLeScanning();
|
||||
}
|
||||
|
||||
private final ScanCallback mLeScanCallback = new ScanCallback() {
|
||||
@Override
|
||||
public void onScanResult(int callbackType, ScanResult result) {
|
||||
handleLeScanResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatchScanResults(List<ScanResult> results) {
|
||||
for (ScanResult result: results) {
|
||||
handleLeScanResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanFailed(int errorCode) {
|
||||
Log.w(TAG, "BLE Scan failed with error code " + errorCode);
|
||||
}
|
||||
};
|
||||
|
||||
void handleLeScanResult(ScanResult result) {
|
||||
if (mCachedDeviceManager == null) {
|
||||
return;
|
||||
}
|
||||
final BluetoothDevice device = result.getDevice();
|
||||
CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
cachedDevice = mCachedDeviceManager.addDevice(device);
|
||||
}
|
||||
if (cachedDevice.getHearingAidInfo() == null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Set hearing aid info on device: " + cachedDevice);
|
||||
}
|
||||
cachedDevice.setHearingAidInfo(new HearingAidInfo.Builder().build());
|
||||
}
|
||||
// No need to handle the device if the device is already in the list or discovering services
|
||||
if (mDevicePreferenceMap.get(cachedDevice) == null
|
||||
&& mConnectingGattList.stream().noneMatch(
|
||||
gatt -> gatt.getDevice().equals(device))) {
|
||||
if (isAndroidCompatibleHearingAid(result)) {
|
||||
addDevice(cachedDevice);
|
||||
} else {
|
||||
discoverServices(cachedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startLeScanning() {
|
||||
if (mBluetoothAdapter == null) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "startLeScanning");
|
||||
}
|
||||
final BluetoothLeScanner leScanner = mBluetoothAdapter.getBluetoothLeScanner();
|
||||
if (leScanner == null) {
|
||||
Log.w(TAG, "LE scanner not found, cannot start LE scanning");
|
||||
} else {
|
||||
final ScanSettings settings = new ScanSettings.Builder()
|
||||
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||
.setLegacy(false)
|
||||
.build();
|
||||
leScanner.startScan(mLeScanFilters, settings, mLeScanCallback);
|
||||
if (mAvailableHearingDeviceGroup != null) {
|
||||
mAvailableHearingDeviceGroup.setProgress(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stopLeScanning() {
|
||||
if (mBluetoothAdapter == null) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "stopLeScanning");
|
||||
}
|
||||
final BluetoothLeScanner leScanner = mBluetoothAdapter.getBluetoothLeScanner();
|
||||
if (leScanner != null) {
|
||||
leScanner.stopScan(mLeScanCallback);
|
||||
if (mAvailableHearingDeviceGroup != null) {
|
||||
mAvailableHearingDeviceGroup.setProgress(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAllDevices() {
|
||||
mDevicePreferenceMap.clear();
|
||||
if (mAvailableHearingDeviceGroup != null) {
|
||||
mAvailableHearingDeviceGroup.removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
void initPreferencesFromPreferenceScreen() {
|
||||
mAvailableHearingDeviceGroup = findPreference(KEY_AVAILABLE_HEARING_DEVICES);
|
||||
}
|
||||
|
||||
private void initHearingDeviceLeScanFilters() {
|
||||
mLeScanFilters = new ArrayList<>();
|
||||
// Filters for ASHA hearing aids
|
||||
mLeScanFilters.add(
|
||||
new ScanFilter.Builder().setServiceUuid(BluetoothUuid.HEARING_AID).build());
|
||||
mLeScanFilters.add(new ScanFilter.Builder()
|
||||
.setServiceData(BluetoothUuid.HEARING_AID, new byte[0]).build());
|
||||
// Filters for LE audio hearing aids
|
||||
mLeScanFilters.add(new ScanFilter.Builder().setServiceUuid(BluetoothUuid.HAS).build());
|
||||
mLeScanFilters.add(new ScanFilter.Builder()
|
||||
.setServiceData(BluetoothUuid.HAS, new byte[0]).build());
|
||||
// Filters for MFi hearing aids
|
||||
mLeScanFilters.add(new ScanFilter.Builder().setServiceUuid(BluetoothUuid.MFI_HAS).build());
|
||||
mLeScanFilters.add(new ScanFilter.Builder()
|
||||
.setServiceData(BluetoothUuid.MFI_HAS, new byte[0]).build());
|
||||
}
|
||||
|
||||
boolean isAndroidCompatibleHearingAid(ScanResult scanResult) {
|
||||
ScanRecord scanRecord = scanResult.getScanRecord();
|
||||
if (scanRecord == null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Scan record is null, not compatible with Android. device: "
|
||||
+ scanResult.getDevice());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
List<ParcelUuid> uuids = scanRecord.getServiceUuids();
|
||||
if (uuids != null) {
|
||||
if (uuids.contains(BluetoothUuid.HEARING_AID) || uuids.contains(BluetoothUuid.HAS)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Scan record uuid matched, compatible with Android. device: "
|
||||
+ scanResult.getDevice());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (scanRecord.getServiceData(BluetoothUuid.HEARING_AID) != null
|
||||
|| scanRecord.getServiceData(BluetoothUuid.HAS) != null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Scan record service data matched, compatible with Android. device: "
|
||||
+ scanResult.getDevice());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Scan record mismatched, not compatible with Android. device: "
|
||||
+ scanResult.getDevice());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void discoverServices(CachedBluetoothDevice cachedDevice) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "connectGattToCheckCompatibility, device: " + cachedDevice);
|
||||
}
|
||||
BluetoothGatt gatt = cachedDevice.getDevice().connectGatt(getContext(), false,
|
||||
new BluetoothGattCallback() {
|
||||
@Override
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status,
|
||||
int newState) {
|
||||
super.onConnectionStateChange(gatt, status, newState);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onConnectionStateChange, status: " + status + ", newState: "
|
||||
+ newState + ", device: " + cachedDevice);
|
||||
}
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
gatt.discoverServices();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
|
||||
super.onServicesDiscovered(gatt, status);
|
||||
boolean isCompatible = gatt.getService(BluetoothUuid.HEARING_AID.getUuid())
|
||||
!= null
|
||||
|| gatt.getService(BluetoothUuid.HAS.getUuid()) != null;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"onServicesDiscovered, compatible with Android: " + isCompatible
|
||||
+ ", device: " + cachedDevice);
|
||||
}
|
||||
if (isCompatible) {
|
||||
addDevice(cachedDevice);
|
||||
}
|
||||
}
|
||||
});
|
||||
mConnectingGattList.add(gatt);
|
||||
}
|
||||
|
||||
void showBluetoothTurnedOnToast() {
|
||||
Toast.makeText(getContext(), R.string.connected_device_bluetooth_turned_on_toast,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public final class BluetoothDevicePreference extends GearPreference {
|
||||
return R.layout.preference_widget_gear;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice getCachedDevice() {
|
||||
public CachedBluetoothDevice getCachedDevice() {
|
||||
return mCachedDevice;
|
||||
}
|
||||
|
||||
@@ -362,7 +362,11 @@ public final class BluetoothDevicePreference extends GearPreference {
|
||||
}
|
||||
}
|
||||
|
||||
void onClicked() {
|
||||
/**
|
||||
* Performs different actions according to the device connected and bonded state after
|
||||
* clicking on the preference.
|
||||
*/
|
||||
public void onClicked() {
|
||||
Context context = getContext();
|
||||
int bondState = mCachedDevice.getBondState();
|
||||
|
||||
|
||||
@@ -29,8 +29,10 @@ import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.HearingDevicePairingDetail;
|
||||
import com.android.settings.accessibility.HearingDevicePairingFragment;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HearingAidInfo;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
@@ -123,8 +125,11 @@ public class HearingAidPairingDialogFragment extends InstrumentedDialogFragment
|
||||
final int launchPage = getArguments().getInt(KEY_LAUNCH_PAGE);
|
||||
final boolean launchFromA11y = (launchPage == SettingsEnums.ACCESSIBILITY)
|
||||
|| (launchPage == SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
|
||||
final String a11yDestination = Flags.newHearingDevicePairingPage()
|
||||
? HearingDevicePairingFragment.class.getName()
|
||||
: HearingDevicePairingDetail.class.getName();
|
||||
final String destination = launchFromA11y
|
||||
? HearingDevicePairingDetail.class.getName()
|
||||
? a11yDestination
|
||||
: BluetoothPairingDetail.class.getName();
|
||||
new SubSettingLauncher(getActivity())
|
||||
.setDestination(destination)
|
||||
|
||||
@@ -15,18 +15,25 @@
|
||||
*/
|
||||
package com.android.settings.connecteddevice;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityHearingAidsFragment.KEY_HEARING_DEVICE_ADD_BT_DEVICES;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.HearingDevicePairingDetail;
|
||||
import com.android.settings.accessibility.HearingDevicePairingFragment;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
@@ -75,6 +82,21 @@ public class AddDevicePreferenceController extends BasePreferenceController
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (TextUtils.equals(preference.getKey(), KEY_HEARING_DEVICE_ADD_BT_DEVICES)) {
|
||||
String destination = Flags.newHearingDevicePairingPage()
|
||||
? HearingDevicePairingFragment.class.getName()
|
||||
: HearingDevicePairingDetail.class.getName();
|
||||
new SubSettingLauncher(preference.getContext())
|
||||
.setDestination(destination)
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.launch();
|
||||
return true;
|
||||
}
|
||||
return super.handlePreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
|
||||
|
||||
Reference in New Issue
Block a user