android10 蓝牙(一)开关与扫描源码解析
蓝牙开关源码分析
xref: /packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEnabler.java
@Override
public boolean onSwitchToggled(boolean isChecked) {
if (maybeEnforceRestrictions()) {
triggerParentPreferenceCallback(isChecked);
return true;
}
// Show toast message if Bluetooth is not allowed in airplane mode
if (isChecked &&
!WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off
mSwitchController.setChecked(false);
triggerParentPreferenceCallback(false);
return false;
}
mMetricsFeatureProvider.action(mContext, mMetricsEvent, isChecked);
if (mBluetoothAdapter != null) {
boolean status = setBluetoothEnabled(isChecked);
// If we cannot toggle it ON then reset the UI assets:
// a) The switch should be OFF but it should still be togglable (enabled = True)
// b) The switch bar should have OFF text.
if (isChecked && !status) {
mSwitchController.setChecked(false);
mSwitchController.setEnabled(true);
mSwitchController.updateTitle(false);
triggerParentPreferenceCallback(false);
return false;
}
}
mSwitchController.setEnabled(false);
triggerParentPreferenceCallback(isChecked);
return true;
}
.........................................................................................
private boolean setBluetoothEnabled(boolean isEnabled) {
return isEnabled ? mBluetoothAdapter.enable() : mBluetoothAdapter.disable();
}
蓝牙开关封装在BluetoothEnabler.java中,实现了SwitchWidgetController.OnSwitchChangeListener监听,重写onSwitchToggled方法。在onSwitchToggled方法中调用setBluetoothEnabled方法,根据传入的boolean值打开蓝牙开关或者关闭蓝牙开关。
蓝牙扫描源码分析
xref: /frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context, Handler handler,
UserHandle userHandle) {
mContext = context.getApplicationContext();
mLocalAdapter = adapter;
mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, this);
mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mContext,
handler, userHandle);
mProfileManager = new LocalBluetoothProfileManager(mContext,
mLocalAdapter, mCachedDeviceManager, mEventManager);
mProfileManager.updateLocalProfiles();
mEventManager.readPairedDevices();
}
打开蓝牙开关后开启蓝牙扫描,调用LocalBluetoothManager方法,在构造方法中会创建BluetoothEventManager对象。
xref: /frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
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());
// Generic connected/not broadcast
addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
new ConnectionStateChangedHandler());
// Discovery broadcasts
addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());
// Pairing broadcasts
addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
// Fine-grained state broadcasts
addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
addHandler(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED, new BatteryLevelChangedHandler());
// Active device broadcasts
addHandler(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler());
addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler());
addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
new ActiveDeviceChangedHandler());
// Headset state changed broadcasts
addHandler(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
new AudioModeChangedHandler());
addHandler(TelephonyManager.ACTION_PHONE_STATE_CHANGED,
new AudioModeChangedHandler());
// ACL connection changed broadcasts
addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
registerAdapterIntentReceiver();
}
......................................................................................
void addHandler(String action, Handler handler) {
mHandlerMap.put(action, handler);
mAdapterIntentFilter.addAction(action);
}
........................................................................................
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);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
} else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&&!cachedDevice.getDevice().isConnected()) {
// Dispatch device add callback to show bonded but
// not connected devices in discovery mode
dispatchDeviceAdded(cachedDevice);
Log.d(TAG, "DeviceFoundHandler found bonded and not connected device:"
+ cachedDevice);
} else {
Log.d(TAG, "DeviceFoundHandler found existing CachedBluetoothDevice:"
+ cachedDevice);
}
cachedDevice.setRssi(rssi);
cachedDevice.setJustDiscovered(true);
}
}
........................................................................................
void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
synchronized (mCallbacks) {
for (BluetoothCallback callback : mCallbacks) {
callback.onDeviceAdded(cachedDevice);
}
}
}
将DeviceFoundHandler添加到addHandler中,DeviceFoundHandler方法中调用了dispatchDeviceAdded方法。在dispatchDeviceAdded会遍历所有的BluetoothCallback,回调onDeviceAdded方法。
xref: /packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@Override
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}
// Prevent updates while the list shows one of the state messages
if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) return;
if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
.........................................................................................
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
if (mDeviceListGroup == null) {
Log.w(TAG, "Trying to create a device preference before the list group/category "
+ "exists!");
return;
}
String key = cachedDevice.getDevice().getAddress();
BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);
if (preference == null) {
preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice,
mShowDevicesWithoutNames);
preference.setKey(key);
//Set hideSecondTarget is true if it's bonded device.
preference.hideSecondTarget(true);
mDeviceListGroup.addPreference(preference);
}
initDevicePreference(preference);
mDevicePreferenceMap.put(cachedDevice, preference);
}
在DeviceListPreferenceFragment.java的onDeviceAdded回调方法中会收到回调事件。调用createDevicePreference方法。在createDevicePreference方法中会将扫描到的蓝牙添加到mDeviceListGroup中,从而显示在界面上。
xref: /packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice,
boolean showDeviceWithoutNames) {
super(context, null);
mResources = getContext().getResources();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mShowDevicesWithoutNames = showDeviceWithoutNames;
if (sDimAlpha == Integer.MIN_VALUE) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
sDimAlpha = (int) (outValue.getFloat() * 255);
}
mCachedDevice = cachedDevice;
mCachedDevice.registerCallback(this);
onDeviceAttributesChanged();
}
..............................................................................................................
public void onDeviceAttributesChanged() {
/*
* The preference framework takes care of making sure the value has
* changed before proceeding. It will also call notifyChanged() if
* any preference info has changed from the previous value.
*/
setTitle(mCachedDevice.getName());
// Null check is done at the framework
setSummary(mCachedDevice.getConnectionSummary());
final Pair<Drawable, String> pair =
BluetoothUtils.getBtRainbowDrawableWithDescription(getContext(), mCachedDevice);
if (pair.first != null) {
setIcon(pair.first);
contentDescription = pair.second;
}
// Used to gray out the item
setEnabled(!mCachedDevice.isBusy());
// Device is only visible in the UI if it has a valid name besides MAC address or when user
// allows showing devices without user-friendly name in developer settings
setVisible(mShowDevicesWithoutNames || mCachedDevice.hasHumanReadableName());
// This could affect ordering, so notify that
if (mNeedNotifyHierarchyChanged) {
notifyHierarchyChanged();
}
}
在BluetoothDevicePreference类的onDeviceAttributesChanged方法中会设置标题、概述以及图标等。