xref: /packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
startScanning();
return true;
}
if (preference instanceof BluetoothDevicePreference) {
BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
CachedBluetoothDevice device = btPreference.getCachedDevice();
mSelectedDevice = device.getDevice();
onDevicePreferenceClick(btPreference);
return true;
}
return super.onPreferenceTreeClick(preference);
}
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
btPreference.onClicked();
}
当点击蓝牙连接的时候会执行onPreferenceTreeClick方法,判断preference是不是BluetoothDevicePreference类型,如果是就执行onDevicePreferenceClick方法,调用BluetoothDevicePreference.java里面的onClicked方法。
xref: /packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
void onClicked() {
Context context = getContext();
int bondState = mCachedDevice.getBondState();
final MetricsFeatureProvider metricsFeatureProvider =
FeatureFactory.getFactory(context).getMetricsFeatureProvider();
if (mCachedDevice.isConnected()) {
metricsFeatureProvider.action(context,
SettingsEnums.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
metricsFeatureProvider.action(context,
SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT);
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
metricsFeatureProvider.action(context,
SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR);
if (!mCachedDevice.hasHumanReadableName()) {
metricsFeatureProvider.action(context,
SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
}
pair();
}
}
先判断配对状态,如果蓝牙已经配对了就调用CachedBluetoothDevice.java中的connect方法。
xref: /frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
public void connect(boolean connectAllProfiles) {
if (!ensurePaired()) {
return;
}
mConnectAttempted = SystemClock.elapsedRealtime();
connectWithoutResettingTimer(connectAllProfiles);
}
.........................................................................................
private void connectWithoutResettingTimer(boolean connectAllProfiles) {
synchronized (mProfileLock) {
// Try to initialize the profiles if they were not.
if (mProfiles.isEmpty()) {
// if mProfiles is empty, then do not invoke updateProfiles. This causes a race
// condition with carkits during pairing, wherein RemoteDevice.UUIDs have been
// updated from bluetooth stack but ACTION.uuid is not sent yet.
// Eventually ACTION.uuid will be received which shall trigger the connection of the
// various profiles
// If UUIDs are not available yet, connect will be happen
// upon arrival of the ACTION_UUID intent.
Log.d(TAG, "No profiles. Maybe we will connect later for device " + mDevice);
return;
}
int preferredProfiles = 0;
for (LocalBluetoothProfile profile : mProfiles) {
if (connectAllProfiles ? profile.accessProfileEnabled()
: profile.isAutoConnectable()) {
if (profile.isPreferred(mDevice)) {
++preferredProfiles;
connectInt(profile);
}
}
}
if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
if (preferredProfiles == 0) {
connectAutoConnectableProfiles();
}
}
}
.........................................................................................
synchronized void connectInt(LocalBluetoothProfile profile) {
if (!ensurePaired()) {
return;
}
if (profile.connect(mDevice)) {
if (BluetoothUtils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
return;
}
Log.i(TAG, "Failed to connect " + profile.toString() + " to " + getName());
}
这里会调用profile的connect方法进行连接,这里以PanProfile为例进行分析。
xref: /frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
public boolean connect(BluetoothDevice device) {
if (mService == null) return false;
List<BluetoothDevice> sinks = mService.getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
mService.disconnect(sink);
}
}
return mService.connect(device);
}
调用BluetoothPan.java中的connect方法
xref: /frameworks/base/core/java/android/bluetooth/BluetoothPan.java
@UnsupportedAppUsage
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
try {
return service.connect(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
}
}
if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
调用PanService中的connect方法
xref: /packages/apps/Bluetooth/src/com/android/bluetooth/pan/PanService.java
public boolean connect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
Log.e(TAG, "Pan Device not disconnected: " + device);
return false;
}
Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device);
mHandler.sendMessage(msg);
return true;
}
.........................................................................................
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_CONNECT: {
BluetoothDevice device = (BluetoothDevice) msg.obj;
if (!connectPanNative(Utils.getByteAddress(device),
BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) {
handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING,
BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE);
handlePanDeviceStateChange(device, null,
BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
BluetoothPan.REMOTE_NAP_ROLE);
break;
}
}
break;
case MESSAGE_DISCONNECT: {
BluetoothDevice device = (BluetoothDevice) msg.obj;
if (!disconnectPanNative(Utils.getByteAddress(device))) {
handlePanDeviceStateChange(device, mPanIfName,
BluetoothProfile.STATE_DISCONNECTING, BluetoothPan.LOCAL_PANU_ROLE,
BluetoothPan.REMOTE_NAP_ROLE);
handlePanDeviceStateChange(device, mPanIfName,
BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
BluetoothPan.REMOTE_NAP_ROLE);
break;
}
}
break;
case MESSAGE_CONNECT_STATE_CHANGED: {
ConnectState cs = (ConnectState) msg.obj;
BluetoothDevice device = getDevice(cs.addr);
// TBD get iface from the msg
if (DBG) {
Log.d(TAG,
"MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state);
}
handlePanDeviceStateChange(device, mPanIfName /* iface */,
convertHalState(cs.state), cs.local_role, cs.remote_role);
}
break;
}
}
};
......................................................................................
private native boolean connectPanNative(byte[] btAddress, int localRole, int remoteRole);
通过handler向handleMessage发送MESSAGE_CONNECT消息。在handleMessage中调用connectPanNative方法,connectPanNative是个native方法。
xref: /packages/apps/Bluetooth/jni/com_android_bluetooth_pan.cpp
static jboolean connectPanNative(JNIEnv* env, jobject object,
jbyteArray address, jint src_role,
jint dest_role) {
debug("in");
if (!sPanIf) return JNI_FALSE;
jbyte* addr = env->GetByteArrayElements(address, NULL);
if (!addr) {
error("Bluetooth device address null");
return JNI_FALSE;
}
jboolean ret = JNI_TRUE;
bt_status_t status = sPanIf->connect((RawAddress*)addr, src_role, dest_role);
if (status != BT_STATUS_SUCCESS) {
error("Failed PAN channel connection, status: %d", status);
ret = JNI_FALSE;
}
env->ReleaseByteArrayElements(address, addr, 0);
return ret;
}
sPanIf它的实现是在MTK封装的蓝牙库中,连接完毕后会返回连接的信息。
xref: /packages/apps/Bluetooth/src/com/android/bluetooth/pan/PanService.java
void handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int localRole,
int remoteRole) {
if (DBG) {
Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface
+ ", state: " + state + ", localRole:" + localRole + ", remoteRole:"
+ remoteRole);
}
int prevState;
BluetoothPanDevice panDevice = mPanDevices.get(device);
if (panDevice == null) {
Log.i(TAG, "state " + state + " Num of connected pan devices: " + mPanDevices.size());
prevState = BluetoothProfile.STATE_DISCONNECTED;
panDevice = new BluetoothPanDevice(state, iface, localRole, remoteRole);
mPanDevices.put(device, panDevice);
} else {
prevState = panDevice.mState;
panDevice.mState = state;
panDevice.mLocalRole = localRole;
panDevice.mRemoteRole = remoteRole;
panDevice.mIface = iface;
}
// Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we
// are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original
// connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and
// changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect
// will fail until the caller explicitly calls BluetoothPan#disconnect.
if (prevState == BluetoothProfile.STATE_DISCONNECTED
&& state == BluetoothProfile.STATE_DISCONNECTING) {
Log.d(TAG, "Ignoring state change from " + prevState + " to " + state);
mPanDevices.remove(device);
return;
}
Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state);
if (prevState == state) {
return;
}
if (remoteRole == BluetoothPan.LOCAL_PANU_ROLE) {
if (state == BluetoothProfile.STATE_CONNECTED) {
if ((!mTetherOn) || (localRole == BluetoothPan.LOCAL_PANU_ROLE)) {
Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
+ " is PANU drop the connection");
mPanDevices.remove(device);
disconnectPanNative(Utils.getByteAddress(device));
return;
}
Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE");
if (mNapIfaceAddr == null) {
mNapIfaceAddr = startTethering(iface);
if (mNapIfaceAddr == null) {
Log.e(TAG, "Error seting up tether interface");
mPanDevices.remove(device);
disconnectPanNative(Utils.getByteAddress(device));
return;
}
}
} else if (state == BluetoothProfile.STATE_DISCONNECTED) {
mPanDevices.remove(device);
Log.i(TAG, "remote(PANU) is disconnected, Remaining connected PANU devices: "
+ mPanDevices.size());
if (mNapIfaceAddr != null && mPanDevices.size() == 0) {
stopTethering(iface);
mNapIfaceAddr = null;
}
}
} else if (mNetworkFactory != null) {
// PANU Role = reverse Tether
Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " + state
+ ", prevState = " + prevState);
if (state == BluetoothProfile.STATE_CONNECTED) {
mNetworkFactory.startReverseTether(iface);
} else if (state == BluetoothProfile.STATE_DISCONNECTED) {
mNetworkFactory.stopReverseTether();
mPanDevices.remove(device);
}
}
if (state == BluetoothProfile.STATE_CONNECTED) {
MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.PAN);
}
/* Notifying the connection state change of the profile before sending the intent for
connection state change, as it was causing a race condition, with the UI not being
updated with the correct connection state. */
Log.d(TAG, "Pan Device state : device: " + device + " State:" + prevState + "->" + state);
Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothPan.EXTRA_STATE, state);
intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, localRole);
sendBroadcast(intent, BLUETOOTH_PERM);
}
通过sendBroadcast广播通知蓝牙连接的结果
2603

被折叠的 条评论
为什么被折叠?



