packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothPairingDetail.java @Override void onDevicePreferenceClick(BluetoothDevicePreference btPreference) { disableScanning(); super.onDevicePreferenceClick(btPreference); } packages\apps\Settings\src\com\android\settings\bluetooth\DeviceListPreferenceFragment.java void onDevicePreferenceClick(BluetoothDevicePreference btPreference) { btPreference.onClicked(); } 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, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT); askDisconnect(); // 之前鏈接過,不須要再配對,直接進行鏈接 } else if (bondState == BluetoothDevice.BOND_BONDED) { metricsFeatureProvider.action(context, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT); mCachedDevice.connect(true); // 沒鏈接過,進行配對,須要鏈接的雙方都贊成以後才能鏈接 } else if (bondState == BluetoothDevice.BOND_NONE) { metricsFeatureProvider.action(context, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR); if (!mCachedDevice.hasHumanReadableName()) { metricsFeatureProvider.action(context, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES); } pair(); } } 1. 已經鏈接過的設備,直接斷開 // Show disconnect confirmation dialog for a device. private void askDisconnect() { Context context = getContext(); String name = mCachedDevice.getName(); if (TextUtils.isEmpty(name)) { name = context.getString(R.string.bluetooth_device); } String message = context.getString(R.string.bluetooth_disconnect_all_profiles, name); String title = context.getString(R.string.bluetooth_disconnect_title); // 對話框的listener DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mCachedDevice.disconnect(); } }; // 顯示斷開對話框 mDisconnectDialog = Utils.showDisconnectDialog(context, mDisconnectDialog, disconnectListener, title, Html.fromHtml(message)); } 2. 匹配過的設別,進行鏈接 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) { // 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"); return; } // Reset the only-show-one-error-dialog tracking variable mIsConnectingErrorPossible = true; int preferredProfiles = 0; for (LocalBluetoothProfile profile : mProfiles) { // connectAllProfile傳進來的是true if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) { if (profile.isPreferred(mDevice)) { ++preferredProfiles; connectInt(profile); // 鏈接對應的profile } } } if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles); if (preferredProfiles == 0) { connectAutoConnectableProfiles(); } } private void connectAutoConnectableProfiles() { if (!ensurePaired()) { return; } // Reset the only-show-one-error-dialog tracking variable mIsConnectingErrorPossible = true; for (LocalBluetoothProfile profile : mProfiles) { if (profile.isAutoConnectable()) { profile.setPreferred(mDevice, true); connectInt(profile); } } } 3. 沒有配對的設備,先進行配對 private void pair() { if (!mCachedDevice.startPairing()) { Utils.showError(getContext(), mCachedDevice.getName(), R.string.bluetooth_pairing_error_message); } } frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth\CachedBluetoothDevice.java public boolean startPairing() { // Pairing is unreliable while scanning, so cancel discovery // 配對的時候,關閉掃描 if (mLocalAdapter.isDiscovering()) { mLocalAdapter.cancelDiscovery(); } if (!mDevice.createBond()) { return false; } return true; } frameworks\base\core\java\android\bluetooth\BluetoothDevice.java @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond() { final IBluetooth service = sService; if (service == null) { Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); return false; } try { Log.i(TAG, "createBond() for device " + getAddress() + " called by pid: " + Process.myPid() + " tid: " + Process.myTid()); return service.createBond(this, TRANSPORT_AUTO); } catch (RemoteException e) { Log.e(TAG, "", e); } return false; } packages\apps\Bluetooth\src\com\android\bluetooth\btservice\AdapterService.java private static class AdapterServiceBinder extends IBluetooth.Stub { public boolean createBond(BluetoothDevice device, int transport) { if (!Utils.checkCallerAllowManagedProfiles(mService)) { Log.w(TAG, "createBond() - Not allowed for non-active user"); return false; } AdapterService service = getService(); if (service == null) return false; return service.createBond(device, transport, null); // bond } // 創建bond boolean createBond(BluetoothDevice device, int transport, OobData oobData) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) { return false; } // 在多播的時候不要進行bond,不明白這個multicast是什麼意思 // Multicast: Do not allow bonding while multcast A2dpService a2dpService = A2dpService.getA2dpService(); if (a2dpService != null && a2dpService.isMulticastFeatureEnabled() && a2dpService.isMulticastOngoing(null)) { Log.i(TAG,"A2dp Multicast is ongoing, ignore bonding"); return false; } mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device)); // Pairing is unreliable while scanning, so cancel discovery // Note, remove this when native stack improves if (!mAdapterProperties.isDiscovering()) { Log.i(TAG,"discovery not active, no need to send cancelDiscovery"); } else { cancelDiscoveryNative(); } // 或去狀態機的消息 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND); msg.obj = device; msg.arg1 = transport; if (oobData != null) { Bundle oobDataBundle = new Bundle(); oobDataBundle.putParcelable(BondStateMachine.OOBDATA, oobData); msg.setData(oobDataBundle); } // 發送消息給狀態機 mBondStateMachine.sendMessage(msg); return true; } packages\apps\Bluetooth\src\com\android\bluetooth\btservice\BondStateMachine.java private class StableState extends State { @Override public void enter() { infoLog("StableState(): Entering Off State"); } @Override public synchronized boolean processMessage(Message msg) { BluetoothDevice dev = (BluetoothDevice)msg.obj; switch(msg.what) { case CREATE_BOND: OobData oobData = null; if (msg.getData() != null) oobData = msg.getData().getParcelable(OOBDATA); createBond(dev, msg.arg1, oobData, true); break; case REMOVE_BOND: removeBond(dev, true); break; case BONDING_STATE_CHANGE: int newState = msg.arg1; /* if incoming pairing, transition to pending state */ if (newState == BluetoothDevice.BOND_BONDING) { if(!mDevices.contains(dev)) { mDevices.add(dev); } sendIntent(dev, newState, 0); transitionTo(mPendingCommandState); } else if (newState == BluetoothDevice.BOND_NONE) { /* if the link key was deleted by the stack */ sendIntent(dev, newState, 0); } else { Log.e(TAG, "In stable state, received invalid newState: " + newState); } break; case CANCEL_BOND: default: Log.e(TAG, "Received unhandled state: " + msg.what); return false; } return true; } } private boolean createBond(BluetoothDevice dev, int transport, OobData oobData, boolean transition) { if(mAdapterService == null) return false; if (dev.getBondState() == BluetoothDevice.BOND_NONE) { infoLog("Bond address is:" + dev); byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); boolean result; // 調用JNI if (oobData != null) { result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData); } else { result = mAdapterService.createBondNative(addr, transport); } if (!result) { sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED); return false; } else if (transition) { transitionTo(mPendingCommandState); } return true; } return false; }
Liu Taojava
2019-3-27android