此处的代码为Android O的代码,本也有有一些patch的添加和修改,不过这些都不影响整个流程的理解。Handover相关的
大致可分为两种情况:直接读取带NFC的特殊设备如:带Nfc的蓝牙耳机、键盘、照相机等;还一种是传输文件的过程中由于文
件较大使用Handover也就是BT(目前仅支持BT)来传输此时也称之为Android Beam。
1、当检测到支持Nfc的蓝牙键盘、鼠标等的时候:(我们以链接蓝牙键盘为例子来分析).
从NfcDispatcher类中的dispatchTag()方法开始分析,至于如何到这一步的可以看别的文章。
public int dispatchTag(Tag tag) {
......
if (tryPeripheralHandover(message)) {
if (DBG) Log.i(TAG, "matched BT HANDOVER");
NfcIddEvent.NfcTag.dispatchedToPrioritizedMethod(tag,
NfcIddEvent.NfcTag.VALUE_APP_HANDOVER);
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
}
......
}
public boolean tryPeripheralHandover(NdefMessage m){
//下面这个方法mHandoverDataParser.parseBluetooth(m)方法是通过检测到的Tag中携带的Ndef格式的信息,
//信息包含了当前Nfc设备(蓝牙鼠标、键盘、耳机等)的各种设备信息,再往下的具体解析和协议息息相关,暂无深入分析。
HandoverDataParser.BluetoothHandoverData handover = mHandoverDataParser.parseBluetooth(m);
//如果解析出来的信息出问题,就需要去分析一下解析相关的协议了。
......
//下面就是解析完Tag中的NDEF携带的信息后,放到响应的变量中以便后续使用。
Intent intent = new Intent(mContext, PeripheralHandoverService.class);
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
if (handover.oobData != null) {
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, handover.oobData);
}
if (handover.uuids != null) {
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids);
}
if (handover.btClass != null) {
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS, handover.btClass);
}
intent.putExtra(PeripheralHandoverService.EXTRA_CLIENT, mMessenger);
intent.putExtra(PeripheralHandoverService.EXTRA_BT_ENABLED, mBluetoothEnabledByNfc.get());
...
//启动PeripheralHandoverService去进一步的处理。
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
return true;
}
public class PeripheralHandoverService extends Service implements BluetoothPeripheralHandover.Callback {
...
public PeripheralHandoverService() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = new MessageHandler();
mMessenger = new Messenger(mHandler);
mBluetoothHeadsetConnected = false;
mBluetoothEnabledByNfc = false;
mStartId = 0;
}
...
@Override
public void onCreate() {
super.onCreate();
mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBluetoothStatusReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
......
if (doPeripheralHandover(intent.getExtras())) {
return START_STICKY;
} else {
stopSelf(startId);
return START_NOT_STICKY;
}
}
}
a、注册的BluetoothAdapter.ACTION_STATE_CHANGED广播。
b、调用doPeripheralHandover去进一步的操作。
mBluetoothStatusReceiver如下:这个reveiver的作用在蓝牙打开的时候并且是由Nfc打开的时候就进一步的调用handover
相关的流程进行处理。
上面的两种情况最终都走到了BluetoothPeripheralHandover的start方法。
这个nextStep很关进,它根据当前所处的不同的action来选择具体的我们下一步要执行的动作。
此时我们处于ACTION_INIT的action所以走到nextStepInit();
至此我们应该先分析一下getProfileProxys(),如下,很简单的实现,就是调用了蓝牙提供的接口去获得对应的proflie的但是并
final BroadcastReceiver mBluetoothStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
handleBluetoothStateChanged(intent);
}
}
};
private void handleBluetoothStateChanged(Intent intent) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
// If there is a pending device pairing, start it
//下面最主要的其实就是调用mBluetoothPeripheralHandover.start()方法进行进一步的操作,
//而此时一般蓝牙刚被Nfc设备打开,根据是否配对来提示用户进行配对或者直接连接。
if (mBluetoothPeripheralHandover != null &&
!mBluetoothPeripheralHandover.hasStarted()) {
if (!mBluetoothPeripheralHandover.start()) {
mNfcAdapter.resumePolling();
}
}
} else if (state == BluetoothAdapter.STATE_OFF) {
if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_TURNING_ON) {
mBluetoothEnabledByNfc = false;
}
mBluetoothHeadsetConnected = false;
}
}
doPeripheralHandover的详解
boolean doPeripheralHandover(Bundle msgData) {
//只能有一个BluetoothPeripheralHandover对象,处理这个的Nfc Tag信息读取,
//此时想要再检测就得把Nfc设备的开关进行打开和关闭操作。
if (mBluetoothPeripheralHandover != null) {
Log.d(TAG, "Ignoring pairing request, existing handover in progress.");
return true;
}
......//这块就是把msgData中携带的数据取出来。(NDEF信息中的数据)
mBluetoothEnabledByNfc = msgData.getBoolean(EXTRA_BT_ENABLED);
//BluetoothPeripheralHandover是真正的处理的地方,此处进行唯一的实例化.
//传入的参数大都是从NDEF信息中解析出来的.
mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(
this, mDevice, name, transport, oobData, uuids, btClass, this);
......
if (mBluetoothAdapter.isEnabled()) {
//如果蓝牙已经打开,直接调用start()去进行配对等的处理。
if (!mBluetoothPeripheralHandover.start()) {
mHandler.removeMessages(MSG_PAUSE_POLLING);
mNfcAdapter.resumePolling();
}
} else {
//如果蓝牙没有打开那么就调用enableBluetooth去打开蓝牙设备.
//此处你打开蓝牙成功后也会往外发送广播最终到前面的receiver中最后也是调用start进行了处理。
if (!enableBluetooth()) {
Log.e(TAG, "Error enabling Bluetooth.");
mBluetoothPeripheralHandover = null;
return false;
}
}
return true;
}
//此处调用的是framework专门为system级别的app设定的方法enableNoAutoConnect,这个方法
//打开蓝牙后不会记录此次操作。
boolean enableBluetooth() {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothEnabledByNfc = true;
return mBluetoothAdapter.enableNoAutoConnect();
}
return true;
}
public boolean start() {
checkMainThread();
...
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(ACTION_ALLOW_CONNECT);
filter.addAction(ACTION_DENY_CONNECT);
mContext.registerReceiver(mReceiver, filter);
//很多地方都会发送这个timeout信息,因为无法确定蓝牙那块是走到了预期,或者出现什么别的情况。
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
//现在的行为是初始化阶段ACTION_INIT
mAction = ACTION_INIT;
mRetryCount = 0;
//调用nextStep去做进一步的处理
nextStep();
return true;
}
void nextStep() {
if (mAction == ACTION_INIT) {
nextStepInit();
} else if (mAction == ACTION_CONNECT) {
nextStepConnect();
} else {
nextStepDisconnect();
}
}
void nextStepInit() {
switch (mState) {
case STATE_INIT:
//如下只要有一个为null,就去getProfileProxys且改变状态STATE_WAITING_FOR_PROXIES.
if (mA2dp == null || mHeadset == null || mInput == null) {
mState = STATE_WAITING_FOR_PROXIES;
if (!getProfileProxys()) {
complete(false);
}
break;
}
//走到此处的时候证明已经获得了需要连接的蓝牙的对应协议的profile对应的service的实现。
case STATE_WAITING_FOR_PROXIES:
//注意state的改变此时变成了STATE_INIT_COMPLETE
mState = STATE_INIT_COMPLETE;
// Check connected devices and see if we need to disconnect
synchronized(mLock) {
if (mTransport == BluetoothDevice.TRANSPORT_LE || mIsHidCapability) {
//根据当前时候连接来决定下一个的状态.
if (mInput.getConnectedDevices().contains(mDevice)) {
Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
mAction = ACTION_DISCONNECT;
} else {
Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
mAction = ACTION_CONNECT;
}
} else {
//处理A2DP和HeadSet.
if (mA2dp.getConnectedDevices().contains(mDevice) ||
mHeadset.getConnectedDevices().contains(mDevice)) {
Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
mAction = ACTION_DISCONNECT;
} else {
// Check if each profile of the device is disabled or not
if (mHeadset.getPriority(mDevice) == BluetoothProfile.PRIORITY_OFF) {
mIsHeadsetAvailable = false;
}
if (mA2dp.getPriority(mDevice) == BluetoothProfile.PRIORITY_OFF) {
mIsA2dpAvailable = false;
}
if (!mIsHeadsetAvailable && !mIsA2dpAvailable) {
Log.i(TAG, "Both Headset and A2DP profiles are unavailable");
complete(false);
break;
}
Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
mAction = ACTION_CONNECT;
mNeedStartTheMusic = mAudioManager.isBluetoothA2dpOn()
& mAudioManager.isMusicActive();
}
}
}
//接着进行下一步。
nextStep();
}
}
又返回对象啊?注意BluetoothPeripheralHandover implements BluetoothProfile.ServiceListener.所以在你连接到对应的profile会回
调相关的接口onServiceConnected.
当成功链接的时候,会走如下的回调,然后实现具体的profile对象的实例化.
并且在实例化完毕后会,往外发送MSG_NEXT_STEP信息。这个信息被如下Handler处理。
但注意此时mAction == ACTION_INIT,但mState = STATE_WAITING_FOR_PROXIES.所以会调用到nextStepInit中的
boolean getProfileProxys() {
if (mTransport == BluetoothDevice.TRANSPORT_LE || mIsHidCapability) {
if (!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.INPUT_DEVICE))
return false;
} else {
if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET))
return false;
if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP))
return false;
}
return true;
}
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
synchronized (mLock) {
switch (profile) {
case BluetoothProfile.HEADSET:
mHeadset = (BluetoothHeadset) proxy;
if (mA2dp != null) {
mHandler.sendEmptyMessage(MSG_NEXT_STEP);
}
break;
case BluetoothProfile.A2DP:
mA2dp = (BluetoothA2dp) proxy;
if (mHeadset != null) {
mHandler.sendEmptyMessage(MSG_NEXT_STEP);
}
break;
case BluetoothProfile.INPUT_DEVICE:
mInput = (BluetoothInputDevice) proxy;
if (mInput != null) {
mHandler.sendEmptyMessage(MSG_NEXT_STEP);
}
break;
}
}
}
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TIMEOUT:
......
break;
case MSG_NEXT_STEP:
//可以看到重新调用了nextStep.
nextStep();
break;
case MSG_RETRY:
......
break;
}
}
};
STATE_WAITING_FOR_PROXIES这个选项当中。去看前面的对应的case中的代码。可以看到就是修改了mAction = XXX;然后
就是又去进行下一个操作了。
此时又来到了nextStep(),但是mAction == ACTION_CONNECT或者mAction == ACTION_DISCONNECT我们先分析ACTI
此时又来到了nextStep(),但是mAction == ACTION_CONNECT或者mAction == ACTION_DISCONNECT我们先分析ACTI
ON_CONNECT对应的就是方法nextStepConnect。
接下来我们具体看看nextStepConnect这个方法内部的几个重要实现。
首先是requestPairConfirmation,如下可以看到就是启动了一个Activity提示用户是否要进行配对,
我们进入到Activity中观察:
而如上的两个广播都是BluetoothPeripheralHandover在它的start()中进行注册的,最终由mReceiver处理
此时假如我们选择的是和蓝牙键盘进行配对那么会走到nextStepConnect(),但此时的state是STATE_WAITING_FOR_BO
void nextStepConnect() {
switch (mState) {
//此时的state是STATE_INIT_COMPLETE走到如下
case STATE_INIT_COMPLETE:
//如果未配对就会去调用requestPairConfirmation.
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
requestPairConfirmation();
mState = STATE_WAITING_FOR_BOND_CONFIRMATION;
break;
}
......
//到这一步的时候是用户根据弹框选择了确认配对
case STATE_WAITING_FOR_BOND_CONFIRMATION:
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
startBonding();
break;
}
//到这一步的时候已经配对完毕了,要对不同的profile进行不同的connecte.
//且会按照顺序通过判断依次进行链接.
case STATE_BONDING:
//状态改为正在连接.
mState = STATE_CONNECTING;
synchronized (mLock) {
//如果是input设备如蓝牙键盘。
if (mIsHidCapability) {
if (mInput.getConnectionState(mDevice)
!= BluetoothProfile.STATE_CONNECTED) {
mHidResult = RESULT_PENDING;
//直接调用对应的proflie对象进行Connect
mInput.connect(mDevice);
toast(mContext.getString(R.string.nfc_strings_toast_connecting_txt),
Toast.LENGTH_LONG);
break;
} else {
mHidResult = RESULT_CONNECTED;
}
} else if (mTransport != BluetoothDevice.TRANSPORT_LE) {
//只要不是input设备,就常尝试用mHeadset、mA2dp两个profile进行了链接
//注意此处还会retry几次。
if (mHeadset.getConnectionState(mDevice) !=
BluetoothProfile.STATE_CONNECTED) {
if (mIsHeadsetAvailable) {
mHfpResult = RESULT_PENDING;
mHeadset.connect(mDevice);
} else {
mHfpResult = RESULT_DISCONNECTED;
}
} else {
mHfpResult = RESULT_CONNECTED;
}
if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
if (mIsA2dpAvailable) {
mA2dpResult = RESULT_PENDING;
mA2dp.connect(mDevice);
} else {
mA2dpResult = RESULT_DISCONNECTED;
}
} else {
mA2dpResult = RESULT_CONNECTED;
}
if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
if (mRetryCount == 0) {
toast(mContext.getString(R.string.nfc_strings_toast_connecting_txt),
Toast.LENGTH_LONG);
}
if (mRetryCount < MAX_RETRY_COUNT) {
sendRetryMessage(RETRY_CONNECT_WAIT_TIME_MS);
break;
}
}
}
}
//当连接完毕的时候,无论成功与否。
case STATE_CONNECTING:
if (mIsHidCapability) {
//输入设备根据连接的结果来做相应的赋值和提示操作
if (mHidResult == RESULT_PENDING) {
break;
} else if (mHidResult == RESULT_CONNECTED) {
toast(mContext.getString(R.string.nfc_strings_toast_connected_txt, mName));
mDevice.setAlias(mName);
complete(true);
} else {
toast(mContext.getString(
R.string.nfc_strings_toast_sht_connection_failed_txt));
complete(false);
}
} else if (mTransport != BluetoothDevice.TRANSPORT_LE) {
//处理A2DP和HeadSet的,基本同Hid
......
if (mA2dpResult == RESULT_CONNECTED || mHfpResult == RESULT_CONNECTED) {
......
} else {
......
}
}
break;
}
}
首先是requestPairConfirmation,如下可以看到就是启动了一个Activity提示用户是否要进行配对,
void requestPairConfirmation() {
Intent dialogIntent = new Intent(mContext, ConfirmConnectActivity.class);
dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
dialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
dialogIntent.putExtra(BluetoothDevice.EXTRA_NAME, mName);
mContext.startActivity(dialogIntent);
}
public class ConfirmConnectActivity extends Activity {
BluetoothDevice mDevice;
AlertDialog mAlert = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(this,
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
...
builder.setMessage(confirmString)
.setCancelable(false)
.setPositiveButton(res.getString(R.string.pair_yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//当用户确认配对的时候往外发送BluetoothPeripheralHandover.ACTION_ALLOW_CONNECT的广播
Intent allowIntent = new Intent(BluetoothPeripheralHandover.ACTION_ALLOW_CONNECT);
allowIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
sendBroadcast(allowIntent);
...
}
})
.setNegativeButton(res.getString(R.string.pair_no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//当用户取消配对的时候往外发送BluetoothPeripheralHandover.ACTION_ALLOW_CONNECT的广播
Intent denyIntent = new Intent(BluetoothPeripheralHandover.ACTION_DENY_CONNECT);
denyIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
sendBroadcast(denyIntent);
...
}
});
mAlert = builder.create();
mAlert.show();
...
}
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleIntent(intent);
}
};
void handleIntent(Intent intent) {
String action = intent.getAction();
...
//配对的Action
if (ACTION_ALLOW_CONNECT.equals(action)) {
//执行配对前再次发送延时信息,因为不确定配对多长时间完成,以及有没有成功
mHandler.removeMessages(MSG_TIMEOUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
nextStepConnect();
//下面是取消配对的action
} else if (ACTION_DENY_CONNECT.equals(action)) {
complete(false);
//下面是配对状态变化的action
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)
&& mState == STATE_BONDING) {
int bond = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothAdapter.ERROR);
if (bond == BluetoothDevice.BOND_BONDED) {
mRetryCount = 0;
nextStepConnect();
} else if (bond == BluetoothDevice.BOND_NONE) {
if (mRetryCount < MAX_RETRY_COUNT) {
sendRetryMessage(RETRY_PAIRING_WAIT_TIME_MS);
} else {
toast(getToastString(R.string.pairing_peripheral_failed));
complete(false);
}
}
//下面是BluetoothHeadset profile链接状态变化的action
} else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
(mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
...
//下面是BluetoothA2dp profile链接状态变化的action
} else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
(mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
...
//下面是BluetoothInputDevice profile链接状态变化的action
} else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action) &&
(mState == STATE_CONNECTING || mState == STATE_DISCONNECTING)) {
int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothProfile.STATE_CONNECTED) {
//链接成功的时候
mHidResult = RESULT_CONNECTED;
nextStep();
} else if (state == BluetoothProfile.STATE_DISCONNECTED) {
//连接失败的时候
mHidResult = RESULT_DISCONNECTED;
nextStep();
}
}
}
ND
_
CO
NFI
RMATION
参照前面的代码,最终走到startBonding方法
无论我们配对成功与否,当配对状态发生改变的时候,就会走到前面说的handleIntent中对应的判断。ACTION_BOND_S
void startBonding() {
//显示修改状态
mState = STATE_BONDING;
//直接调用BluetoothDevice的不同的Bond方法进行配对,暂不清楚这两个的具体区别???
if (mOobData != null) {
if (!mDevice.createBondOutOfBand(mTransport, mOobData)) {
toast(mContext.getString(R.string.nfc_strings_toast_sht_paring_failed_txt));
complete(false);
}
} else if (!mDevice.createBond(mTransport)) {
toast(mContext.getString(R.string.nfc_strings_toast_sht_paring_failed_txt));
complete(false);
}
}
TATE_CHANGED,并且此时的state为STATE_BONDING.查看上面代码,在配对成功的时候调用nextStepConnect,失败的时
候根据判断重试或者直接做最后的赋值操作。
在nextStepConnect()当中此时的state状态时STATE_BONDING,注意此时已经是配对成功了,但是state还没改变,处于
在nextStepConnect()当中此时的state状态时STATE_BONDING,注意此时已经是配对成功了,但是state还没改变,处于
正在配对状态,那么我们进去case STATE_BONDING。然后先把状态改为:mState = STATE_CONNECTING;正在链接接着就
开始真正的connect。根据不同的profile调用不同的connect。在连接成功后BT那边会往外发送广播,会被
handleIntent进行处理,
此处我们是以链接蓝牙键盘为例子,那么就会走到BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED
然后又去
调用nextStep(),又会走到nextStepConnect()。但此时的状态时是state为STATE_CONNECTING.进入到
对应的判断中做最后的通
知处理即可,调用complete。
//成功的时候true,失败的时候false.
至此完成了类似于读取Tag的分发流程,把每个外设都看成是一个Nfc的Tag.
2、当是P2P模式最终以蓝牙传输的时候。
void complete(boolean connected) {
reportBluetoothPeripheralHandoverComplete(connected);
mState = STATE_COMPLETE;
mContext.unregisterReceiver(mReceiver);
mHandler.removeMessages(MSG_TIMEOUT);
mHandler.removeMessages(MSG_RETRY);
synchronized (mLock) {
if (mA2dp != null) {
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp);
}
if (mHeadset != null) {
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset);
}
if (mInput != null) {
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mInput);
}
mA2dp = null;
mHeadset = null;
mInput = null;
}
mCallback.onBluetoothPeripheralHandoverComplete(connected);
}
2、当是P2P模式最终以蓝牙传输的时候。
此处直接从P2P模式已经确认要发送开始,此时用户已经点击屏幕,开始回调发送事件。对应的HandoverClient和Handover
Se
rver已经启动。(前面的文章有分析)
就是P2pLinkManager类的SendTask内部类开始分析,且只分析handover的
final class SendTask extends AsyncTask<Void, Void, Void> {
...
HandoverClient handoverClient;
//需要通过BT传输的操作
int doHandover(Uri[] uris, UserHandle userHandle) throws IOException {
NdefMessage response = null;
//先实例化BeamManager,用于管理从开始到结束的传输的动作。
BeamManager beamManager = BeamManager.getInstance();
//判断是不是有一个传输正在进行。
if (beamManager.isBeamInProgress()) {
return HANDOVER_BUSY;
}
//如下是客户端根据协议把要请求的信息如蓝牙地址等,封装成NDEF格式的信息用于往外发送给
//另一个手机也就是服务端,然后服务端开启自己的BT进行配对等等的操作,暂不分析此处的是现实细节
NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
//如果成功封装成Ndef信息
if (request != null) {
if (handoverClient != null) {
//通过Client想客户端发送请求,内部就是往指定的服务器地址发送Ndef请求信息,请求试用handover来传输
//此处的信息还是通过Nfc来发送的。
response = handoverClient.sendHandoverRequest(request);
}
//如果远端的手机不支持handover,那么改用别的方式.
if (response == null && snepClient != null) {
SnepMessage snepResponse = snepClient.get(request);
response = snepResponse.getNdefMessage();
}
if (response == null) {
if (snepClient != null)
return HANDOVER_UNSUPPORTED;
else
return HANDOVER_FAILURE;
}
} else {
return HANDOVER_UNSUPPORTED;
}
//走到这里的时候证明远端的Handover是成功,打算开始调用BT进行真正的数据的传输。
//mHandoverDataParser.getOutgoingHandoverData(response),来把HandoverServer传过来的
//Ndef数据解析,并且赋值给我们需要的变量,就是比如把蓝牙地址、名称、数据配对信息等,赋值给了BeamManager
//的一些变量,此处暂不深入分析,因为的对照协议解析,暂时不太清楚???
if (!beamManager.startBeamSend(mContext,
mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) {
return HANDOVER_BUSY;
}
return HANDOVER_SUCCESS;
}
int doSnepProtocol(NdefMessage msg) throws IOException {
...
}
@Override
public Void doInBackground(Void... args) {
......
//当解析传过来的数据发现需要使用handover的时候,uris被设置值,此时进入到doHandover
if (uris != null) {
try {
int handoverResult = doHandover(uris, userHandle);
switch (handoverResult) {
case HANDOVER_SUCCESS:
result = true;
break;
case HANDOVER_FAILURE:
result = false;
break;
case HANDOVER_UNSUPPORTED:
result = false;
onHandoverUnsupported();
break;
case HANDOVER_BUSY:
result = false;
onHandoverBusy();
break;
}
} catch (IOException e) {
result = false;
}
}
......
if (result) {
onSendComplete(m, time);
}
return null;
}
}
接下来我们就来看看BeamManager的简单介绍
此时是调用到了startBeamSend进而启动BeamSendService来完成进一步的操作。
可以看到如上的很多的工作都是在BeamTransferManager中完成的!BeamTransferManager代码较多此处就一点点分析
先从实例化看起。
public class BeamManager implements Handler.Callback {
...//省略成员变量显示
//获取实例,单例模式
private static final class Singleton {
public static final BeamManager INSTANCE = new BeamManager();
}
private BeamManager() {
mLock = new Object();
mBeamInProgress = false;
mCallback = new Handler(Looper.getMainLooper(), this);
mNfcService = NfcService.getInstance();
}
public static BeamManager getInstance() {
return Singleton.INSTANCE;
}
public boolean isBeamInProgress() {
synchronized (mLock) {
return mBeamInProgress;
}
}
public boolean startBeamReceive(Context context,
HandoverDataParser.BluetoothHandoverData handoverData) {
synchronized (mLock) {
if (mBeamInProgress) {
return false;
} else {
mBeamInProgress = true;
}
}
BeamTransferRecord transferRecord =
BeamTransferRecord.forBluetoothDevice(
handoverData.device, handoverData.carrierActivating, null);
Intent receiveIntent = new Intent(context.getApplicationContext(),
BeamReceiveService.class);
receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
new Messenger(mCallback));
if (CtaUtils.showCtaBtDialogIfNeeded(context, mCallback,
receiveIntent, handoverData.device)) {
return true;
}
whitelistOppDevice(context, handoverData.device);
context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
return true;
}
//已经收到回应开始尝试使用handover模式也称之为Beam模式
//注意第二个参数就是远端的Handoverserver给出的回应,进一步封装的数据
public boolean startBeamSend(Context context,
HandoverDataParser.BluetoothHandoverData outgoingHandoverData,
Uri[] uris, UserHandle userHandle) {
//只能执行一个传输.
synchronized (mLock) {
if (mBeamInProgress) {
return false;
} else {
mBeamInProgress = true;
}
}
//这个Record如其名字,就是记录了remoteDevice(远端的device)、uris(存放的要传输的数据的uri)等
BeamTransferRecord transferRecord = BeamTransferRecord.forBluetoothDevice(
outgoingHandoverData.device, outgoingHandoverData.carrierActivating,
uris);
//启动BeamReceiveService来通过service进一步完成正真的传输.
Intent sendIntent = new Intent(context.getApplicationContext(),
BeamSendService.class);
sendIntent.putExtra(BeamSendService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
sendIntent.putExtra(BeamSendService.EXTRA_BEAM_COMPLETE_CALLBACK,
new Messenger(mCallback));
......
context.startServiceAsUser(sendIntent, userHandle);
return true;
}
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_BEAM_COMPLETE) {
synchronized (mLock) {
mBeamInProgress = false;
}
boolean success = msg.arg1 == 1;
if (success) {
mNfcService.playSound(NfcService.SOUND_END);
}
return true;
}
return false;
}
void whitelistOppDevice(Context context, BluetoothDevice device) {
if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
intent.setPackage(BLUETOOTH_PACKAGE);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
context.sendBroadcastAsUser(intent, UserHandle.CURRENT);
}
}
public class BeamSendService extends Service implements BeamTransferManager.Callback{
......
private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
handleBluetoothStateChanged(intent);
}
}
};
//构造很简单只是得到了BluetoothAdapter
public BeamSendService() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBluetoothStateReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
......
//调用doTransfer开始往外发送.
if (doTransfer(transferRecord)) {
return START_STICKY;
} else {
//异常处理
......
}
}
boolean doTransfer(BeamTransferRecord transferRecord) {
if (createBeamTransferManager(transferRecord)) {
//下面这个receiver我们后面在解释。
mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
//Ndef信息中携带的是蓝牙的传输链接的时候才进行传输。
if (transferRecord.dataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
//如果已经打开
if (mBluetoothAdapter.isEnabled()) {
// 直接调用TransferManager的start开始传送,
mTransferManager.start();
} else {
//调用BT相关的接口去打开蓝牙,打开成功后会发送蓝牙状态改变你的广播,
if (!mBluetoothAdapter.enableNoAutoConnect()) {
Log.e(TAG, "Error enabling Bluetooth.");
mTransferManager = null;
return false;
}
//用来标记是Nfc打开的BT
mBluetoothEnabledByNfc = true;
...
}
}
return true;
}
return false;
}
boolean createBeamTransferManager(BeamTransferRecord transferRecord) {
......
//如下的实例化很关键
//实例化BeamTransferManager来管理传输中的流程显示等,关于BeamTransferManager下面详解
mTransferManager = new BeamTransferManager(this, this, transferRecord, false);
//第一个notification!
mTransferManager.updateNotification();
return true;
}
//收到BT开启的广播以后开始准备传送.
private void handleBluetoothStateChanged(Intent intent) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
if (mTransferManager != null &&
mTransferManager.mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
//收到广播以后同样是调用TransferManager的start开始传输.
mTransferManager.start();
}
}
}
......
//传输完成的回调.
@Override
public void onTransferComplete(BeamTransferManager transfer, boolean success) {
// Play success sound
......
if (mBluetoothEnabledByNfc) {
mBluetoothEnabledByNfc = false;
mBluetoothAdapter.disable();
}
//
invokeCompleteCallback(success);
stopSelf(mStartId);
}
......
}
先从实例化看起。
构造中实例化的变量很多,我们只看比较重要的。
接下来就是第一个通知updateNotification,借此我们来分析一下此方法。
再往下就是start()开始传输的函数了。
BluetoothOppHandover用于完成和本地蓝牙的交互操作,start如下:
那么我们就看一下BluetoothOppHandover当中的sendIntent
到此我们就完成了Nfc端的发送广播和BT通信去完成最终的数据传输,一旦开始传输,蓝牙就会在每个传输的阶段发送广
public BeamTransferManager(Context context, Callback callback,
BeamTransferRecord pendingTransfer, boolean incoming) {
...
mRemoteDevice = pendingTransfer.remoteDevice;
//往外发送的时候是false.
mIncoming = incoming;
mTransferId = pendingTransfer.id;
mDataLinkType = pendingTransfer.dataLinkType;
mRemoteActivating = pendingTransfer.remoteActivating;
mTotalCount = (pendingTransfer.uris != null) ? pendingTransfer.uris.length : 0;
mProgress = 0.0f;
mState = STATE_NEW;
mUris = pendingTransfer.uris == null
? new ArrayList<Uri>()
: new ArrayList<Uri>(Arrays.asList(pendingTransfer.uris));
......
//将要往外发送的uris
mOutgoingUris = pendingTransfer.uris;
}
void updateNotification() {
Builder notBuilder = new Notification.Builder(mContext, BEAM_NOTIFICATION_CHANNEL);
notBuilder.setXXX;
...
String beamString;
//下面判断是往外发送还是接受的,此处我们分析的是发送的。(接受的是不是从HandoverServer开始分析?)
if (mIncoming) {
beamString = mContext.getString(R.string.beam_progress);
} else {
beamString = mContext.getString(R.string.beam_outgoing);
}
//第一次的时候mState == STATE_NEW在构造中进行的实例化
if (mState == STATE_NEW || mState == STATE_IN_PROGRESS ||
mState == STATE_W4_NEXT_TRANSFER || mState == STATE_W4_MEDIA_SCANNER) {
notBuilder.setXXX;
...
//下面就是处理进度条显示的问题
float progress = 0;
if (mTotalCount > 0) {
float progressUnit = 1.0f / mTotalCount;
progress = (float) mCurrentCount * progressUnit + mProgress * progressUnit;
}
if (mTotalCount > 0 && progress > 0) {
notBuilder.setProgress(100, (int) (100 * progress), false);
} else {
notBuilder.setProgress(100, 0, true);
}
//下面是当传输成功的时候
} else if (mState == STATE_SUCCESS) {
notBuilder.setAutoCancel(true);
...
//下面是当传输失败的时候
} else if (mState == STATE_FAILED) {
notBuilder.setAutoCancel(false);
...
//取消传输的时候
} else if (mState == STATE_CANCELLED || mState == STATE_CANCELLING) {
notBuilder.setAutoCancel(false);
...
} else {
return;
}
//把不同的显示内容notify出去即可。
mNotificationManager.notify(null, mTransferId, notBuilder.build());
}
public void start() {
......
//当是往外传输的时候
if (!mIncoming
//当是通过蓝牙往外传输的时候
if (mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
//传入Handoverserver返回回来的Ndef消息用于和本地蓝牙配对链接等。
new BluetoothOppHandover(mContext, mRemoteDevice, mUris, mRemoteActivating).start();
}
}
}
public void start() {
if (mRemoteActivating) {
Long timeElapsed = SystemClock.elapsedRealtime() - mCreateTime;
if (timeElapsed < REMOTE_BT_ENABLE_DELAY_MS) {
//此处左中也是调用sendIntent().
mHandler.sendEmptyMessageDelayed(MSG_START_SEND,
REMOTE_BT_ENABLE_DELAY_MS - timeElapsed);
} else {
sendIntent();
}
} else {
// Remote BT enabled already, start send immediately
sendIntent();
}
}
void sendIntent() {
Intent intent = new Intent();
intent.setPackage("com.android.bluetooth");
String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris.get(0));
intent.setType(mimeType);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
......
//而如下两个广播那在Bluetooth.apk的应用中的BluetoothOppHandoverReceiver
//进行了处理,最终由Bluetooth去完成发送文件的操作。
if (mUris.size() == 1) {
intent.setAction(ACTION_HANDOVER_SEND);
intent.putExtra(Intent.EXTRA_STREAM, mUris.get(0));
} else {
intent.setAction(ACTION_HANDOVER_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mUris);
}
if (DBG) Log.d(TAG, "Handing off outging transfer to BT");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcast(intent);
complete();//状态置为complete
}
播给Nfc的应用以便Nfc应用可以更新通知的显示。这些操作也是在BeamTransferManager当中实现的。我们也应该意识到有个
receiver去接受来自BT的广播,进而完成更新操作。这就是前面在SendService中的doTransfer()进行实例化的BeamStatusRece
iver,它用于我们上面所说的操作,我们去看一下。
通过上面可以大概的总结一下,在传输的过程中的时候是一直在调用mTransferManager.updateFileProgress(progress)而在
public class BeamStatusReceiver extends BroadcastReceiver {
...//各种成员变量的广播我们就省略了,代码中直接看即可
//构造
BeamStatusReceiver(Context context, BeamTransferManager transferManager) {
mContext = context;
mTransferManager = transferManager;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
int dataLinkType = intent.getIntExtra(EXTRA_HANDOVER_DATA_LINK_TYPE,
BeamTransferManager.DATA_LINK_TYPE_BLUETOOTH);
if (ACTION_CANCEL_HANDOVER_TRANSFER.equals(action)) {
if (mTransferManager != null) {
mTransferManager.cancel();
}
} else if (ACTION_TRANSFER_PROGRESS.equals(action) ||
ACTION_TRANSFER_DONE.equals(action) ||
ACTION_HANDOVER_STARTED.equals(action)) {
handleTransferEvent(intent, dataLinkType);
}
}
//感兴趣的广播
public IntentFilter getIntentFilter() {
IntentFilter filter = new IntentFilter(ACTION_TRANSFER_DONE);
filter.addAction(ACTION_TRANSFER_PROGRESS);
filter.addAction(ACTION_CANCEL_HANDOVER_TRANSFER);
filter.addAction(ACTION_HANDOVER_STARTED);
return filter;
}
private void handleTransferEvent(Intent intent, int deviceType) {
String action = intent.getAction();
int id = intent.getIntExtra(EXTRA_TRANSFER_ID, -1);
String sourceAddress = intent.getStringExtra(EXTRA_ADDRESS);
......
mTransferManager.setBluetoothTransferId(id);
//接收到BT传输完成,发过来的对应广播以后更新,最终还是更新notification.
//这个广播在传输完成后20s还不发,就会出现发送失败的显示.
if (action.equals(ACTION_TRANSFER_DONE)) {
int handoverStatus = intent.getIntExtra(EXTRA_TRANSFER_STATUS,
HANDOVER_TRANSFER_STATUS_FAILURE);
if (handoverStatus == HANDOVER_TRANSFER_STATUS_SUCCESS) {
......
mTransferManager.finishTransfer(true, uri, mimeType);
} else {
mTransferManager.finishTransfer(false, null, null);
}
//传输的过程中BT发过来的广播,这个的实现就是在BluetoothOppNotification类中
//嵌入到了蓝牙的通知中,就好比改更新蓝牙传输的进度的时候,隐藏了不更新,转而发送
//这个notification然后Nfc来更新进度!
} else if (action.equals(ACTION_TRANSFER_PROGRESS)) {
float progress = intent.getFloatExtra(EXTRA_TRANSFER_PROGRESS, 0.0f);
mTransferManager.updateFileProgress(progress);
//用于开始Handover的处理
} else if (action.equals(ACTION_HANDOVER_STARTED)) {
int count = intent.getIntExtra(EXTRA_OBJECT_COUNT, 0);
if (count > 0) {
mTransferManager.setObjectCount(count);
}
}
}
}
传输完毕后调用mTransferManager.finishTransfer(true, uri, mimeType);看起来并没有更新Notification啊别急,继续分析这两个的
实现。
先看updateFileProgress
先看updateFileProgress
public void updateFileProgress(float progress) {
......
this.mProgress = progress;
//用于接受的时候
if (mIncoming && mRemoteDevice != null) whitelistOppDevice(mRemoteDevice);
updateStateAndNotification(STATE_IN_PROGRESS);
}
//调用到了updateStateAndNotification,并且传入state = STATE_IN_PROGRESS
void updateStateAndNotification(int newState) {
this.mState = newState;
......
//终于看到这个了,去更新Notification,如我们前面所分析。
updateNotification();
......
}
再看一下finishTransfer
接下来就是根据BT放接受的成都以及传过来的广播来更新Notification了,注意一下mIncoming的值就行。
至此简单的分析了一下NFC和Handover(也成Beam)协同工作的流程,还有一些断开连接等流程未继续分析,不过代码都是
public void finishTransfer(boolean success, Uri uri, String mimeType) {
......
if (success && uri != null) {
...
//重新初始化进度
mProgress = 0.0f;
if (mimeType == null) {
mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, uri);
}
if (mimeType != null) {
mUris.add(uri);
mTransferMimeTypes.add(mimeType);
}
...
} else {
Log.e(TAG, "Handover transfer failed");
}
mHandler.removeMessages(MSG_NEXT_TRANSFER_TIMER);
if (mCurrentCount == mTotalCount) {
if (mIncoming) {
//当是接受的时候还回去做进一步处理,如把这个收到的数据放到那里等
processFiles();
} else {
......
//发送的时候,根据发送成功的文件数量来调用updateStateAndNotification
updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED);
}
} else {
//不止一个图的时候
mHandler.sendEmptyMessageDelayed(MSG_NEXT_TRANSFER_TIMER, WAIT_FOR_NEXT_TRANSFER_MS);
updateStateAndNotification(STATE_W4_NEXT_TRANSFER);
}
}
对于发送而言也是调用到updateStateAndNotification,进而进入到updateNotification更新通知栏。至此我们分析完毕
往外
发送数据的时候的流程,接下来简单看一下接受数据的时候。
理所应当的就想到了接受的地方肯定跑不了HandoverServer当中
啊,然后是在内部类ServerThread中接受然请求的handover信息,
发送完respond以后调用到ConnectionThread中的run的如下代码:
if (!beamManager.startBeamReceive(mContext, handoverData.handoverData)) {
mCallback.onHandoverBusy();
break;
}
调用到BeamTransferManager中的startBeamReceive,前面那我们已经列过其代码,此处再单独列出来分析一下。
public boolean startBeamReceive(Context context,
HandoverDataParser.BluetoothHandoverData handoverData) {
...
//同样也是实例化一个transferRecord
BeamTransferRecord transferRecord =
BeamTransferRecord.forBluetoothDevice(
handoverData.device, handoverData.carrierActivating, null);
//期初的service就不同了,这块要启动的是BeamReceiveService.
Intent receiveIntent = new Intent(context.getApplicationContext(),
BeamReceiveService.class);
receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
new Messenger(mCallback));
//接收数据的device的白名单的
whitelistOppDevice(context, handoverData.device);
context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
return true;
}
下面列出BeamReceiveService的简单介绍。
public class BeamReceiveService extends Service implements BeamTransferManager.Callback{
......
private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_OFF) {
//源码就什么也没写,看来是在关闭的时候不作操作。
}
}
}
};
//构造
public BeamReceiveService() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
......
//同理发送的时候的设计形式,只不过此处调用的是prepareToReceive.
if (prepareToReceive(transferRecord)) {
if (DBG) Log.i(TAG, "Ready for incoming Beam transfer");
return START_STICKY;
} else {
......//异常处理
}
}
// TODO: figure out a way to not duplicate this code
@Override
public void onCreate() {
......
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBluetoothStateReceiver, filter);
}
......
boolean prepareToReceive(BeamTransferRecord transferRecord) {
......
//没有开启的时候
if (!mBluetoothAdapter.isEnabled()) {
//开启蓝牙下面的标志已经见过好多次了。
if (!mBluetoothAdapter.enableNoAutoConnect()) {
Log.e(TAG, "Error enabling Bluetooth.");
return false;
}
mBluetoothEnabledByNfc = true;
}
//同样接受的时候在这里实例化BeamTransferManager.
mTransferManager = new BeamTransferManager(this, this, transferRecord, true);
//也需要更新进度条,同样实例化BeamStatusReceiver
mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
mTransferManager.start();
mTransferManager.updateNotification();
return true;
}
......
@Override
public void onTransferComplete(BeamTransferManager transfer, boolean success) {
......
}
......
}
//可以看到start对接受没什么实质性的操作
public void start() {
......
if (!mIncoming) {
if (mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
new BluetoothOppHandover(mContext, mRemoteDevice, mUris, mRemoteActivating).start();
}
}
}
至此简单的分析了一下NFC和Handover(也成Beam)协同工作的流程,还有一些断开连接等流程未继续分析,不过代码都是
在这
一块了。