NFC源码分析之P2P工作模式.

本文详细解析了NFC的P2P模式工作原理,包括从底层JNI回调到Java层处理的过程,以及不同模式(Initiator和Target)下的设备交互流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       文章只对Nfc的P2P模式的java层的代码进行了分析,native层的代码还不熟悉.直接从P2P模
的JNI层回调开始分析。
整体时序图:

  server端时序图:

     当有可被用作P2P模式的NFC设备被发现后,经过底层的一系列处理传输到JNI然后回调到:
NativeNfcManager.java当中的notifyLlcpLinkActivation()。
1
/**
2
* Notifies P2P Device detected, to activate LLCP link
3
*/
4
private void notifyLlcpLinkActivation(NativeP2pDevice device) {
5
    mListener.onLlcpLinkActivated(device);
6
}
      mListener是DeviceHostListener由NfcService实现的,进入onLlcpLinkActivated()开始java层的处
理,native层感应到了P2P设备,java层需要解析一下,看看是什么格式,做什么操作等。
1
/**
2
* Notifies P2P Device detected, to activate LLCP link
3
* NfcDepEndpoint:代表了一个远程的P2p设备,可以是target也可以是initiator.
4
*                取决于native处理完返回来的是什么了。注意和TagEndpoint的区别,
5
*                TagEndpoint是代表远端的Tag.
6
*/
7
@Override
8
public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
9
    sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
10
}
       
1
void sendMessage(int what, Object obj) {
2
    Message msg = mHandler.obtainMessage();
3
    msg.what = what;
4
    msg.obj = obj;
5
    mHandler.sendMessage(msg);
6
}
      对应到mHandler中的
1
case MSG_LLCP_LINK_ACTIVATION:
2
        ......
3
        llcpActivated((NfcDepEndpoint) msg.obj);
4
  break;
    先介绍一些基本的只知识
远程的P2P设备会有两种模式:
    1)、Target:当前手机往外发送数据的时候,远程的设备就是Target,自己就是Initiator
    2)、Initiator:当前手机接受数据的时候,远程的设备就是Initiator,自己就是Target.
    在上层就体现在NfcDepEndpoint.getMode()的不同.并且他们的基本流程都一致,差异点是在
Target端会先执行connect(),调用到NativeP2pDevice中的native方法doConnect()进行数据链路层的连
接保证底层已经是发现对方并且是可以连接的。
    再然后简单了解一下NativeP2pDevice.java类的实例化,和NativeNfcTag实例化类似,在
NativeNfcManager.cpp当中
1
const char*  gNativeP2pDeviceClassName  = "com/android/nfc/dhimpl/NativeP2pDevice";
2
static struct nfc_jni_native_data* nat = NULL;
3
static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o)
4
{
5
    ......
6
    if (nfc_jni_cache_object(e, gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) 
7
        == -1)
8
    {
9
        ALOGE("%s: fail cache NativeP2pDevice", __func__);
10
        return JNI_FALSE;
11
    }
12
    ......    
13
}
   把NativeP2pDevice类对应到了nat->cached_P2pDevice这个变量,然后在PeerToPeer.cpp中如
下方法完成了NativeP2pDevice的实例化和变量的设置,而且每次检测到P2P设备都会进行一次实例
化,就算第一次检测到了,然后点击传输的时候,第二次也会再实例化一个.(感觉就是出现在范围内
就一次)
1
/*******************************************************************************
2
**
3
** Function:        llcpActivatedHandler
4
**
5
** Description:    Receive LLLCP-activated event from stack.
6
**                  nat: JVM-related data.
7
**                  activated: Event data.
8
**
9
** Returns:        None
10
**
11
*******************************************************************************/
12
void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& 
13
                                       activated)
14
{
15
    ......
16
    ALOGV("%s: get object class", fn);
17
    ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(nat->cached_P2pDevice));
18
    ......
19
    //初始化变量
20
    ALOGV("%s: instantiate", fn);
21
    /* New target instance */
22
    jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V");
23
    ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor));
24
25
    /* Set P2P Target mode */
26
    jfieldID f = e->GetFieldID(tag_cls.get(), "mMode", "I");
27
28
    //如下有个疑问,亲测当使用两个手机的时候,无论是在发送方还是接收方,Log打印都是initiator.
29
    //无论是大数据传输图片还是传输小数据联系人等.????????这是为什么那? 
30
    //发现偶尔,第一次的时候接收方可能回事target,其它都是initiator
31
    if (activated.is_initiator == true) {
32
        ALOGV("%s: p2p initiator", fn);
33
        e->SetIntField(tag.get(), f, (jint) MODE_P2P_INITIATOR);
34
    } else {
35
        ALOGV("%s: p2p target", fn);
36
        e->SetIntField(tag.get(), f, (jint) MODE_P2P_TARGET);
37
    }
38
    /* Set LLCP version */
39
    f = e->GetFieldID(tag_cls.get(), "mLlcpVersion", "B");
40
    e->SetByteField(tag.get(), f, (jbyte) activated.remote_version);
41
42
    /* Set tag handle */
43
    //这个handle也是每次都是同一个值,无论是接受还是发送,无论是不是同一个资源。
44
    //而且重启手机再打印Log还是一样,真是很神奇!
45
    f = e->GetFieldID(tag_cls.get(), "mHandle", "I");
46
    e->SetIntField(tag.get(), f, (jint) 0x1234); // 
47
48
    if (nat->tag != NULL) {
49
        e->DeleteGlobalRef(nat->tag);
50
    }
51
    nat->tag = e->NewGlobalRef(tag.get());
52
53
    ALOGV("%s: notify nfc service", fn);
54
55
    //调用回调!
56
    /* Notify manager that new a P2P device was found */
57
    e->CallVoidMethod(nat->manager, 
58
                      android::gCachedNfcManagerNotifyLlcpLinkActivation, tag.get());
59
    ......
60
61
    ALOGV("%s: exit", fn);
62
}
      接下来开始正式分析P2P的流程,从llcpActivated()开始:
1
private boolean llcpActivated(NfcDepEndpoint device) {
2
    Log.d(TAG, "LLCP Activation message");
3
    //当远程p2p是Target端的时候,一定要注意,此时的Mode指的是远端的用于和当前设备进行P2P操作
4
    //的设备。
5
    if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
6
        if (device.connect()) { //最终是NfcDepEndpoint中的native方法doConnect();
7
            /* Check LLCP compliance */
8
            if (mDeviceHost.doCheckLlcp()) {//doCheckLlcp是NativeNfcManager中Native方法
9
                /* Activate LLCP Link */
10
                if (mDeviceHost.doActivateLlcp()) {//doActivateLlcp也是
11
                    //NativeNfcManager中的Native方法
12
                    synchronized (NfcService.this) {
13
                        //当放到集合当中,注意这个集合也存放了,NativeNfcTag对象,也就是读
14
                        //取Tag时候实例化的那个
15
                        //fields below are used in multiple threads and protected by 
16
                        //synchronized(this)
17
                        //final HashMap<Integer, Object> mObjectMap = new 
18
                        //HashMap<Integer, Object>();
19
                        //暂时测试同一个手机下如前面所说handle一直是一个值,这样的话也就是
20
                        //说,P2P的Device里面只会存一个
21
                        mObjectMap.put(device.getHandle(), device);
22
                    }
23
                    //底层按照llcp协议建立完链路连接的时候调用如下方法。
24
                    mP2pLinkManager.onLlcpActivated(device.getLlcpVersion());
25
                    return true;
26
                } else {device.disconnect();//断开链接}
27
            } else {
28
                //断开连接
29
                if (DBG) Log.d(TAG, "Remote Target does not support LLCP. 
30
                               Disconnect.");
31
                device.disconnect();//最终是NfcDepEndpoint中的native方法doDisconnect();
32
            }
33
        } else {//不能连接远程的target,然后去执行发送数据.}
34
    //当是远程的P2P是发起者initiator的时候.
35
    } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
36
            //可以看到对比MODE_P2P_TARGET就是少了一个device.connect().
37
            /* Check LLCP compliancy */
38
            if (mDeviceHost.doCheckLlcp()) {
39
                /* Activate LLCP Link */
40
                if (mDeviceHost.doActivateLlcp()) {
41
                    if (DBG) Log.d(TAG, "Target Activate LLCP OK");
42
                        synchronized (NfcService.this) {
43
                            // Register P2P device
44
                            mObjectMap.put(device.getHandle(), device);
45
                        }
46
                    mP2pLinkManager.onLlcpActivated(device.getLlcpVersion());
47
                    return true;
48
                }
49
            } else { Log.w(TAG, "checkLlcp failed");}
50
    }
51
    return false;
52
}
      如上无论远端是Target还是initaitor,最后都调用了,P2pLinkManager中的onLlcpActivated。
至此,native层的llcp链路建立成功并且也通过了check,我们接下来只需要按照传输协议建立socket
传递数据即可!
     另外native层执行完链路连接以后会回调很多状态给上层,在P2pLinkManager类当中有如下三个
回调:
1
public void onLlcpFirstPacketReceived()  
2
public void onLlcpDeactivated()  
3
void onSendComplete(NdefMessage msg, long elapsedRealtime)
      进入到P2PLinkManager当中
1
public void onLlcpActivated(byte peerLlcpVersion) {
2
    Log.i(TAG, "LLCP activated");
3
    synchronized (P2pLinkManager.this) {
4
        ......
5
        mLastLlcpActivationTime = SystemClock.elapsedRealtime();
6
        mPeerLlcpVersion = peerLlcpVersion;
7
        //分别对不同的链接状态进行处理,此时对应的是在P2pLinkManager的构造中初始化为
8
        //LINK_STATE_DOWN.
9
        //注意第一次tap,然后两个手机超出范围(会进行Deactivated相关回调,后面说),再次tap的
10
        //时候mLinkState会变成LINK_STATE_DEBOUNCE.(有前面Deactivated设置的)
11
        switch (mLinkState) {
12
            //所以刚开始的时候是进入到这里。
13
            case LINK_STATE_DOWN:
14
                //加上了一些判断,保证现在是要进行P2P的状态。
15
                //NFC的整个P2P的流程中会有很多的类似的状态判断,因为P2P的链接随时可能中断,
16
                //毕竟要我们拿着手机相互靠近,一不小心就离开了
17
                if (!mEventListener.isP2pIdle()
18
                        && mSendState != SEND_STATE_PENDING) {
19
                    break;
20
                }
21
                if (DBG) Log.d(TAG, "onP2pInRange()");
22
                //这个方法内就会得到一个当前屏幕截图的bitmap对象,但在这还不会弹出提示的界面.
23
                mEventListener.onP2pInRange();
24
                //更改链接状态。
25
                mLinkState = LINK_STATE_UP;
26
                //mSendState状态在构造中初始化,为SEND_STATE_NOTHING_TO_SEND.所以走到else
27
                //第一次tap获取完毕屏幕截图的时候,第二次tap时候会处于SEND_STATE_PENDING.
28
                if (mSendState == SEND_STATE_PENDING) {
29
                    ......
30
                } else {
31
                    mSendState = SEND_STATE_NOTHING_TO_SEND;
32
                    //按照app传入的各个要发送的数据进行
33
                    prepareMessageToSend(true);
34
                    //判断是否有数据要往外发,有数据往外发的时候才会进入。
35
                    //此时当是接收方的时候这会儿就不会做任何处理,因为都是null。此时会作为
36
                    //server端,等待client的链接
37
                    //mMessageToSend != null,代表传输小数据,直接发送即可。
38
                    //mUrisToSend != null,代表要传输大数据,需要用到BT,进行Handover.
39
                    if (mMessageToSend != null ||
40
                            (mUrisToSend != null && 
41
                             mHandoverDataParser.isHandoverSupported())) {
42
                        //如下是一个异步的处理方式,因此会直接往往下走
43
                        connectLlcpServices();
44
                        //上面connectLlcpServices还未异步执行完毕的时候,这块肯定就赋值了
45
                        //而对于一般的测试,发现发送方的发送,走到这里的时候都会走到else,需
46
                        //要进行确认.此时mSendState就变成SEND_STATE_NEED_CONFIRMATION了
47
                        if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) 
48
                        {
49
                            //标记不需要确认直接发送
50
                            mSendState = SEND_STATE_SENDING;
51
                        } else {
52
                            //标记需要在UI上确认的才能P2p
53
                            mSendState = SEND_STATE_NEED_CONFIRMATION;
54
                        }
55
                    }
56
                }
57
                break;
58
            case LINK_STATE_UP:
59
                if (DBG) Log.d(TAG, "zhaoyuan Duplicate onLlcpActivated()");
60
                return;
61
            //正常传输东西的时候的第二次Tap,会走到这里
62
            case LINK_STATE_DEBOUNCE:
63
                // Immediately connect and try to send again
64
                Log.d(TAG, "zhaoyuan LINK_STATE_DEBOUNCE");
65
                mLinkState = LINK_STATE_UP;
66
                if (mSendState == SEND_STATE_SENDING ||
67
                        mSendState == SEND_STATE_NEED_CONFIRMATION) {
68
                    // If we have something to send still, connect LLCP
69
                    //此时需要传输东西走到这里.
70
                    connectLlcpServices();
71
                }
72
                mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
73
                break;
74
        }
75
    }
76
}
      我们一步步看onLlcpActivated()中的重要的方法。
     mEventListener.onP2pInRange(); mEventListener是P2pEventListener.
1
//进行P2P链接的时候回调事件用来更新UI界面的接口.
2
interface P2pEventListener {
3
    ......
4
    //Indicates a P2P device is in range.
5
    public void onP2pInRange();
6
    ......
7
}
而P2pEventManager实现了P2pEventListener这个接口,所以进入P2pEventManager中
1
public class P2pEventManager implements P2pEventListener, SendUi.Callback {
2
    ......
3
    public P2pEventManager(Context context, P2pEventListener.Callback callback) {
4
        mNfcService = NfcService.getInstance();
5
        mContext = context;
6
        //mCallback定义在P2pEventListener中,位于P2pLinkManager.java当中
7
        mCallback = callback;
8
        ......
9
10
        mSending = false;
11
        final int uiModeType = mContext.getResources().getConfiguration().uiMode
12
                & Configuration.UI_MODE_TYPE_MASK;
13
        //不懂下面的这个是什么意思!,抓取Log发现正常初始化的时候为UI_MODE_TYPE_NORMAL.
14
        if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
15
            // "Appliances" don't intrinsically have a way of confirming this, so we
16
            // don't use the UI and just autoconfirm where necessary.
17
            // Don't instantiate SendUi or else we'll use memory and never reclaim it.
18
            mSendUi = null;
19
        } else {
20
            //this的类型是SendUi.Callback也可以看到:P2pEventManager implements 
21
            //P2pEventListener, SendUi.Callback
22
            mSendUi = new SendUi(context, this);
23
        }
24
    }
25
    @Override
26
    public void onP2pInRange() {
27
        mNdefSent = false;
28
        mNdefReceived = false;
29
        mInDebounce = false;
30
        //屏幕处于亮屏且解锁的状态的时候,发送声音,震动.
31
        if (mNfcService.mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED) {
32
            mNfcService.playSound(NfcService.SOUND_START);
33
            mVibrator.vibrate(VIBRATION_PATTERN, -1);
34
        }
35
        if (mSendUi != null) {
36
          //SendUi就是P2P过程中负责和界面交互的类。
37
            mSendUi.takeScreenshot();
38
        }
39
    }
40
}
     对于SendUi实例化时候传入的this,构定义如下,注意命名此处就是SendUi的完成发送和取消发
送的回调,定于SendUi当中,而实现于P2pEventManager.
     接着到SenUi中:
1
public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
2
        TimeAnimator.TimeListener, TextureView.SurfaceTextureListener, 
3
        android.view.Window.Callback {
4
        
5
    public interface Callback {
6
        public void onSendConfirmed();//确认发送
7
        public void onCanceled();//取消发送
8
    }
9
    ......
10
    public void takeScreenshot() {
11
        ...
12
        //更新当前状态
13
        mState = STATE_W4_SCREENSHOT;
14
        //去异步的获取一个屏幕截图.
15
        new ScreenshotTask().execute();
16
    }
17
    ......
18
    final class ScreenshotTask extends AsyncTask<Void, Void, Bitmap> {
19
        @Override
20
        protected Bitmap doInBackground(Void... params) {
21
            return createScreenshot();
22
        }
23
        @Override
24
        protected void onPostExecute(Bitmap result) {
25
            //在构造中mState = STATE_IDLE;
26
            //mState在前面takeScreenshot设置的是STATE_W4_SCREENSHOT
27
            if (mState == STATE_W4_SCREENSHOT) {
28
                //生成的截图设置到mScreenshotBitmap,这个在后面显示用户确认操作时候用.
29
                // Screenshot done, wait for request to start preSend anim
30
                mScreenshotBitmap = result;
31
                //并且把mState变成将要发送的状态
32
                mState = STATE_W4_PRESEND;
33
            } else if (mState == STATE_W4_SCREENSHOT_THEN_STOP) {
34
                // We were asked to finish, move to idle state and exit
35
                mState = STATE_IDLE;
36
            } else if (mState == STATE_W4_SCREENSHOT_PRESEND_REQUESTED ||
37
                    mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED) {
38
                if (result != null) {
39
                    mScreenshotBitmap = result;
40
                    boolean requestTap = 
41
                        (mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED);
42
                    mState = STATE_W4_PRESEND;
43
                    showPreSend(requestTap);
44
                } else {
45
                    // Failed to take screenshot; reset state to idle
46
                    // and don't do anything
47
                    Log.e(TAG, "Failed to create screenshot");
48
                    mState = STATE_IDLE;
49
                }
50
            } else {
51
                Log.e(TAG, "Invalid state on screenshot completion: " + 
52
                      Integer.toString(mState));
53
            }
54
        }
55
    };
56
57
    /**
58
    * 此处旨在理解流程,具体的画图算大小省略,这个方法会返回当前界面的一个截图.
59
    */
60
    Bitmap createScreenshot() {
61
        ......
62
        //根据不同屏幕进行适配
63
        final int navBarHeight = ...;
64
        final int navBarHeightLandscape = ...;
65
        final int navBarWidth = ...;
66
        ......
67
        Bitmap bitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
68
        ......
69
        int newLeft = ...;
70
        int newTop = ...;
71
        int newWidth = ...;
72
        int newHeight = ...;
73
        float smallestWidth = ...;
74
        float smallestWidthDp = ...;
75
        if (bitmap.getWidth() < bitmap.getHeight()) {
76
            newHeight = ...;
77
        } else {
78
            if (smallestWidthDp > 599) {
79
                newHeight = ...;
80
            } else {
81
                newHeight = ...;
82
                newWidth = ...;
83
            }
84
        }
85
        bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight);
86
        return bitmap;
87
    }
88
}
    到此其实也只是获取到了一个用屏幕的截图绘制的bitmap,把它设置给了mScreenshotBitmap,
并不会显示什么界面,然后回到P2PLinkManager中的onLlcpActivated 接这前面的往下看先是:
1
mLinkState = LINK_STATE_UP;而对于mSendState的状态,在构造中初始化的时候为
2
mSendState = SEND_STATE_NOTHING_TO_SEND;所以刚开始会走到else的分支。
     //依据第三方要传输消息的APP设置的信息,准备发送的信息.
     //主要是把最终解析出来的数据放到mMessageToSend和mUrisToSend中
     //ndef的小数据一般用mMessageToSend存储,如:Contact、Email、等
     //picture、video等一般会放在mUrisToSend中
1
void prepareMessageToSend(boolean generatePlayLink) {
2
    synchronized (P2pLinkManager.this) {
3
        mMessageToSend = null;
4
        mUrisToSend = null;
5
        //由在构造中的时候默认是false,但是在NfcService一系列附加的行为启动完毕后
6
        //调用到P2pLinkManager中enableDisable,会把它赋值为true.
7
        if (!mIsSendEnabled) {
8
            return;
9
        }
10
        //检测前台应用是否有活动的activity,前台程序就是指,你打开比如联系人、图库等注意是
11
        //可分享的activity界面你打开后,选中某个图片,一轻触就开始走流程了,否则的话没啥反应.
12
        if (foregroundUids.isEmpty()) {
13
            Log.e(TAG, "Could not determine foreground UID.");
14
            return;
15
        }
16
        //检测到如前台程序是否可以使用Beam功能。
17
        if (isBeamDisabled(foregroundUids.get(0))) {
18
            if (DBG) Log.d(TAG, "Beam is disabled by policy.");
19
            return;
20
        }
21
        //mCallbackNdef是IAppCallback接口的实现,通过调用NfcAdapterService的接口
22
        //setAppCallback进行设置的,一般无论是第三方app还是系统的联系人、图库等发送数据
23
        //的时候都会设置.但由于系统里面很多应用,可能别的应用已经注册,观察发现发送方和
24
        //接收方此处都是mCallbackNdef != null,但是foregroundUids可能没有包含当前的uid
25
        if (mCallbackNdef != null) {
26
            //如果是自己添加的前台进程的话,走下面的流程,发送方和接收方次处就会不同.
27
            if (foregroundUids.contains(mNdefCallbackUid)) {
28
                try {
29
                    //createBeamShareData在framework中有实现,在NfcActivityManager中实现
30
                    //此处还需要深入的再看看怎么确定beam的数据的,(??????)
31
                    //通过Log发现:
32
                    //图片资源的时候  mMessageToSend = null
33
                    //            mUrisToSend = [Landroid.net.Uri;@473547e
34
                    //            mUserHandle = UserHandle{0}
35
                    //            mSendFlags = 0
36
                    //*******************************
37
                    // 联系人资源的时候 mMessageToSend = NdefMessage 
38
                    //               [NdefRecord tnf=2 type=746578742F782D7663617264  
39
                    //                payload=424547494E3A56434152
40
                    //                440D0A56455253494F4E3A322E310D0A4E3A3B5A686
41
                    //                16F7975616E3B3B3B0D0A464E3A5A68616F7975616E
42
                    //                200D0A54454C3B43454C4C3A3133363938353233363
43
                    //                9380D0A454E443A56434152440D0A]
44
                    //                    mUrisToSend = null.
45
                    //                    mUserHandle = UserHandle{0}
46
                    //                    mSendFlags = 0
47
                    //总的来说是由createBeamShareData内部实现的区分!
48
                    BeamShareData shareData = 
49
                            mCallbackNdef.createBeamShareData(mPeerLlcpVersion);
50
                    mMessageToSend = shareData.ndefMessage;
51
                    mUrisToSend = shareData.uris;
52
                    mUserHandle = shareData.userHandle;
53
                    mSendFlags = shareData.flags;
54
                    return;
55
                } ...
56
            } else {
57
                //当如图库退出前台的时候,可能它的回调并没有清除。
58
                //你想作为Socket接收端,就会到当前判断不会去专门打开指定的应用界面去发送东西
59
                if (DBG) Log.d(TAG, "Last registered callback is not running in the 
60
                               foreground.");
61
            }
62
        }
63
        //当没有设置回调,就调用系统默认的,将当前Pkg的信息打包发送到上层。
64
        List<Integer> foregroundPids =
65
                mForegroundUtils.getForegroundPids(foregroundUids.get(0));
66
        ......
67
        //找到正在运行的pkg
68
        String pkgName = null;
69
        ActivityManager manager =
70
                (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
71
        List<RunningAppProcessInfo> appList = manager.getRunningAppProcesses();
72
        for (RunningAppProcessInfo info : appList) {
73
            for (Integer pid : foregroundPids) {
74
                if (pid.intValue() == info.pid) {
75
                    if (DBG) Log.d(TAG, "PID:" + info.pid + " Name:" + 
76
                                   info.processName);
77
                    pkgName = info.processName;
78
                    break;
79
                }
80
            }
81
            if (pkgName != null) {
82
                break;
83
            }
84
        }
85
        //正常情况下都会找到一个正在运行的前台应用,如你是在home界面的时候
86
        //Log:com.sonymobile.home 会被发现.
87
        if (pkgName != null) {
88
            if (!generatePlayLink || beamDefaultDisabled(pkgName)) {
89
                if (DBG) Log.d(TAG, "Disabling default Beam behavior");
90
                mMessageToSend = null;
91
                mUrisToSend = null;
92
            } else {
93
                mMessageToSend = createDefaultNdef(pkgName);
94
                mUrisToSend = null;
95
                mSendFlags = 0;
96
            }
97
        }
98
        //作为接收端的时候此处就会为null,不会发送任何数据.
99
        if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend);
100
        if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend);
101
    }
102
}
       再回到前面P2pLinkManager中的onLlcpActivated当中,继续往下看,此时作为接收方没有数据
发送的时候流程就到这结束了,作为发送方那么必然有一个不为null,此时调connectLlcpServices();
同样目前还是位于P2PLinkManager中
1
void connectLlcpServices() {
2
    synchronized (P2pLinkManager.this) {
3
        ......
4
        mConnectTask = new ConnectTask();
5
        mConnectTask.execute();
6
    }
7
}
8
final class ConnectTask extends AsyncTask<Void, Void, Boolean> {
9
10
    //执行完对应的client的链接以后,会走到这里.
11
    @Override
12
    protected void onPostExecute(Boolean result)  {
13
        ......
14
        //如果成功connect到指定的server socket.
15
        if (result) {
16
            onLlcpServicesConnected();
17
        } else {
18
            Log.e(TAG, "Could not connect required NFC transports");
19
        }
20
    }
21
22
    @Override
23
    protected Boolean doInBackground(Void... params) {
24
        //初始化一些参数,用来标记使用那种协议来解析数据.
25
        boolean needsHandover = false;
26
        boolean needsNdef = false;
27
        boolean success = false;
28
        //如下三个分别去链接接收方的对应的server,至于相关的server的初始化,在别的博客有说明.
29
        //这些客户端的socket创建也是按照llcp协议的要求来设置一些属性如访问节点等.
30
        HandoverClient handoverClient = null;
31
        SnepClient snepClient = null;
32
        NdefPushClient nppClient = null;
33
34
        synchronized(P2pLinkManager.this) {
35
            if (mUrisToSend != null) {
36
                //进入到此处的时候就会用bt进行传输
37
                needsHandover = true;
38
            }
39
            if (mMessageToSend != null) {
40
                //日历、联系人这一类的小数据
41
                needsNdef = true;
42
            }
43
        }
44
        // We know either is requested - otherwise this task
45
        // wouldn't have been started.
46
        if (needsHandover) {
47
            //此处实例化客户端的HandoverClient,每一个tap都会进行
48
            handoverClient = new HandoverClient();
49
            try {
50
                //此时就会去链接远端,接收方手机的HandoverServer.
51
                //调用connect,最终会调用到:
52
                //LlcpSocket当中connectToService(HandoverServer.
53
                //HANDOVER_SERVICE_NAME);
54
                //LlcpSocket是由NativeLlcpSocket实现,代表一个llcp的面向连接中的客户端。
55
                //连接它对应的服务端的Socket.在别的博客有介绍.后面也会去介绍server端的处理
56
                handoverClient.connect();
57
                success = true; // Regardless of NDEF result
58
            } ...
59
        }
60
        //当需要用ndef发送的时候
61
        if (needsNdef || (needsHandover && handoverClient == null)){
62
            if(NfcService.sIsDtaMode) {
63
                //不懂sIsDtaMode模式代表什么,好像和运营商的测试有关?
64
                ......
65
            }else{
66
                //可以看到对于Ndef的数据,先使用SnepClient进行链接.
67
                snepClient = new SnepClient();
68
            }
69
            try{
70
                if(NfcService.sIsDtaMode) {
71
                    ......
72
                }else{
73
                    snepClient.connect();
74
                }
75
                success = true;
76
                mDtaSnepClient = null;
77
            }...
78
            //当SnepClient链接不成功的时候,在使用NdefPushClient进行链接
79
            //此时就是看对方的手机支持不支持SnepClient,Android版本过老的话,就可能不支持
80
            //目前测得手机都是支持的.
81
            if (!success) {
82
                nppClient = new NdefPushClient();
83
                try {
84
                    nppClient.connect();
85
                    success = true;
86
                }...
87
            }
88
        }
89
        synchronized (P2pLinkManager.this) {
90
            //当ConnectTask被cancel的时候
91
            if (isCancelled()) {
92
                // Cancelled by onLlcpDeactivated on UI thread
93
                if (handoverClient != null) {
94
                    handoverClient.close();
95
                }
96
                if (snepClient != null) {
97
                    snepClient.close();
98
                }
99
                if (nppClient != null) {
100
                    nppClient.close();
101
                }
102
                if(mDtaSnepClient != null) {
103
                    mDtaSnepClient.close();
104
                }
105
                return false;
106
            //当ConnectTask没有cancle的时候
107
            } else {
108
                //......
109
                mHandoverClient = handoverClient;
110
                mSnepClient = snepClient;
111
                mNdefPushClient = nppClient;
112
                return success;
113
            }
114
        }
115
    }
116
};
      根据传输的格式来,来实例化对应的链接如:HandoverClient、SnepClient、NdefPushClient连
接成功后返回true至此socket的客户端启动完毕,并与server端建立起了链接,但是还未往外发送数
据,回到onLlcpActivated()当中,我们刚在else中执行了connectLlcpServices(),再往下的分析看前
面对应的地方,然后回到现在.链接成功后执行
1
void onLlcpServicesConnected() {
2
    synchronized (P2pLinkManager.this) {
3
        //先检查连接状态,只有处于LINK_STATE_UP才可以进行如下操作
4
        if (mLinkState != LINK_STATE_UP) {
5
            return;
6
        }
7
        mLlcpServicesConnected = true;
8
        //此时有两种情况,进入到需要传输数据的页面,第一次tap的时候,就是我们前面分析的流程
9
        //此时mSendState在前面的onLlcpActivated异步设置了是SEND_STATE_NEED_CONFIRMATION.
10
        //第二种情况是在已经确认后走到这里时,此时的mSendState,通过一些列回调设置成了
11
        //SEND_STATE_SENDING,后面也会有关于这个的分析.
12
        if (mSendState == SEND_STATE_NEED_CONFIRMATION) {
13
            //需要用户手动确认的,就是那个"Tap your screen to beam"的传输提示.
14
            if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()");
15
            mEventListener.onP2pSendConfirmationRequested();
16
        } else if (mSendState == SEND_STATE_SENDING) {
17
            //不需要确认直接发送
18
            mEventListener.onP2pResumeSend();
19
            sendNdefMessage();
20
        } else {
21
        // Either nothing to send or canceled/complete, ignore
22
        }
23
    }
24
}
       注意此时还未显示出来用户提示的界面,(缩小屏幕,提示你轻触使用beam进行传送)。下面继
续我们的跟踪(此时是第一次tap哦),又到P2pEventManager中onP2pSendConfirmationRequested中
1
@Override
2
public void onP2pSendConfirmationRequested() {
3
    //播放声音和震动.
4
    mNfcService.playSound(NfcService.SOUND_START);
5
    mVibrator.vibrate(VIBRATION_PATTERN, -1);
6
    //SendUi我们前面已经说过.
7
    if (mSendUi != null) {
8
        //注意传入的参数是false.
9
        mSendUi.showPreSend(false);
10
    } else {
11
        //直接不需要弹出确认页面,进行确认逻辑.
12
        mCallback.onP2pSendConfirmed();
13
    }
14
}
      分析确认send的画面,也就是showPreSend(),这个最终也会调用到onP2pSendConfirmed().
1
public void showPreSend(boolean promptToNfcTap) {
2
    ......
3
    //mScreenshotLayout是个View对象用来承载预先显示的这个画面,里面会放入一系列的组件
4
    //此时为它设置ontouch
5
    mScreenshotLayout.setOnTouchListener(this);
6
    //mScreenshotBitmap这就是前面在范围内的时候onP2pInRange截图生成的bitmap,
7
    mScreenshotView.setImageBitmap(mScreenshotBitmap);
8
    ......
9
    //由于promptToNfcTap是false,所以STATE_W4_TOUCH.
10
    //接下来你点击屏幕的时候(中间没有异常情况)
11
    mState = promptToNfcTap ? STATE_W4_NFC_TAP : STATE_W4_TOUCH;
12
}
    到现在为止才会显示出来整体的用户提示界面如下:
    原图如下:打算往外发的数据
    检测到远程的P2P设备时候:
     之后按照提示,如果你此时两个P2P设备已经远离,再把设备靠近即可完成发送。且一旦用户点
中间的界面,那么就会触发onTouch事件。
1
@Override
2
public boolean onTouch(View v, MotionEvent event) {
3
    //第一次到这执行完showPreSend后mState = STATE_W4_TOUCH。
4
    if (mState != STATE_W4_TOUCH) {
5
        return false;
6
    }
7
    ......
8
    //可以看到,最终调用onSendConfirmed去弹"Bring devices together again"
9
    //此时是在SendUI,因此mCallback对应的是P2pEventManager.
10
    mCallback.onSendConfirmed();
11
    return true;
12
}
     点击以后才会出现如下图:
  

此时是在SendUi当中,前面我们也说了它内部的callback的实现是在P2pEventManager如下:
1
@Override
2
public void onSendConfirmed() {
3
    if (!mSending) {
4
        if (mSendUi != null) {
5
            //调用下面这个界面变化成指定的传输提示动画。 图!
6
            mSendUi.showStartSend();
7
        }
8
        //此时的mCallback是在P2pEventListener声明,注意和SendUI中的区别.
9
        //实现是在P2pLinkManager,(都快晕菜了-.-!)
10
        mCallback.onP2pSendConfirmed();
11
    }
12
    mSending = true;//标记处于发送当中
13
}
      我们去P2pLinkManager当中.
1
@Override
2
public void onP2pSendConfirmed() {
3
    onP2pSendConfirmed(true);
4
}
5
private void onP2pSendConfirmed(boolean requireConfirmation) {
6
    if (DBG) Log.d(TAG, "onP2pSendConfirmed()");
7
    synchronized (this) {
8
        //在一开始的onLlcpActivated当中设置如下
9
        //mSendState = SEND_STATE_NEED_CONFIRMATION;
10
        //mLinkState也在前面的onLlcpActivated当中被被设置为LINK_STATE_UP,
11
        //但是当我们离开P2P的范围的时候,此时有个回调会被执行,然后:
12
        //mLinkState会被设置为LINK_STATE_DEBOUNCE.
13
        if (mLinkState == LINK_STATE_DOWN || (requireConfirmation
14
                && mSendState != SEND_STATE_NEED_CONFIRMATION)) {
15
            return;
16
        }
17
        //这个很重要把发送状态置为正在发送.
18
        mSendState = SEND_STATE_SENDING;
19
        //当是第一次tap的时候,两个手机没有离开P2P距离,会走到这里最。
20
        if (mLinkState == LINK_STATE_UP) {
21
            if (mLlcpServicesConnected) {
22
                sendNdefMessage();
23
            } // else, will send messages when link comes up
24
        //第一次tap的时候,中间两个手机有离开P2P范围那么会走到这里
25
        } else if (mLinkState == LINK_STATE_DEBOUNCE) {
26
            scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, 
27
                                  LINK_SEND_CONFIRMED_DEBOUNCE_MS);
28
            mEventListener.onP2pSendDebounce();
29
        }
30
    }
31
}
32
33
//onP2pSendDebounce源码,位于P2pEventManager当中
34
@Override
35
public void onP2pSendDebounce() {
36
    mInDebounce = true;
37
    mNfcService.playSound(NfcService.SOUND_ERROR);
38
    if (mSendUi != null) {
39
        mSendUi.showSendHint();//显示"Bring devices together again"
40
    }
41
}
42
43
//接下来应该是分析,一个是断开连接的回调,一个是第二次的tap!!
44
45
下面我们先分析一下tap完毕,你离开P2P范围的时候的回调,直接从JNI的回调看起
46
//在NativeNfcManager中,mListener是DeviceHostListener,对应的就是NfcService.
47
/**
48
* Notifies P2P Device detected, to activate LLCP link
49
*/
50
private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
51
    mListener.onLlcpLinkDeactivated(device);
52
}
53
//然后到NfcService中
54
/**
55
* Notifies P2P Device detected, to activate LLCP link
56
*/
57
@Override
58
public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
59
    sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
60
}
61
case MSG_LLCP_LINK_DEACTIVATED:
62
    //不晓得下面的mIsDebugBuild用意何在
63
    if (mIsDebugBuild) {
64
        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
65
        mContext.sendBroadcast(deactIntent);
66
    }
67
    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
68
    boolean needsDisconnect = false;
69
    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
70
    synchronized (NfcService.this) {
71
        /* Check if the device has been already unregistered */
72
        if (mObjectMap.remove(device.getHandle()) != null) {
73
            /* Disconnect if we are initiator */
74
            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
75
                if (DBG) Log.d(TAG, "disconnecting from target");
76
                needsDisconnect = true;
77
            } else {
78
                if (DBG) Log.d(TAG, "not disconnecting from initiator");
79
            }
80
        }
81
    }
82
    if (needsDisconnect) {
83
        device.disconnect();  // restarts polling loop
84
    }
85
    mP2pLinkManager.onLlcpDeactivated();
86
    break;
    //到P2pLinkManager当中
1
/**
2
* Must be called on UI Thread.
3
*/
4
public void onLlcpDeactivated() {
5
    Log.i(TAG, "LLCP deactivated.zhaoyuan");
6
    synchronized (this) {
7
        ......
8
        //在前面tap到,建立起链接的时候都会设置为LINK_STATE_UP状态
9
        switch (mLinkState) {
10
            case LINK_STATE_DOWN:
11
            case LINK_STATE_DEBOUNCE:
12
                Log.i(TAG, "Duplicate onLlcpDectivated()");
13
                break;
14
            case LINK_STATE_UP:
15
                //设置为LINK_STATE_DEBOUNCE状态。
16
                //mSendState 在onP2pSendConfirmed的时候设置为SEND_STATE_SENDING.
17
                mLinkState = LINK_STATE_DEBOUNCE;
18
                int debounceTimeout = 0;
19
                switch (mSendState) {
20
                    case SEND_STATE_NOTHING_TO_SEND:
21
                        debounceTimeout = 0;
22
                        break;
23
                    case SEND_STATE_NEED_CONFIRMATION:
24
                        debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS;
25
                        break;
26
                    case SEND_STATE_SENDING:
27
                        //int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000;这个是5s的延时.
28
                        debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS;
29
                        break;
30
                    case SEND_STATE_COMPLETE:
31
                        debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS;
32
                        break;
33
                    case SEND_STATE_CANCELED:
34
                        debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS;
35
                }
36
                //发送what =  MSG_DEBOUNCE_TIMEOUT,延时debounceTimeout时间的一个msg.
37
                scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout);
38
                //注意当你只是tap,然后离开范围的时候,此时的mSendState为
39
                //SEND_STATE_NEED_CONFIRMATION
40
                //这个是在前面onLlcpServicesConnected()中设置的.
41
                //而在触发ontouch,确认传送的时候,只要你再次tap,正常情况下此处会被设置
42
                //mSendState为SEND_STATE_COMPLETE.后面分析第二次tap的时候详解.
43
                if (mSendState == SEND_STATE_SENDING) {
44
                    Log.e(TAG, "onP2pSendDebounce()");
45
                    mEventListener.onP2pSendDebounce();
46
                }
47
                cancelSendNdefMessage();//mSendTask.cancel(true);
48
                disconnectLlcpServices();
49
                break;
50
        }
51
    }
52
}
53
54
//disconnectLlcpServices的源码.
55
void disconnectLlcpServices() {
56
    synchronized (this) {
57
        if (mConnectTask != null) {
58
            mConnectTask.cancel(true);
59
            mConnectTask = null;
60
        }
61
        // Close any already connected LLCP clients
62
        if (mNdefPushClient != null) {
63
            mNdefPushClient.close();
64
            mNdefPushClient = null;
65
        }
66
        if (mSnepClient != null) {
67
            mSnepClient.close();
68
            mSnepClient = null;
69
        }
70
        if (mHandoverClient != null) {
71
            mHandoverClient.close();
72
            mHandoverClient = null;
73
        }
74
        mLlcpServicesConnected = false;
75
    }
76
}
77
78
//MSG_DEBOUNCE_TIMEOUT发生时候的源码
79
case MSG_DEBOUNCE_TIMEOUT:
80
    synchronized (this) {
81
        if (mLinkState != LINK_STATE_DEBOUNCE) {
82
            break;
83
        }
84
        if (DBG) Log.d(TAG, "Debounce timeout");
85
        //就是把这些变量置为初始化的时候的状态
86
        //这个可以保证发生timeout以后,第二次tap的时候初始化状态.
87
        mLinkState = LINK_STATE_DOWN;
88
        mSendState = SEND_STATE_NOTHING_TO_SEND;
89
        mMessageToSend = null;
90
        mUrisToSend = null;
91
        if (DBG) Log.d(TAG, "onP2pOutOfRange()");
92
        //结束SendUI的界面.
93
        mEventListener.onP2pOutOfRange();
94
    }
95
    break;
96
//onP2pOutOfRange的源码
97
@Override
98
public void onP2pOutOfRange() {
99
    if (mSending) {
100
        mNfcService.playSound(NfcService.SOUND_ERROR);
101
        mSending = false;
102
    }
103
    if (!mNdefSent && !mNdefReceived && mSendUi != null) {
104
        mSendUi.finish(SendUi.FINISH_SCALE_UP);
105
    }
106
    mInDebounce = false;
107
}
      有了Deactivated的回调,我们再分析一下,点击确认以后的第二次tap,此时要进行真正的传输
了。检测到P2p设备以后前面的一些列操作基本相同,然后走到P2pLinkManager中的
onLlcpActivated的时候。由于前面有点远,下面直接再次贴出相关源码
1
public void onLlcpActivated(byte peerLlcpVersion) {
2
    Log.i(TAG, "LLCP activated");
3
    synchronized (P2pLinkManager.this) {
4
        ......
5
        //注意此时:已点击确认,且未发生timeout 那么:
6
        //mLinkState = LINK_STATE_DEBOUNCE;
7
        //mSendState = SEND_STATE_SENDING;
8
        switch (mLinkState) {
9
            case LINK_STATE_DOWN:
10
                ......
11
                break;
12
            case LINK_STATE_UP:
13
                if (DBG) Log.d(TAG, "zhaoyuan Duplicate onLlcpActivated()");
14
                return;
15
            case LINK_STATE_DEBOUNCE:
16
                // Immediately connect and try to send again
17
                //重新把mLinkState设置为LINK_STATE_UP以便后面可以建立连接.
18
                mLinkState = LINK_STATE_UP;
19
                if (mSendState == SEND_STATE_SENDING ||
20
                        mSendState == SEND_STATE_NEED_CONFIRMATION) {
21
                    // If we have something to send still, connect LLCP
22
                    connectLlcpServices();
23
                }
24
                //移除timeout
25
                mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
26
                break;
27
        }
28
    }
29
}
      关于connectLlcpServices往后的代码,我们前面已经贴出,此处直接贴出不同的地方.
到onLlcpServicesConnected以后
1
void onLlcpServicesConnected() {
2
    synchronized (P2pLinkManager.this) {
3
        //就是因为这个判断,前面需要重新设置状态.
4
        if (mLinkState != LINK_STATE_UP) {
5
            return;
6
        }
7
        mLlcpServicesConnected = true;
8
        //此时mSendState已经变成SEND_STATE_SENDING了,所以直接执行发送.
9
        if (mSendState == SEND_STATE_NEED_CONFIRMATION) {
10
            ......
11
        } else if (mSendState == SEND_STATE_SENDING) {
12
            mEventListener.onP2pResumeSend();
13
            sendNdefMessage();
14
        } ...
15
    }
16
}
17
//sendNdefMessage源码
18
void sendNdefMessage() {
19
    synchronized (this) {
20
        cancelSendNdefMessage();
21
        mSendTask = new SendTask();
22
        //去执行SendTask的doInBackground.
23
        mSendTask.execute();
24
    }
25
}
       SendTask相关源码.
1
final class SendTask extends AsyncTask<Void, Void, Void> {
2
    NdefPushClient nppClient;
3
    SnepClient snepClient;
4
    HandoverClient handoverClient;
5
6
    int doHandover(Uri[] uris, UserHandle userHandle) throws IOException {
7
        NdefMessage response = null;
8
        //获取BeamManager的实例,这个是管理Beam transfers的,保证同一时间只有一个在进行.
9
        BeamManager beamManager = BeamManager.getInstance();
10
        //如果有一个正在进行的handover,那么会提示正忙
11
        if (beamManager.isBeamInProgress()) {
12
            return HANDOVER_BUSY;
13
        }
14
        //HandoverDataParser类管理NFC传输到其它传输技术之间的切换。
15
        //发送方按照Nfc Form的对应协议,把标准的蓝牙请求消息封装成NdefMessage。
16
        //接收方收到的消息带有这些请求信息的时候就会配对了,建立连接了等.
17
        //关于Handover的详细信息有别的博客详细介绍.
18
        NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
19
        if (request != null) {
20
            if (handoverClient != null) {
21
                //下面内部会调用到LlcpSocket的sock.send(tmpBuffer).
22
                //它会作为socket的client端,就是客户端。(既然两个手机都开启了服务端,不会冲
23
                //突到本地吗???)
24
                //最终会调用到native的对应的方法.
25
                //通过handoverClient往外发送前面生成NdefMessage的请求,并且接受远端的回应.
26
                response = handoverClient.sendHandoverRequest(request);
27
            }
28
            //当是null的时候远程不支持handover,使用snepClient进行发送
29
            //在以前比较老的版本没有handoverClient这个client的,所以此处兼容snepClient
30
            if (response == null && snepClient != null) {
31
                // Remote device may not support handover service,
32
                //下面就是通过SnepClient相关的协议去发送数据,并获取response了。
33
                //这是以前没有handoverClient的时候的实现,现在基本都用不到这里.
34
                SnepMessage snepResponse = snepClient.get(request);
35
                response = snepResponse.getNdefMessage();
36
            }
37
            if (response == null) {
38
                return HANDOVER_UNSUPPORTED;
39
            }
40
        } else {
41
            return HANDOVER_UNSUPPORTED;
42
        }
43
        //走到这里response有回应,开始走BeamManager相关流程去发送数据,repose就包含了接收设
44
        //备的蓝牙地址.
45
        //一定注意此时的andoverDataParser解析的就是server返回回来的消息,然后经过处理.
46
        if (!beamManager.startBeamSend(mContext,
47
                mHandoverDataParser.getOutgoingHandoverData(response), uris, 
48
                                       userHandle)) {
49
            return HANDOVER_BUSY;
50
        }
51
        return HANDOVER_SUCCESS;
52
    }
53
54
    int doSnepProtocol(NdefMessage msg) throws IOException {
55
        if (msg != null) {
56
            snepClient.put(msg);
57
            return SNEP_SUCCESS;
58
        } else {
59
            return SNEP_FAILURE;
60
        }
61
    }
62
63
    @Override
64
    public Void doInBackground(Void... args) {
65
        NdefMessage m;
66
        Uri[] uris;
67
        UserHandle userHandle;
68
        boolean result = false;
69
70
        synchronized (P2pLinkManager.this) {
71
            if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) {
72
                return null;
73
            }
74
            //取出要发送的对应的变量.
75
            m = mMessageToSend;
76
            uris = mUrisToSend;
77
            userHandle = mUserHandle;
78
            snepClient = mSnepClient;
79
            handoverClient = mHandoverClient;
80
            nppClient = mNdefPushClient;
81
        }
82
        //当uris!= null的时候就表明传入的是大数据,需要使用BT进行handover.
83
        //此处的uris就是我们要往外发送的数据了.
84
        if (uris != null) {
85
            if (DBG) Log.d(TAG, "Trying handover request");
86
            try {
87
                int handoverResult = doHandover(uris, userHandle);
88
                switch (handoverResult) {
89
                    case HANDOVER_SUCCESS:
90
                        result = true;
91
                        break;
92
                    case HANDOVER_FAILURE:
93
                        result = false;
94
                        break;
95
                    case HANDOVER_UNSUPPORTED:
96
                        result = false;
97
                        onHandoverUnsupported();
98
                        break;
99
                    case HANDOVER_BUSY:
100
                        result = false;
101
                        onHandoverBusy();
102
                        break;
103
                }
104
            } ...
105
        }
106
        //当不能使用handover(或者说不需要使用),此时一般就是小数据
107
        if (!result && m != null && snepClient != null) {
108
            if (DBG) Log.d(TAG, "Sending ndef via SNEP");
109
            try {
110
                //直接优先使用snepClient去进行传输.
111
                int snepResult = doSnepProtocol(m);
112
                switch (snepResult) {
113
                    case SNEP_SUCCESS:
114
                        result = true;
115
                        break;
116
                    case SNEP_FAILURE:
117
                        result = false;
118
                        break;
119
                    default:
120
                        result = false;
121
                }
122
            } ...
123
        }
124
        //当snepclient不能成功传输的时候,再使用NdefPushClient.
125
        if (!result && m != null && nppClient != null) {
126
            result = nppClient.push(m);
127
        }
128
129
        //成功传输的时候.
130
        if (result) {
131
            onSendComplete(m, time);
132
        }
133
134
        return null;
135
    }
136
};
       先看发送完成的关于onSendComplete.
1
//P2pLinkManager中的onSendComplete
2
void onSendComplete(NdefMessage msg, long elapsedRealtime) {
3
    // Make callbacks on UI thread
4
    mHandler.sendEmptyMessage(MSG_SEND_COMPLETE);
5
}
6
case MSG_SEND_COMPLETE:
7
    synchronized (P2pLinkManager.this) {
8
        //释放SendTask.
9
        mSendTask = null;
10
        ......
11
        //发送状态设置为SEND_STATE_COMPLETE
12
        mSendState = SEND_STATE_COMPLETE;
13
        //移除timeout.
14
        mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
15
        if (DBG) Log.d(TAG, "onP2pSendComplete()");
16
        mEventListener.onP2pSendComplete();
17
        //这个是app注册了mCallbackNdef以后的回调.
18
        if (mCallbackNdef != null) {
19
            try {
20
                mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion);
21
            } catch (Exception e) {
22
                Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage());
23
            }
24
        }
25
    }
26
    break;
27
28
//P2pEventManager中的onP2pSendComplete源码.
29
@Override
30
public void onP2pSendComplete() {
31
    mNfcService.playSound(NfcService.SOUND_END);
32
    mVibrator.vibrate(VIBRATION_PATTERN, -1);
33
    if (mSendUi != null) {
34
        mSendUi.finish(SendUi.FINISH_SEND_SUCCESS);
35
    }
36
    mSending = false;
37
    mNdefSent = true;
38
}
接下来依次介绍doHandover(uris)、doSnepProtocol(m)、nppClient.push(m)、onSendComplete(m, 
time)。
doHandover相关:
注意此处的handover是P2P的时候的发送端,也就是Client端的流程.
主要的工作:
  1)、调用HandoverClient把本地的NFC的请求,发到远端的server,通过:
      NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
      handoverClient.sendHandoverRequest(request);
      request是一个NdefMessage消息,符合NFC Form的相应协议标准,封装了蓝牙的地址、名字、
      秘钥等信息用于远端的配对和链接。此处通过响应的socket协议发送.
  2)、调用BeamManager的startBeamSend开始传输工作,来配合远端的手机进行Beam传输.

HandoverClient中的sendHandoverRequest
1
public NdefMessage sendHandoverRequest(NdefMessage msg) throws IOException {
2
    ......
3
    //在初始化相关的介绍中我们提到过,LlcpSocket代表LLCP中的client端,
4
    //由NativeLlcpSocket它来实现的.
5
    LlcpSocket sock = null;
6
    synchronized (mLock) {
7
        ......
8
        sock = mSocket;
9
    }
10
    int offset = 0;
11
    byte[] buffer = msg.toByteArray();
12
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
13
    try {
14
        int remoteMiu = sock.getRemoteMiu();
15
        if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
16
        while (offset < buffer.length) {
17
            int length = Math.min(buffer.length - offset, remoteMiu);
18
            byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length);
19
            if (DBG) Log.d(TAG, "about to send a " + length + " byte packet");
20
            //Handover Client端往外发送消息.
21
            sock.send(tmpBuffer);
22
            offset += length;
23
        }
24
25
        //读取通过handover来获得的response.
26
        // Now, try to read back the handover response
27
        byte[] partial = new byte[sock.getLocalMiu()];
28
        NdefMessage handoverSelectMsg = null;
29
        while (true) {
30
            int size = sock.receive(partial);
31
            Log.d(TAG, "about to receive size = " + size );
32
            if (size < 0) {
33
                break;
34
            }
35
            byteStream.write(partial, 0, size);
36
            try {
37
                //此处暂不清楚具体获取的是什么,应该也是BT相关的一些信息,用于配对和链接等。
38
                //都应该是按照NFC handover相关的协议的,实例化成NdefMessage.
39
                handoverSelectMsg = new NdefMessage(byteStream.toByteArray());
40
                // If we get here, message is complete
41
                break;
42
            }...
43
        }
44
        return handoverSelectMsg;
45
    } ...
46
    return null;
47
}
//Beamanager
1
public boolean startBeamSend(Context context,
2
                          HandoverDataParser.BluetoothHandoverData 
3
                          outgoingHandoverData,
4
                          Uri[] uris, UserHandle userHandle) {
5
    ......
6
    BeamTransferRecord transferRecord = BeamTransferRecord.forBluetoothDevice(
7
            outgoingHandoverData.device, outgoingHandoverData.carrierActivating,
8
            uris);
9
    Intent sendIntent = new Intent(context.getApplicationContext(),
10
            BeamSendService.class);
11
    sendIntent.putExtra(BeamSendService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
12
    sendIntent.putExtra(BeamSendService.EXTRA_BEAM_COMPLETE_CALLBACK,
13
            new Messenger(mCallback));
14
    //国内过CTA测试的时候的弹框,毕竟不能偷偷地打开呀!
15
    if (CtaUtils.showCtaBtDialogIfNeeded(context, mCallback, sendIntent, null)) {
16
        return true;
17
    }
18
  //启动BeamSendService这个服务,
19
    context.startServiceAsUser(sendIntent, userHandle);
20
    return true;
21
}
//BeamSendService
主要工作:
1
1)、new BeamTransferManager;
2
    2)、new BeamStatusReceiver;
3
    3)、mBluetoothAdapter.enableNoAutoConnect()(if not enable BT)
4
      and when BT enable handleBluetoothStateChanged();
5
    4)、mTransferManager.start();
相关源码
1
public class BeamSendService extends Service implements 
2
                BeamTransferManager.Callback {
3
    ......
4
    private BeamTransferManager mTransferManager;
5
    private BeamStatusReceiver mBeamStatusReceiver;
6
    ......
7
    private final BluetoothAdapter mBluetoothAdapter;
8
    private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() 
9
    {
10
        @Override
11
        public void onReceive(Context context, Intent intent) {
12
            String action = intent.getAction();
13
            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
14
                handleBluetoothStateChanged(intent);
15
            }
16
        }
17
    };
18
    
19
    private void handleBluetoothStateChanged(Intent intent) {
20
        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
21
                BluetoothAdapter.ERROR);
22
        //当一开始蓝牙是关闭的,然后我们会调用enableNoAutoConnect()去无痕迹的打开BT.
23
        if (state == BluetoothAdapter.STATE_ON) {
24
            if (mTransferManager != null &&
25
                    mTransferManager.mDataLinkType == 
26
                BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
27
                //调用start开始传输
28
                mTransferManager.start();
29
            }
30
        }
31
    }
32
    ......
33
    @Override
34
    public void onCreate() {
35
        ......
36
        //注册BT状态改变的广播
37
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
38
        registerReceiver(mBluetoothStateReceiver, filter);
39
    }
40
    
41
    @Override
42
    public int onStartCommand(Intent intent, int flags, int startId) {
43
        ......
44
      BeamTransferRecord transferRecord;
45
      ......
46
        mCompleteCallback = intent.getParcelableExtra(EXTRA_BEAM_COMPLETE_CALLBACK);
47
        if (doTransfer(transferRecord)) {
48
            if (DBG) Log.i(TAG, "Starting outgoing Beam transfer");
49
            return START_STICKY;
50
        } ...
51
    }
52
    boolean doTransfer(BeamTransferRecord transferRecord) {
53
        if (createBeamTransferManager(transferRecord)) {
54
            // register Beam status receiver
55
            mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
56
            registerReceiver(mBeamStatusReceiver, 
57
                             mBeamStatusReceiver.getIntentFilter(),
58
                    BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
59
60
            if (transferRecord.dataLinkType == 
61
                BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
62
                //如果蓝牙已经打开的话,直接开始传输.
63
                if (mBluetoothAdapter.isEnabled()) {
64
                    mTransferManager.start();
65
                } else {
66
                    //系统内部app调用的接口,此时蓝牙打开不会被记录,也不会自动连接.
67
                    if (!mBluetoothAdapter.enableNoAutoConnect()) {
68
                        ......
69
                        return false;
70
                    }
71
                    mBluetoothEnabledByNfc = true;
72
                }
73
            }
74
            return true;
75
        }
76
        return false;
77
    }
78
    boolean createBeamTransferManager(BeamTransferRecord transferRecord) {
79
        ......
80
        mTransferManager = new BeamTransferManager(this, this, transferRecord, false);
81
        //跟新通知栏,准备开始传输数据.
82
        mTransferManager.updateNotification();
83
        return true;
84
    }
85
}
86
87
//其中关于BeamTransferManager
88
public BeamTransferManager(Context context, Callback callback,
89
                          BeamTransferRecord pendingTransfer, boolean incoming) {
90
    ......
91
    //代表远端BT的BluetoothDevice对象.
92
    mRemoteDevice = pendingTransfer.remoteDevice;
93
    //是往外发送还是接受
94
    mIncoming = incoming;
95
    ......
96
    //传输的文件的总数,
97
    //是发送方的时候uris最开始传入的地方就是在prepareMessageToSend中的createBeamShareData
98
    //是由第三方app设置要传输的内容的。
99
    //当是接受放的时候刚到这里mTotalCount为0,在后续会被设置为正确的count.
100
    mTotalCount = (pendingTransfer.uris != null) ? pendingTransfer.uris.length : 0;
101
    //通知栏上当前的进度
102
    mProgress = 0.0f;
103
    //状态
104
    mState = STATE_NEW;
105
    //要传输的uri
106
    mUris = pendingTransfer.uris == null
107
            ? new ArrayList<Uri>()
108
            : new ArrayList<Uri>(Arrays.asList(pendingTransfer.uris));
109
    ......
110
    //当前的count和总共的count
111
    mCurrentCount = 0;
112
    mSuccessCount = 0;
113
    //往外传输的uris.
114
    mOutgoingUris = pendingTransfer.uris;
115
    //......
116
    mHandler = new Handler(Looper.getMainLooper(), this);
117
    //用来检测当前transfer时候处于活动状态.
118
    mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS);
119
    mNotificationManager = (NotificationManager) mContext.getSystemService(
120
            Context.NOTIFICATION_SERVICE);
121
    ......
122
}
123
//start
124
public void start() {
125
    ......
126
    //如果是发送方mIncoming就是false,当是接收方的时候就是true,就到此为止了.
127
    if (!mIncoming) {
128
        if (mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
129
            new BluetoothOppHandover(mContext, mRemoteDevice, mUris, 
130
                                     mRemoteActivating).start();
131
        }
132
    }
133
}
134
135
//BluetoothOppHandover的start()
136
/**
137
* Main entry point. This method is usually called after construction,
138
* to begin the BT sequence. Must be called on Main thread.
139
*/
140
public void start() {
141
    //测试的时候抓取Log发现mRemoteActivating为true.
142
    if (mRemoteActivating) {
143
        Long timeElapsed = SystemClock.elapsedRealtime() - mCreateTime;
144
        if (timeElapsed < REMOTE_BT_ENABLE_DELAY_MS) {
145
            mHandler.sendEmptyMessageDelayed(MSG_START_SEND,
146
                    REMOTE_BT_ENABLE_DELAY_MS - timeElapsed);
147
        } else {
148
            // Already waited long enough for BT to come up
149
            // - start send.
150
            sendIntent();
151
        }
152
    } else {
153
        // Remote BT enabled already, start send immediately
154
        sendIntent();
155
    }
156
}
157
void sendIntent() {
158
    Intent intent = new Intent();
159
    intent.setPackage("com.android.bluetooth");
160
    String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris.get(0));
161
    intent.setType(mimeType);
162
    intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
163
    ......
164
    //一个的时候发送ACTION_HANDOVER_SEND,多个的时候发送ACTION_HANDOVER_SEND_MULTIPLE.
165
    if (mUris.size() == 1) {
166
        intent.setAction(ACTION_HANDOVER_SEND);
167
        intent.putExtra(Intent.EXTRA_STREAM, mUris.get(0));
168
    } else {
169
        intent.setAction(ACTION_HANDOVER_SEND_MULTIPLE);
170
        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mUris);
171
    }
172
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
173
    mContext.sendBroadcast(intent);
174
    //complete里面就是把mState = STATE_COMPLETE;
175
    complete();
176
}
     至此发送方Nfc端的流程就完成了,但是BT端也会有流程,此处做一个简单的分析。(有个疑问就
是不知道两边的BT什么时候配对链接的???可能启动了各个服务尝试去连接远程触发的代码,进
而建立连接)
在BT中的BluetoothOppHandoverReceiver :
    接收到Intent以后调用BluetoothOppManager中的saveSendingFileInfo进行相应变量的保存
    和startTransfer(device)开始Handover传输.
BluetoothOppManager:
    1)、startTransfer开启一个线程把要传输的Info存入到database当中.
        通过 inner Class InsertShareInfoThread.run().insertMultipleShare/insertSingleShare
    2)、用insertMultipleShare举例,最终insert到数据库当中
注意后面的这些差写入操作是异步的在一个单独的线程中,所以Log看起来就比较随意。到此处位置
的流程,并不能看到和蓝牙的进一步交互了,接下来的一系列的动作可能就是和远端的BT相互传输
的时候触发的吧或者说本身蓝牙初始化,建立完链接以后的动作.(好像是有个循环一直在等,有数据就
会发送).
    到此位置Handover中关于P2p的流程已经分析完毕,至于详细的Handover的一些信息解析此处没
有涉及到。
     我们再回到SendTask中的doInBackground,跳过doHandover()以后执行的是doSnepProtocol();
此时就不需要和BT交互了,是要直接通过NFC传输完的,为方便观察再次贴出代码
1
int doSnepProtocol(NdefMessage msg) throws IOException {
2
    if (msg != null) {
3
        snepClient.put(msg);
4
        return SNEP_SUCCESS;
5
    } ...
6
}
    SnepClient类中的put方法,
1
public void put(NdefMessage msg) throws IOException {
2
    //一些个判断.
3
    SnepMessenger messenger;
4
    synchronized (this) {
5
        if (mState != CONNECTED) {
6
            throw new IOException("Socket not connected.");
7
        }
8
        messenger = mMessenger;
9
    }
10
    //重要的是SnepMessenger的sendMessage和getMessage
11
    synchronized (mTransmissionLock) {
12
        try {
13
            //下面两个方法就是Android按照SNEP协议进行编写执行的。
14
            //通过SnepMessenger进行发送,SnepMessenger实现了协议.
15
            messenger.sendMessage(SnepMessage.getPutRequest(msg));
16
            messenger.getMessage();
17
        }...
18
    }
19
}
     客户端生成一个put请求的SnepMessage信息。REQUEST_PUT
1
public static SnepMessage getPutRequest(NdefMessage ndef) {
2
    return new SnepMessage(VERSION, REQUEST_PUT, ndef.toByteArray().length, 0, ndef);
3
}
     接下来就是真正的按照协议写的地方(网上的解析)
1
public void sendMessage(SnepMessage msg) throws IOException {
2
    byte[] buffer = msg.toByteArray();
3
    ...
4
    //取当前buffer的长度和定义的Fragment中较小值,看看是不是需要分段发送,先取出来较小的那个.
5
    int length = Math.min(buffer.length, mFragmentLength);
6
    byte[] tmpBuffer = Arrays.copyOfRange(buffer, 0, length);
7
    if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
8
    //将消息透过socket发送出去
9
    //final LlcpSocket mSocket实例化SnepMessage时传入的,最初是在SnepCLient实例化的时候
10
    //调用到connect的时候,调用如下产生
11
    //socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024);
12
    mSocket.send(tmpBuffer);
13
    //若数据包不用切割(一个数据包能发完),则直接返回 
14
    if (length == buffer.length) {
15
        return;
16
    }
17
    // Look for Continue or Reject from peer.
18
    //按照Snep协议,若切片后发送,则需要等待对方的回复后再决定下一步行动
19
    int offset = length;
20
    byte[] responseBytes = new byte[HEADER_LENGTH];
21
    //调用socket去接受server端的回复。
22
    mSocket.receive(responseBytes);
23
    SnepMessage snepResponse;
24
    try {
25
        snepResponse = SnepMessage.fromByteArray(responseBytes);
26
    } ...
27
    if (DBG) Log.d(TAG, "Got response from first fragment: " + 
28
                   snepResponse.getField());
29
    ...
30
    // 符合要求后,将剩余的数据发送完成 
31
    while (offset < buffer.length) {
32
        length = Math.min(buffer.length - offset, mFragmentLength);
33
        tmpBuffer = Arrays.copyOfRange(buffer, offset, offset + length);
34
        if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
35
        //一直发送!
36
        mSocket.send(tmpBuffer);
37
        if(NfcService.sIsDtaMode) {
38
            ......
39
        }
40
        offset += length;
41
    }
42
}
  根据协议,发送完毕后需要等待对方的response消息,就进入了getMessage()阶段,代码分析下:
1
public SnepMessage getMessage() throws IOException, SnepException {
2
    ......
3
    //等待对方的回复消息.
4
    size = mSocket.receive(partial);
5
    if (DBG) Log.d(TAG, "read " + size + " bytes");
6
    if (size < 0) {
7
        try {
8
            //接收的数据大小小于0,直接回复Reject 
9
            mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
10
        } ...
11
    } else if (size < HEADER_LENGTH) {
12
        //根据协议,接收的数据小于Header.size(因为Snep数据必须包含Header),直接回复Reject.
13
        try {
14
            if((NfcService.sIsDtaMode)&&(mIsClient)){
15
                if (DBG) Log.d(TAG, "Invalid header length");
16
                close();
17
            } else {
18
                mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
19
            }
20
            mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
21
        } ...
22
    } else {
23
        //更新buffer值
24
        readSize = size - HEADER_LENGTH;
25
        buffer.write(partial, 0, size);
26
    }
27
    DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(partial));
28
    requestVersion = dataIn.readByte();
29
    requestField = dataIn.readByte();
30
    requestLength = dataIn.readInt();
31
    if (DBG) Log.d(TAG, "read " + readSize + " of " + requestLength);
32
    //Header中携带的Version不匹配的时候,直接接收完成,退出。
33
    //如果接收数据小于Header中规定的数据,则请求对方继续发送,回复Continue,也是按照协议来的
34
    if (requestLength > readSize) {
35
        if (DBG) Log.d(TAG, "requesting continuation");
36
        mSocket.send(SnepMessage.getMessage(fieldContinue).toByteArray());
37
    } else {
38
        doneReading = true;
39
    }
40
    // Remaining fragments
41
    //让他continue以后,才能接受生剩余的
42
    while (!doneReading) {
43
        try {
44
            size = mSocket.receive(partial);
45
            if (DBG) Log.d(TAG, "read " + size + " bytes");
46
            if (size < 0) {
47
                try {
48
                    mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
49
                } ...
50
            } else {
51
                //正确接收数据,不断更新收到的数据 
52
                readSize += size;
53
                buffer.write(partial, 0, size);
54
                if (readSize == requestLength) {
55
                    doneReading = true;
56
                }
57
            }
58
        }...
59
    }
60
    try {
61
        //接收的肯定是二进制的数据流,将接收的数据转换成SNEP格式.
62
        return SnepMessage.fromByteArray(buffer.toByteArray());
63
    } catch (FormatException e) {
64
        Log.e(TAG, "Badly formatted NDEF message, ignoring", e);
65
        throw new SnepException(e);
66
    }
67
}
    可能当前的P2P并不支持SNEP协议,那么就会尝试用NPP协议进行数据的解析,这样就到了
NdefPushClient的push流程,此处现在的手机基本用不到,
1
public boolean push(NdefMessage msg) {
2
    LlcpSocket sock = null;
3
    synchronized (mLock) {
4
      ......
5
        sock = mSocket;
6
    }
7
    //按照制定格式创建NdefPushProtoco,没看过这个协议.
8
    NdefPushProtocol proto = new NdefPushProtocol(msg, 
9
                                                  NdefPushProtocol.ACTION_IMMEDIATE);
10
    ......
11
    try {
12
        remoteMiu = sock.getRemoteMiu();
13
        if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
14
        // 将当前信息完整的发送出去,一直到完成.
15
        while (offset < buffer.length) {
16
            int length = Math.min(buffer.length - offset, remoteMiu);
17
            byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length);
18
            if (DBG) Log.d(TAG, "about to send a " + length + " byte packet");
19
            sock.send(tmpBuffer);
20
            offset += length;
21
        }
22
        return true;
23
    } catch (IOException e) {
24
        ......
25
    } finally {
26
        ......
27
    }
28
    return false;
29
}
  上述操作都完成后,表示send数据已经完成,需要通知一下用户界面,我们继续返回
P2pLinkManager中的SendTask当中,往下走是调用onSendComplete去进一步处理.
  至此,完成了基本的发送方的流程,而对于进行P2P的时候的接收方。在onLlcpActivated()的时候
1
//此处值跟踪接受方相关的
2
public void onLlcpActivated(byte peerLlcpVersion) {
3
    synchronized (P2pLinkManager.this) {
4
        ...
5
        switch (mLinkState) {
6
            case LINK_STATE_DOWN:
7
                ...
8
                //下面的有屏幕截图,但是并不会显示
9
                mEventListener.onP2pInRange();
10
                mLinkState = LINK_STATE_UP;
11
                //同样会走到else.
12
                if (mSendState == SEND_STATE_PENDING) {
13
                    ......
14
                } else {
15
                    mSendState = SEND_STATE_NOTHING_TO_SEND;
16
                    prepareMessageToSend(true);
17
                    //执行完prepareMessageToSend后mMessageToSend和mUrisToSend都为null.
18
                    if (mMessageToSend != null ||
19
                            (mUrisToSend != null && 
20
                             mHandoverDataParser.isHandoverSupported())) {
21
                      ......
22
                    }
23
                    Log.d(TAG, "zhaoyuan connectLlcpServices over  mSendState = 
24
                          "+mSendState);
25
                }
26
                break;
27
            ...
28
        }
29
    }
30
}
     接收方此处相关的代码就执行到这里就结束了,不过那在你使用不同的协议进行传输数据的时
候,接收方的对应的server会做出相应.
    其中有:HandoverServer、SnepServer、NdefPushServer等.由于对SnepServer和
NdefPushServer是在一点也看不懂,
此处分析HandoverServer,其它两个也是类似的.(这几个server的初始化也在别的博客又提到)
1
private class ServerThread extends Thread {
2
        private boolean mThreadRunning = true;
3
        LlcpServerSocket mServerSocket;
4
        @Override
5
        public void run() {
6
            boolean threadRunning;
7
            ...
8
            while (threadRunning) {
9
                try {
10
                    synchronized (HandoverServer.this) {
11
                        mServerSocket = 
12
                            NfcService.getInstance().createLlcpServerSocket(mSap,
13
                                HANDOVER_SERVICE_NAME, MIU, 1, 1024);
14
                    }
15
                    ...
16
                    while (threadRunning) {
17
                        LlcpServerSocket serverSocket;
18
                        synchronized (HandoverServer.this) {
19
                            serverSocket = mServerSocket;
20
                        }
21
                        ......
22
                        //server段初始化完成以后,会block在此处
23
                        LlcpSocket communicationSocket = serverSocket.accept();
24
                        if (communicationSocket != null) {
25
                            //一旦有Client成功连接
26
                            new ConnectionThread(communicationSocket).start();
27
                        }
28
                        ......
29
                    }
30
                } ... 
31
            }
32
        }
33
        ......
34
    }
35
//关于ConnectionThread的run方法,我们只关注和P2P的流程相关的至于Handover协议相关的
36
//详细解析,暂布料机
37
public void run() {
38
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
39
    try {
40
        ...
41
        byte[] partial = new byte[mSock.getLocalMiu()];
42
        NdefMessage handoverRequestMsg = null;
43
        while (running) {
44
            int size = mSock.receive(partial);
45
            ...
46
            byteStream.write(partial, 0, size);
47
            try {
48
                handoverRequestMsg = new NdefMessage(byteStream.toByteArray());
49
            } ...
50
            if (handoverRequestMsg != null) {
51
                ......
52
                mCallback.onHandoverRequestReceived();
53
                //这是接收方(server)的BeamTransfer的入口,开始弹出通知更新流程等.
54
                if (!beamManager.startBeamReceive(mContext, 
55
                                                  handoverData.handoverData)) {
56
                    mCallback.onHandoverBusy();
57
                    break;
58
                }
59
                // We can process another handover transfer
60
                byteStream = new ByteArrayOutputStream();
61
            }
62
            ......
63
        }
64
    } ...
65
}
     然后重新进入到BeamManager中的startBeamReceive里面,基本的流程和Send差不多的.
1
public boolean startBeamReceive(Context context,
2
                        HandoverDataParser.BluetoothHandoverData handoverData) {
3
    ......
4
    BeamTransferRecord transferRecord =
5
            BeamTransferRecord.forBluetoothDevice(
6
                    handoverData.device, handoverData.carrierActivating, null);
7
8
    Intent receiveIntent = new Intent(context.getApplicationContext(),
9
            BeamReceiveService.class);
10
    receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, 
11
                           transferRecord);
12
    receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
13
            new Messenger(mCallback));
14
    //国内CTA相关的
15
    if (CtaUtils.showCtaBtDialogIfNeeded(context, mCallback,
16
            receiveIntent, handoverData.device)) {
17
        return true;
18
    }
19
    //添加到whitelistOppDevice就不会额外的弹出配对框
20
    whitelistOppDevice(context, handoverData.device);
21
    //启动BeamReceiveService.
22
    context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
23
    return true;
24
}
25
//BeamReceiveService相关的源码
26
public class BeamReceiveService extends Service implements 
27
    BeamTransferManager.Callback {
28
    @Override
29
    public int onStartCommand(Intent intent, int flags, int startId) {
30
        ......
31
        //可以看到基本和send的设计理念差不多
32
        if (prepareToReceive(transferRecord)) {
33
            if (DBG) Log.i(TAG, "Ready for incoming Beam transfer");
34
            return START_STICKY;
35
        }...
36
    }
37
    boolean prepareToReceive(BeamTransferRecord transferRecord) {
38
        ......
39
40
        if (!mBluetoothAdapter.isEnabled()) {
41
            //没有打开BT的时候自动打开
42
            if (!mBluetoothAdapter.enableNoAutoConnect()) {
43
                Log.e(TAG, "Error enabling Bluetooth.");
44
                return false;
45
            }
46
            mBluetoothEnabledByNfc = true;
47
        }
48
        //和Send同样实例化BeamTransferManager,只不过参数的实际值可能有点区别
49
        mTransferManager = new BeamTransferManager(this, this, transferRecord, true);
50
51
        //BeamStatusReceiver注册很多需要从BT接受的广播,都是和Transfer相关的
52
        mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
53
        registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
54
                BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
55
        //调用start开始,其实在发送方没做什么操作,可以看前面贴出的源码
56
        mTransferManager.start();
57
        //同样更新通知界面.
58
        mTransferManager.updateNotification();
59
        return true;
60
    }
61
}
62
//接下来就需要关于BeamStatusReceiver的分析了
63
public class BeamStatusReceiver extends BroadcastReceiver {
64
    ......
65
        @Override
66
    public void onReceive(Context context, Intent intent) {
67
        String action = intent.getAction();
68
        int dataLinkType = intent.getIntExtra(EXTRA_HANDOVER_DATA_LINK_TYPE,
69
                BeamTransferManager.DATA_LINK_TYPE_BLUETOOTH);
70
71
        if (ACTION_CANCEL_HANDOVER_TRANSFER.equals(action)) {
72
            if (mTransferManager != null) {
73
                mTransferManager.cancel();
74
            }
75
        } else if (ACTION_TRANSFER_PROGRESS.equals(action) ||
76
                ACTION_TRANSFER_DONE.equals(action) ||
77
                ACTION_HANDOVER_STARTED.equals(action)) {
78
            handleTransferEvent(intent, dataLinkType);
79
        }
80
    }
81
    public IntentFilter getIntentFilter() {
82
        IntentFilter filter = new IntentFilter(ACTION_TRANSFER_DONE);
83
        filter.addAction(ACTION_TRANSFER_PROGRESS);
84
        filter.addAction(ACTION_CANCEL_HANDOVER_TRANSFER);
85
        filter.addAction(ACTION_HANDOVER_STARTED);
86
        return filter;
87
    }
88
    private void handleTransferEvent(Intent intent, int deviceType) {
89
        String action = intent.getAction();
90
        String sourceAddress = intent.getStringExtra(EXTRA_ADDRESS);
91
        ......
92
        //ACTION_TRANSFER_DONE是当接受完毕后跟新通知界面的
93
        if (action.equals(ACTION_TRANSFER_DONE)) {
94
            int handoverStatus = intent.getIntExtra(EXTRA_TRANSFER_STATUS,
95
                    HANDOVER_TRANSFER_STATUS_FAILURE);
96
            if (handoverStatus == HANDOVER_TRANSFER_STATUS_SUCCESS) {
97
                String uriString = intent.getStringExtra(EXTRA_TRANSFER_URI);
98
                String mimeType = intent.getStringExtra(EXTRA_TRANSFER_MIMETYPE);
99
                Uri uri = Uri.parse(uriString);
100
                if (uri != null && uri.getScheme() == null) {
101
                    uri = Uri.fromFile(new File(uri.getPath()));
102
                }
103
                mTransferManager.finishTransfer(true, uri, mimeType);
104
            } else {
105
                mTransferManager.finishTransfer(false, null, null);
106
            }
107
        } else if (action.equals(ACTION_TRANSFER_PROGRESS)) {
108
            //传输的途中,更新通知栏传输的进程.
109
            float progress = intent.getFloatExtra(EXTRA_TRANSFER_PROGRESS, 0.0f);
110
            mTransferManager.updateFileProgress(progress);
111
        } else if (action.equals(ACTION_HANDOVER_STARTED)) {
112
            //进入到此处的时候证明接收方和远端的BT已经建立好链接,并且配对了.
113
            //下面就开始准备接受了,而EXTRA_OBJECT_COUNT,就是携带的总共需要接受的数量.
114
            int count = intent.getIntExtra(EXTRA_OBJECT_COUNT, 0);
115
            if (count > 0) {
116
                mTransferManager.setObjectCount(count);
117
            }
118
        }
119
    }
120
}
至于传输的通知栏的UI显示逻辑此处暂不深入了。
这样就完成了全部的P2P的java层的流程.
文章参考:
http://blog.youkuaiyun.com/xuwen0306/article/details/44724859

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值