Bluetooth蓝牙连接

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广播通知蓝牙连接的结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值