• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.nfc;
18 
19 import android.content.Intent;
20 import android.content.pm.UserInfo;
21 
22 import com.android.nfc.beam.BeamManager;
23 import com.android.nfc.beam.BeamSendService;
24 import com.android.nfc.beam.BeamTransferRecord;
25 
26 import android.os.UserManager;
27 import com.android.nfc.sneptest.ExtDtaSnepServer;
28 import com.android.nfc.sneptest.DtaSnepClient;
29 import com.android.nfc.echoserver.EchoServer;
30 import com.android.nfc.handover.HandoverClient;
31 import com.android.nfc.handover.HandoverDataParser;
32 import com.android.nfc.handover.HandoverServer;
33 import com.android.nfc.ndefpush.NdefPushClient;
34 import com.android.nfc.ndefpush.NdefPushServer;
35 import com.android.nfc.snep.SnepClient;
36 import com.android.nfc.snep.SnepMessage;
37 import com.android.nfc.snep.SnepServer;
38 
39 import android.content.Context;
40 import android.content.SharedPreferences;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.PackageManager;
43 import android.content.pm.PackageManager.NameNotFoundException;
44 import android.net.Uri;
45 import android.nfc.BeamShareData;
46 import android.nfc.IAppCallback;
47 import android.nfc.NdefMessage;
48 import android.nfc.NdefRecord;
49 import android.nfc.NfcAdapter;
50 import android.os.AsyncTask;
51 import android.os.Handler;
52 import android.os.Message;
53 import android.os.SystemClock;
54 import android.os.UserHandle;
55 import android.util.Log;
56 import java.io.FileDescriptor;
57 import java.io.IOException;
58 import java.io.PrintWriter;
59 import java.nio.charset.StandardCharsets;
60 import java.util.Arrays;
61 import java.util.List;
62 import java.io.UnsupportedEncodingException;
63 
64 /**
65  * Interface to listen for P2P events.
66  * All callbacks are made from the UI thread.
67  */
68 interface P2pEventListener {
69     /**
70      * Indicates the user has expressed an intent to share
71      * over NFC, but a remote device has not come into range
72      * yet. Prompt the user to NFC tap.
73      */
onP2pNfcTapRequested()74     public void onP2pNfcTapRequested();
75 
76     /**
77      * Indicates the user has expressed an intent to share over
78      * NFC, but the link hasn't come up yet and we no longer
79      * want to wait for it
80      */
onP2pTimeoutWaitingForLink()81     public void onP2pTimeoutWaitingForLink();
82 
83     /**
84      * Indicates a P2P device is in range.
85      * <p>onP2pInRange() and onP2pOutOfRange() will always be called
86      * alternately.
87      */
onP2pInRange()88     public void onP2pInRange();
89 
90     /**
91      * Called when a NDEF payload is prepared to send, and confirmation is
92      * required. Call Callback.onP2pSendConfirmed() to make the confirmation.
93      */
onP2pSendConfirmationRequested()94     public void onP2pSendConfirmationRequested();
95 
96     /**
97      * Called to indicate a send was successful.
98      */
onP2pSendComplete()99     public void onP2pSendComplete();
100 
101     /**
102      *
103      * Called to indicate the link has broken while we were trying to send
104      * a message. We'll start a debounce timer for the user to get the devices
105      * back together. UI may show a hint to achieve that
106      */
onP2pSendDebounce()107     public void onP2pSendDebounce();
108 
109     /**
110      * Called to indicate a link has come back up after being temporarily
111      * broken, and sending is resuming
112      */
onP2pResumeSend()113     public void onP2pResumeSend();
114 
115     /**
116      * Called to indicate the remote device does not support connection handover
117      */
onP2pHandoverNotSupported()118     public void onP2pHandoverNotSupported();
119 
120     /**
121      * Called to indicate the device is busy with another handover transfer
122      */
onP2pHandoverBusy()123     public void onP2pHandoverBusy();
124 
125     /**
126      * Called to indicate a receive was successful.
127      */
onP2pReceiveComplete(boolean playSound)128     public void onP2pReceiveComplete(boolean playSound);
129 
130     /**
131      * Indicates the P2P device went out of range.
132      */
onP2pOutOfRange()133     public void onP2pOutOfRange();
134 
135     public interface Callback {
onP2pSendConfirmed()136         public void onP2pSendConfirmed();
onP2pCanceled()137         public void onP2pCanceled();
138     }
139 }
140 
141 /**
142  * Manages sending and receiving NDEF message over LLCP link.
143  * Does simple debouncing of the LLCP link - so that even if the link
144  * drops and returns the user does not know.
145  */
146 class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
147     static final String TAG = "NfcP2pLinkManager";
148     static final boolean DBG = true;
149 
150     /** Include this constant as a meta-data entry in the manifest
151      *  of an application to disable beaming the market/AAR link, like this:
152      *  <pre>{@code
153      *  <application ...>
154      *      <meta-data android:name="android.nfc.disable_beam_default"
155      *          android:value="true" />
156      *  </application>
157      *  }</pre>
158      */
159     static final String DISABLE_BEAM_DEFAULT = "android.nfc.disable_beam_default";
160 
161     /** Enables the LLCP EchoServer, which can be used to test the android
162      * LLCP stack against nfcpy.
163      */
164     static final boolean ECHOSERVER_ENABLED = false;
165 
166     // TODO dynamically assign SAP values
167     static final int NDEFPUSH_SAP = 0x10;
168     static final int HANDOVER_SAP = 0x14;
169 
170     static final int LINK_SEND_PENDING_DEBOUNCE_MS = 3000;
171     static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000;
172     static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 500;
173     static final int LINK_SEND_CANCELED_DEBOUNCE_MS = 250;
174 
175     // The amount of time we wait for the link to come up
176     // after a user has manually invoked Beam.
177     static final int WAIT_FOR_LINK_TIMEOUT_MS = 10000;
178 
179     static final int MSG_DEBOUNCE_TIMEOUT = 1;
180     static final int MSG_RECEIVE_COMPLETE = 2;
181     static final int MSG_RECEIVE_HANDOVER = 3;
182     static final int MSG_SEND_COMPLETE = 4;
183     static final int MSG_START_ECHOSERVER = 5;
184     static final int MSG_STOP_ECHOSERVER = 6;
185     static final int MSG_HANDOVER_NOT_SUPPORTED = 7;
186     static final int MSG_SHOW_CONFIRMATION_UI = 8;
187     static final int MSG_WAIT_FOR_LINK_TIMEOUT = 9;
188     static final int MSG_HANDOVER_BUSY = 10;
189 
190     // values for mLinkState
191     static final int LINK_STATE_DOWN = 1;
192     static final int LINK_STATE_UP = 2;
193     static final int LINK_STATE_DEBOUNCE = 3;
194 
195     // values for mSendState
196     static final int SEND_STATE_NOTHING_TO_SEND = 1;
197     static final int SEND_STATE_NEED_CONFIRMATION = 2;
198     static final int SEND_STATE_PENDING = 3;
199     static final int SEND_STATE_SENDING = 4;
200     static final int SEND_STATE_COMPLETE = 5;
201     static final int SEND_STATE_CANCELED = 6;
202 
203     // return values for doSnepProtocol
204     static final int SNEP_SUCCESS = 0;
205     static final int SNEP_FAILURE = 1;
206 
207     // return values for doHandover
208     static final int HANDOVER_SUCCESS = 0;
209     static final int HANDOVER_FAILURE = 1;
210     static final int HANDOVER_UNSUPPORTED = 2;
211     static final int HANDOVER_BUSY = 3;
212 
213     final NdefPushServer mNdefPushServer;
214     final SnepServer mDefaultSnepServer;
215     final HandoverServer mHandoverServer;
216     final EchoServer mEchoServer;
217     final Context mContext;
218     final P2pEventListener mEventListener;
219     final Handler mHandler;
220     final HandoverDataParser mHandoverDataParser;
221     final ForegroundUtils mForegroundUtils;
222 
223     final int mDefaultMiu;
224     final int mDefaultRwSize;
225 
226     // Locked on NdefP2pManager.this
227     PackageManager mPackageManager;
228     int mLinkState;
229     int mSendState;  // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE
230     boolean mIsSendEnabled;
231     boolean mIsReceiveEnabled;
232     NdefMessage mMessageToSend;  // not valid in SEND_STATE_NOTHING_TO_SEND
233     Uri[] mUrisToSend;  // not valid in SEND_STATE_NOTHING_TO_SEND
234     UserHandle mUserHandle; // not valid in SEND_STATE_NOTHING_TO_SEND
235     int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND
236     IAppCallback mCallbackNdef;
237     int mNdefCallbackUid;
238     SendTask mSendTask;
239     SharedPreferences mPrefs;
240     SnepClient mSnepClient;
241     HandoverClient mHandoverClient;
242     NdefPushClient mNdefPushClient;
243     ConnectTask mConnectTask;
244     boolean mLlcpServicesConnected;
245     long mLastLlcpActivationTime;
246     byte mPeerLlcpVersion;
247     // for DTA Mode
248     private int mDtaMiu;
249     private int mDtaRwSize;
250     private int mServiceSap;
251     private int mTestCaseID;
252     private String mServiceName;
253     private ExtDtaSnepServer mExtDtaSnepServer = null;
254     private DtaSnepClient mDtaSnepClient = null;
255     private boolean mClientEnabled = false;
256     private boolean mServerEnabled = false;
257     private boolean mExtDtaSnepServerRunning = false;
258     private boolean mPutBeforeGet = false;
259 
P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu, int defaultRwSize)260     public P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu,
261             int defaultRwSize) {
262         mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
263         mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
264         mHandoverServer = new HandoverServer(context, HANDOVER_SAP, handoverDataParser, mHandoverCallback);
265 
266         if (ECHOSERVER_ENABLED) {
267             mEchoServer = new EchoServer();
268         } else {
269             mEchoServer = null;
270         }
271         mPackageManager = context.getPackageManager();
272         mContext = context;
273         mEventListener = new P2pEventManager(context, this);
274         mHandler = new Handler(this);
275         mLinkState = LINK_STATE_DOWN;
276         mSendState = SEND_STATE_NOTHING_TO_SEND;
277         mIsSendEnabled = false;
278         mIsReceiveEnabled = false;
279         mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE);
280         mHandoverDataParser = handoverDataParser;
281         mDefaultMiu = defaultMiu;
282         mDefaultRwSize = defaultRwSize;
283         mLlcpServicesConnected = false;
284         mNdefCallbackUid = -1;
285         mForegroundUtils = ForegroundUtils.getInstance();
286      }
287 
288     /**
289      * May be called from any thread.
290      * Assumes that NFC is already on if any parameter is true.
291      */
enableDisable(boolean sendEnable, boolean receiveEnable)292     public void enableDisable(boolean sendEnable, boolean receiveEnable) {
293         synchronized (this) {
294             if (!mIsReceiveEnabled && receiveEnable) {
295                 mDefaultSnepServer.start();
296                 mNdefPushServer.start();
297                 mHandoverServer.start();
298                 if (mEchoServer != null) {
299                     mHandler.sendEmptyMessage(MSG_START_ECHOSERVER);
300                 }
301             } else if (mIsReceiveEnabled && !receiveEnable) {
302                 if (DBG) Log.d(TAG, "enableDisable: llcp deactivate");
303                 onLlcpDeactivated ();
304                 mDefaultSnepServer.stop();
305                 mNdefPushServer.stop();
306                 mHandoverServer.stop();
307                 if (mEchoServer != null) {
308                     mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER);
309                 }
310                 if (mExtDtaSnepServerRunning)
311                     disableExtDtaSnepServer();
312             }
313             mIsSendEnabled = sendEnable;
314             mIsReceiveEnabled = receiveEnable;
315         }
316     }
317 
318     /**
319      * To Enable DTA SNEP Server for NFC Forum testing
320      */
enableExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize,int testCaseId)321     public void enableExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize,int testCaseId) {
322         if (DBG) Log.d(TAG, "Enabling Extended DTA Server");
323         mServiceName = serviceName;
324         mServiceSap = serviceSap;
325         mDtaMiu = miu;
326         mDtaRwSize  = rwSize;
327         mTestCaseID = testCaseId;
328         synchronized (this) {
329             if(mExtDtaSnepServer == null)
330             mExtDtaSnepServer = new ExtDtaSnepServer(mServiceName, mServiceSap, mDtaMiu, mDtaRwSize,
331                                                      mExtDtaSnepServerCallback,mContext, mTestCaseID);
332             mExtDtaSnepServer.start();
333             mExtDtaSnepServerRunning = true;
334         }
335         mServerEnabled = true;
336     }
337 
338     /**
339      * To Disable DTA SNEP Server for NFC Forum testing
340      */
disableExtDtaSnepServer()341     public void disableExtDtaSnepServer() {
342         if (DBG) Log.d(TAG, "Disabling Extended DTA Server");
343         if (!mExtDtaSnepServerRunning)
344             return;
345         synchronized (this) {
346             mExtDtaSnepServer.stop();
347             mExtDtaSnepServer = null;
348             mExtDtaSnepServerRunning = false;
349         }
350         mServerEnabled = false;
351     }
352 
353     /**
354      * To Enable DTA SNEP Client for NFC Forum testing
355      */
enableDtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId)356     public void enableDtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId) {
357         if (DBG) Log.d(TAG, "enableDtaSnepClient");
358         mClientEnabled = true;
359         mServiceName = serviceName;
360         mServiceSap = -1;
361         mDtaMiu = miu;
362         mDtaRwSize = rwSize;
363         mTestCaseID = testCaseId;
364     }
365 
366     /**
367      * To Disable DTA SNEP Client for NFC Forum testing
368      */
disableDtaSnepClient()369     public void disableDtaSnepClient() {
370         if (DBG) Log.d(TAG, "disableDtaSnepClient");
371         mDtaSnepClient = null;
372         mClientEnabled = false;
373     }
374 
375 
376     /**
377      * May be called from any thread.
378      * @return whether the LLCP link is in an active or debounce state
379      */
isLlcpActive()380     public boolean isLlcpActive() {
381         synchronized (this) {
382             return mLinkState != LINK_STATE_DOWN;
383         }
384     }
385 
386     /**
387      * Set NDEF callback for sending.
388      * May be called from any thread.
389      * NDEF callbacks may be set at any time (even if NFC is
390      * currently off or P2P send is currently off). They will become
391      * active as soon as P2P send is enabled.
392      */
setNdefCallback(IAppCallback callbackNdef, int callingUid)393     public void setNdefCallback(IAppCallback callbackNdef, int callingUid) {
394         synchronized (this) {
395             mCallbackNdef = callbackNdef;
396             mNdefCallbackUid = callingUid;
397         }
398     }
399 
400 
onManualBeamInvoke(BeamShareData shareData)401     public void onManualBeamInvoke(BeamShareData shareData) {
402         synchronized (P2pLinkManager.this)    {
403             if (mLinkState != LINK_STATE_DOWN) {
404                 return;
405             }
406             if (mForegroundUtils.getForegroundUids().contains(mNdefCallbackUid)) {
407                 // Try to get data from the registered NDEF callback
408                 prepareMessageToSend(false);
409             } else {
410                 mMessageToSend = null;
411                 mUrisToSend = null;
412             }
413             if (mMessageToSend == null && mUrisToSend == null && shareData != null) {
414                 // No data from the NDEF callback, get data from ShareData
415                 if (shareData.uris != null) {
416                     mUrisToSend = shareData.uris;
417                 } else if (shareData.ndefMessage != null) {
418                     mMessageToSend = shareData.ndefMessage;
419                 }
420 
421                 mUserHandle = shareData.userHandle;
422             }
423             if (mMessageToSend != null ||
424                     (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
425                 mSendState = SEND_STATE_PENDING;
426                 mEventListener.onP2pNfcTapRequested();
427                 scheduleTimeoutLocked(MSG_WAIT_FOR_LINK_TIMEOUT, WAIT_FOR_LINK_TIMEOUT_MS);
428             }
429         }
430     }
431 
432     /**
433      * Must be called on UI Thread.
434      */
onLlcpActivated(byte peerLlcpVersion)435     public void onLlcpActivated(byte peerLlcpVersion) {
436         Log.i(TAG, "LLCP activated");
437         synchronized (P2pLinkManager.this) {
438             if (mEchoServer != null) {
439                 mEchoServer.onLlcpActivated();
440             }
441             mLastLlcpActivationTime = SystemClock.elapsedRealtime();
442             mPeerLlcpVersion = peerLlcpVersion;
443             switch (mLinkState) {
444                 case LINK_STATE_DOWN:
445                     if (DBG) Log.d(TAG, "onP2pInRange()");
446                     // Start taking a screenshot
447                     mEventListener.onP2pInRange();
448                     mLinkState = LINK_STATE_UP;
449                     // If we had a pending send (manual Beam invoke),
450                     // mark it as sending
451                     if (mSendState == SEND_STATE_PENDING) {
452                         mSendState = SEND_STATE_SENDING;
453                         mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT);
454                         // Immediately try to connect LLCP services
455                         connectLlcpServices();
456                     } else {
457                         mSendState = SEND_STATE_NOTHING_TO_SEND;
458                         prepareMessageToSend(true);
459                         if (mMessageToSend != null ||
460                                 (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
461                             // We have data to send, connect LLCP services
462                             connectLlcpServices();
463                             if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) {
464                                 mSendState = SEND_STATE_SENDING;
465                             } else {
466                                 mSendState = SEND_STATE_NEED_CONFIRMATION;
467                             }
468                         }
469                     }
470                     break;
471                 case LINK_STATE_UP:
472                     if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()");
473                     return;
474                 case LINK_STATE_DEBOUNCE:
475                     // Immediately connect and try to send again
476                     mLinkState = LINK_STATE_UP;
477                     if (mSendState == SEND_STATE_SENDING ||
478                             mSendState == SEND_STATE_NEED_CONFIRMATION) {
479                         // If we have something to send still, connect LLCP
480                         connectLlcpServices();
481                     }
482                     mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
483                     break;
484             }
485         }
486     }
487 
488     /**
489      * Must be called on UI Thread.
490      */
onLlcpFirstPacketReceived()491     public void onLlcpFirstPacketReceived() {
492         synchronized (P2pLinkManager.this) {
493             long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime;
494             if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU");
495         }
496     }
497 
onUserSwitched(int userId)498     public void onUserSwitched(int userId) {
499         // Update the cached package manager in case of user switch
500         synchronized (P2pLinkManager.this) {
501             try {
502                 mPackageManager  = mContext.createPackageContextAsUser("android", 0,
503                         new UserHandle(userId)).getPackageManager();
504             } catch (NameNotFoundException e) {
505                 Log.e(TAG, "Failed to retrieve PackageManager for user");
506             }
507         }
508     }
509 
prepareMessageToSend(boolean generatePlayLink)510     void prepareMessageToSend(boolean generatePlayLink) {
511         synchronized (P2pLinkManager.this) {
512             mMessageToSend = null;
513             mUrisToSend = null;
514             if (!mIsSendEnabled) {
515                 return;
516             }
517 
518             List<Integer> foregroundUids = mForegroundUtils.getForegroundUids();
519             if (foregroundUids.isEmpty()) {
520                 Log.e(TAG, "Could not determine foreground UID.");
521                 return;
522             }
523 
524             if (isBeamDisabled(foregroundUids.get(0))) {
525                 if (DBG) Log.d(TAG, "Beam is disabled by policy.");
526                 return;
527             }
528 
529             if (mCallbackNdef != null) {
530                 if (foregroundUids.contains(mNdefCallbackUid)) {
531                     try {
532                         BeamShareData shareData = mCallbackNdef.createBeamShareData(mPeerLlcpVersion);
533                         mMessageToSend = shareData.ndefMessage;
534                         mUrisToSend = shareData.uris;
535                         mUserHandle = shareData.userHandle;
536                         mSendFlags = shareData.flags;
537                         return;
538                     } catch (Exception e) {
539                         Log.e(TAG, "Failed NDEF callback: ", e);
540                     }
541                 } else {
542                     // This is not necessarily an error - we no longer unset callbacks from
543                     // the app process itself (to prevent IPC calls on every pause).
544                     // Hence it may simply be a stale callback.
545                     if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground.");
546                 }
547             }
548 
549             // fall back to default NDEF for the foreground activity, unless the
550             // application disabled this explicitly in their manifest.
551             String[] pkgs = mPackageManager.getPackagesForUid(foregroundUids.get(0));
552             if (pkgs != null && pkgs.length >= 1) {
553                 if (!generatePlayLink || beamDefaultDisabled(pkgs[0])) {
554                     if (DBG) Log.d(TAG, "Disabling default Beam behavior");
555                     mMessageToSend = null;
556                     mUrisToSend = null;
557                 } else {
558                     mMessageToSend = createDefaultNdef(pkgs[0]);
559                     mUrisToSend = null;
560                     mSendFlags = 0;
561                 }
562             }
563 
564             if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend);
565             if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend);
566         }
567     }
568 
isBeamDisabled(int uid)569     private boolean isBeamDisabled(int uid) {
570         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
571         UserInfo userInfo = userManager.getUserInfo(UserHandle.getUserId(uid));
572         return userManager.hasUserRestriction(
573                         UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle());
574 
575     }
576 
beamDefaultDisabled(String pkgName)577     boolean beamDefaultDisabled(String pkgName) {
578         try {
579             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName,
580                     PackageManager.GET_META_DATA);
581             if (ai == null || ai.metaData == null) {
582                 return false;
583             }
584             return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT);
585         } catch (NameNotFoundException e) {
586             return false;
587         }
588     }
589 
createDefaultNdef(String pkgName)590     NdefMessage createDefaultNdef(String pkgName) {
591         NdefRecord appUri = NdefRecord.createUri(Uri.parse(
592                 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam"));
593         NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName);
594         return new NdefMessage(new NdefRecord[] { appUri, appRecord });
595     }
596 
disconnectLlcpServices()597     void disconnectLlcpServices() {
598         synchronized (this) {
599             if (mConnectTask != null) {
600                 mConnectTask.cancel(true);
601                 mConnectTask = null;
602             }
603             // Close any already connected LLCP clients
604             if (mNdefPushClient != null) {
605                 mNdefPushClient.close();
606                 mNdefPushClient = null;
607             }
608             if (mSnepClient != null) {
609                 mSnepClient.close();
610                 mSnepClient = null;
611             }
612             if (mHandoverClient != null) {
613                 mHandoverClient.close();
614                 mHandoverClient = null;
615             }
616             mLlcpServicesConnected = false;
617         }
618     }
619 
620     /**
621      * Must be called on UI Thread.
622      */
onLlcpDeactivated()623     public void onLlcpDeactivated() {
624         Log.i(TAG, "LLCP deactivated.");
625         synchronized (this) {
626             if (mEchoServer != null) {
627                 mEchoServer.onLlcpDeactivated();
628             }
629 
630             switch (mLinkState) {
631                 case LINK_STATE_DOWN:
632                 case LINK_STATE_DEBOUNCE:
633                     Log.i(TAG, "Duplicate onLlcpDectivated()");
634                     break;
635                 case LINK_STATE_UP:
636                     // Debounce
637                     mLinkState = LINK_STATE_DEBOUNCE;
638                     int debounceTimeout = 0;
639                     switch (mSendState) {
640                         case SEND_STATE_NOTHING_TO_SEND:
641                             debounceTimeout = 0;
642                             break;
643                         case SEND_STATE_NEED_CONFIRMATION:
644                             debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS;
645                             break;
646                         case SEND_STATE_SENDING:
647                             debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS;
648                             break;
649                         case SEND_STATE_COMPLETE:
650                             debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS;
651                             break;
652                         case SEND_STATE_CANCELED:
653                             debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS;
654                     }
655                     scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout);
656                     if (mSendState == SEND_STATE_SENDING) {
657                         Log.e(TAG, "onP2pSendDebounce()");
658                         mEventListener.onP2pSendDebounce();
659                     }
660                     cancelSendNdefMessage();
661                     disconnectLlcpServices();
662                     break;
663             }
664          }
665      }
666 
onHandoverUnsupported()667     void onHandoverUnsupported() {
668         mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED);
669     }
670 
onHandoverBusy()671     void onHandoverBusy() {
672         mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY);
673     }
674 
onSendComplete(NdefMessage msg, long elapsedRealtime)675     void onSendComplete(NdefMessage msg, long elapsedRealtime) {
676         // Make callbacks on UI thread
677         mHandler.sendEmptyMessage(MSG_SEND_COMPLETE);
678     }
679 
sendNdefMessage()680     void sendNdefMessage() {
681         synchronized (this) {
682             cancelSendNdefMessage();
683             mSendTask = new SendTask();
684             mSendTask.execute();
685         }
686     }
687 
cancelSendNdefMessage()688     void cancelSendNdefMessage() {
689         synchronized (P2pLinkManager.this) {
690             if (mSendTask != null) {
691                 mSendTask.cancel(true);
692             }
693         }
694     }
695 
connectLlcpServices()696     void connectLlcpServices() {
697         synchronized (P2pLinkManager.this) {
698             if (mConnectTask != null) {
699                 Log.e(TAG, "Still had a reference to mConnectTask!");
700             }
701             mConnectTask = new ConnectTask();
702             mConnectTask.execute();
703         }
704     }
705 
706     // Must be called on UI-thread
onLlcpServicesConnected()707     void onLlcpServicesConnected() {
708         if (DBG) Log.d(TAG, "onLlcpServicesConnected");
709         synchronized (P2pLinkManager.this) {
710             if (mLinkState != LINK_STATE_UP) {
711                 return;
712             }
713             mLlcpServicesConnected = true;
714             if (mSendState == SEND_STATE_NEED_CONFIRMATION) {
715                 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()");
716                 mEventListener.onP2pSendConfirmationRequested();
717             } else if (mSendState == SEND_STATE_SENDING) {
718                 mEventListener.onP2pResumeSend();
719                 sendNdefMessage();
720             } else {
721                 // Either nothing to send or canceled/complete, ignore
722             }
723         }
724     }
725 
726     final class ConnectTask extends AsyncTask<Void, Void, Boolean> {
727         @Override
onPostExecute(Boolean result)728         protected void onPostExecute(Boolean result)  {
729             if (isCancelled()) {
730                 if (DBG) Log.d(TAG, "ConnectTask was cancelled");
731                 return;
732             }
733             if (result) {
734                 onLlcpServicesConnected();
735             } else {
736                 Log.e(TAG, "Could not connect required NFC transports");
737             }
738         }
739 
740         @Override
doInBackground(Void... params)741         protected Boolean doInBackground(Void... params) {
742             boolean needsHandover = false;
743             boolean needsNdef = false;
744             boolean success = false;
745             HandoverClient handoverClient = null;
746             SnepClient snepClient = null;
747             NdefPushClient nppClient = null;
748 
749             synchronized(P2pLinkManager.this) {
750                 if (mUrisToSend != null) {
751                     needsHandover = true;
752                 }
753 
754                 if (mMessageToSend != null) {
755                     needsNdef = true;
756                 }
757             }
758             // We know either is requested - otherwise this task
759             // wouldn't have been started.
760             if (needsHandover) {
761                 handoverClient = new HandoverClient();
762                 try {
763                     handoverClient.connect();
764                     success = true; // Regardless of NDEF result
765                 } catch (IOException e) {
766                     handoverClient = null;
767                 }
768             }
769             if (needsNdef || (needsHandover && handoverClient == null)) {
770                 if (NfcService.sIsDtaMode) {
771                     if (mClientEnabled) {
772                         if (mDtaSnepClient == null) {
773                             if (DBG) Log.d(TAG, "Creating DTA Snep Client");
774                             mDtaSnepClient = new DtaSnepClient(mServiceName, mDtaMiu, mDtaRwSize, mTestCaseID);
775                         }
776                     }
777                 } else
778                     snepClient = new SnepClient();
779                 try {
780                     if (NfcService.sIsDtaMode) {
781                         if (mDtaSnepClient != null)
782                             mDtaSnepClient.DtaClientOperations(mContext);
783                     }
784                     else
785                         snepClient.connect();
786                     success = true;
787                     mDtaSnepClient = null;
788                 } catch (IOException e) {
789                     snepClient = null;
790                 }
791 
792                 if (!success) {
793                     nppClient = new NdefPushClient();
794                     try {
795                         nppClient.connect();
796                         success = true;
797                     } catch (IOException e) {
798                         nppClient = null;
799                     }
800                 }
801             }
802 
803             synchronized (P2pLinkManager.this) {
804                 if (isCancelled()) {
805                     // Cancelled by onLlcpDeactivated on UI thread
806                     if (handoverClient != null) {
807                         handoverClient.close();
808                     }
809                     if (snepClient != null) {
810                         snepClient.close();
811                     }
812                     if (nppClient != null) {
813                         nppClient.close();
814                     }
815                     if (mDtaSnepClient != null) {
816                         mDtaSnepClient.close();
817                     }
818                     return false;
819                 } else {
820                     // Once assigned, these are the responsibility of
821                     // the code on the UI thread to release - typically
822                     // through onLlcpDeactivated().
823                     mHandoverClient = handoverClient;
824                     mSnepClient = snepClient;
825                     mNdefPushClient = nppClient;
826                     return success;
827                 }
828             }
829         }
830     };
831 
832     final class SendTask extends AsyncTask<Void, Void, Void> {
833         NdefPushClient nppClient;
834         SnepClient snepClient;
835         HandoverClient handoverClient;
836 
doHandover(Uri[] uris, UserHandle userHandle)837         int doHandover(Uri[] uris, UserHandle userHandle) throws IOException {
838             NdefMessage response = null;
839             BeamManager beamManager = BeamManager.getInstance();
840 
841             if (beamManager.isBeamInProgress()) {
842                 return HANDOVER_BUSY;
843             }
844 
845             NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
846             if (request != null) {
847                 if (handoverClient != null) {
848                     response = handoverClient.sendHandoverRequest(request);
849                 }
850                 if (response == null && snepClient != null) {
851                     // Remote device may not support handover service,
852                     // try the (deprecated) SNEP GET implementation
853                     // for devices running Android 4.1
854                     SnepMessage snepResponse = snepClient.get(request);
855                     response = snepResponse.getNdefMessage();
856                 }
857                 if (response == null) {
858                     if (snepClient != null)
859                         return HANDOVER_UNSUPPORTED;
860                     else
861                         return HANDOVER_FAILURE;
862                 }
863             } else {
864                 return HANDOVER_UNSUPPORTED;
865             }
866 
867             if (!beamManager.startBeamSend(mContext,
868                     mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) {
869                 return HANDOVER_BUSY;
870             }
871 
872             return HANDOVER_SUCCESS;
873         }
874 
doSnepProtocol(NdefMessage msg)875         int doSnepProtocol(NdefMessage msg) throws IOException {
876             if (msg != null) {
877                 snepClient.put(msg);
878                 return SNEP_SUCCESS;
879             } else {
880                 return SNEP_FAILURE;
881             }
882         }
883 
884         @Override
doInBackground(Void... args)885         public Void doInBackground(Void... args) {
886             NdefMessage m;
887             Uri[] uris;
888             UserHandle userHandle;
889             boolean result = false;
890 
891             synchronized (P2pLinkManager.this) {
892                 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) {
893                     return null;
894                 }
895                 m = mMessageToSend;
896                 uris = mUrisToSend;
897                 userHandle = mUserHandle;
898                 snepClient = mSnepClient;
899                 handoverClient = mHandoverClient;
900                 nppClient = mNdefPushClient;
901             }
902 
903             long time = SystemClock.elapsedRealtime();
904 
905             if (uris != null) {
906                 if (DBG) Log.d(TAG, "Trying handover request");
907                 try {
908                     int handoverResult = doHandover(uris, userHandle);
909                     switch (handoverResult) {
910                         case HANDOVER_SUCCESS:
911                             result = true;
912                             break;
913                         case HANDOVER_FAILURE:
914                             result = false;
915                             break;
916                         case HANDOVER_UNSUPPORTED:
917                             result = false;
918                             onHandoverUnsupported();
919                             break;
920                         case HANDOVER_BUSY:
921                             result = false;
922                             onHandoverBusy();
923                             break;
924                     }
925                 } catch (IOException e) {
926                     result = false;
927                 }
928             }
929 
930             if (!result && m != null && snepClient != null) {
931                 if (DBG) Log.d(TAG, "Sending ndef via SNEP");
932                 try {
933                     int snepResult = doSnepProtocol(m);
934                     switch (snepResult) {
935                         case SNEP_SUCCESS:
936                             result = true;
937                             break;
938                         case SNEP_FAILURE:
939                             result = false;
940                             break;
941                         default:
942                             result = false;
943                     }
944                 } catch (IOException e) {
945                     result = false;
946                 }
947             }
948 
949             if (!result && m != null && nppClient != null) {
950                 result = nppClient.push(m);
951             }
952 
953             time = SystemClock.elapsedRealtime() - time;
954             if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time);
955             if (result) {
956                 onSendComplete(m, time);
957             }
958 
959             return null;
960         }
961     };
962 
963 
964     final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() {
965         @Override
966         public void onHandoverRequestReceived() {
967             onReceiveHandover();
968         }
969 
970         @Override
971         public void onHandoverBusy() {
972             P2pLinkManager.this.onHandoverBusy();
973         }
974     };
975 
976     final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() {
977         @Override
978         public void onMessageReceived(NdefMessage msg) {
979             onReceiveComplete(msg);
980         }
981     };
982 
983     final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() {
984         @Override
985         public SnepMessage doPut(NdefMessage msg) {
986             if(NfcService.sIsDtaMode)
987             Log.d(TAG, "DTA mode enabled, dont dispatch the tag");
988             else
989             onReceiveComplete(msg);
990             return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS);
991         }
992 
993         @Override
994         public SnepMessage doGet(int acceptableLength, NdefMessage msg) {
995             // The NFC Forum Default SNEP server is not allowed to respond to
996             // SNEP GET requests - see SNEP 1.0 TS section 6.1. However,
997             // since Android 4.1 used the NFC Forum default server to
998             // implement connection handover, we will support this
999             // until we can deprecate it.
1000             NdefMessage response = null;
1001             if (NfcService.sIsDtaMode){
1002                if(msg != null && mHandoverDataParser.getIncomingHandoverData(msg) !=  null) {
1003                    response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect;
1004                }
1005             } else {
1006                 response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect;
1007             }
1008             if (response != null) {
1009                 onReceiveHandover();
1010                 return SnepMessage.getSuccessResponse(response);
1011             } else {
1012                 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED);
1013             }
1014         }
1015     };
1016     final ExtDtaSnepServer.Callback mExtDtaSnepServerCallback = new ExtDtaSnepServer.Callback() {
1017         @Override
1018         public SnepMessage doPut(NdefMessage msg) {
1019             mPutBeforeGet = true;
1020             return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS);
1021         }
1022 
1023         @Override
1024         public SnepMessage doGet(int acceptableLength, NdefMessage msg) {
1025             if ((!mPutBeforeGet)) {
1026                 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND);
1027             } else if (acceptableLength == 501) {
1028                 mPutBeforeGet = false;
1029                 return SnepMessage.getMessage(SnepMessage.RESPONSE_EXCESS_DATA);
1030             } else if (mPutBeforeGet&&(acceptableLength == 1024)) {
1031                 try {
1032                     mPutBeforeGet = false;
1033                     return SnepMessage.getSuccessResponse(SnepMessage.getLargeNdef());
1034                 } catch (UnsupportedEncodingException e) {
1035                     mPutBeforeGet = false;
1036                     return null;
1037                 }
1038             } else {
1039                 mPutBeforeGet = false;
1040                 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED);
1041             }
1042         }
1043     };
1044 
onReceiveHandover()1045     void onReceiveHandover() {
1046         mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget();
1047     }
1048 
onReceiveComplete(NdefMessage msg)1049     void onReceiveComplete(NdefMessage msg) {
1050         // Make callbacks on UI thread
1051         mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget();
1052     }
1053 
1054     @Override
handleMessage(Message msg)1055     public boolean handleMessage(Message msg) {
1056         switch (msg.what) {
1057             case MSG_START_ECHOSERVER:
1058                 synchronized (this) {
1059                     mEchoServer.start();
1060                     break;
1061                 }
1062             case MSG_STOP_ECHOSERVER:
1063                 synchronized (this) {
1064                     mEchoServer.stop();
1065                     break;
1066                 }
1067             case MSG_WAIT_FOR_LINK_TIMEOUT:
1068                 synchronized (this) {
1069                     // User wanted to send something but no link
1070                     // came up. Just cancel the send
1071                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1072                     mEventListener.onP2pTimeoutWaitingForLink();
1073                 }
1074                 break;
1075             case MSG_DEBOUNCE_TIMEOUT:
1076                 synchronized (this) {
1077                     if (mLinkState != LINK_STATE_DEBOUNCE) {
1078                         break;
1079                     }
1080                     if (DBG) Log.d(TAG, "Debounce timeout");
1081                     mLinkState = LINK_STATE_DOWN;
1082                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1083                     mMessageToSend = null;
1084                     mUrisToSend = null;
1085                     if (DBG) Log.d(TAG, "onP2pOutOfRange()");
1086                     mEventListener.onP2pOutOfRange();
1087                 }
1088                 break;
1089             case MSG_RECEIVE_HANDOVER:
1090                 // We're going to do a handover request
1091                 synchronized (this) {
1092                     if (mLinkState == LINK_STATE_DOWN) {
1093                         break;
1094                     }
1095                     if (mSendState == SEND_STATE_SENDING) {
1096                         cancelSendNdefMessage();
1097                     }
1098                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1099                     if (DBG) Log.d(TAG, "onP2pReceiveComplete()");
1100                     mEventListener.onP2pReceiveComplete(false);
1101                 }
1102                 break;
1103             case MSG_RECEIVE_COMPLETE:
1104                 NdefMessage m = (NdefMessage) msg.obj;
1105                 synchronized (this) {
1106                     if (mLinkState == LINK_STATE_DOWN) {
1107                         break;
1108                     }
1109                     if (mSendState == SEND_STATE_SENDING) {
1110                         cancelSendNdefMessage();
1111                     }
1112                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1113                     if (DBG) Log.d(TAG, "onP2pReceiveComplete()");
1114                     mEventListener.onP2pReceiveComplete(true);
1115                     NfcService.getInstance().sendMockNdefTag(m);
1116                 }
1117                 break;
1118             case MSG_HANDOVER_NOT_SUPPORTED:
1119                 synchronized (P2pLinkManager.this) {
1120                     mSendTask = null;
1121 
1122                     if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
1123                         break;
1124                     }
1125                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1126                     if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()");
1127                     mEventListener.onP2pHandoverNotSupported();
1128                 }
1129                 break;
1130             case MSG_SEND_COMPLETE:
1131                 synchronized (P2pLinkManager.this) {
1132                     mSendTask = null;
1133 
1134                     if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
1135                         break;
1136                     }
1137                     mSendState = SEND_STATE_COMPLETE;
1138                     mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
1139                     if (DBG) Log.d(TAG, "onP2pSendComplete()");
1140                     mEventListener.onP2pSendComplete();
1141                     if (mCallbackNdef != null) {
1142                         try {
1143                             mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion);
1144                         } catch (Exception e) {
1145                             Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage());
1146                         }
1147                     }
1148                 }
1149                 break;
1150             case MSG_HANDOVER_BUSY:
1151                 synchronized (P2pLinkManager.this) {
1152                     mSendTask = null;
1153 
1154                     if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
1155                         break;
1156                     }
1157                     mSendState = SEND_STATE_NOTHING_TO_SEND;
1158                     if (DBG) Log.d(TAG, "onP2pHandoverBusy()");
1159                     mEventListener.onP2pHandoverBusy();
1160                 }
1161         }
1162         return true;
1163     }
1164 
1165 
1166     @Override
onP2pSendConfirmed()1167     public void onP2pSendConfirmed() {
1168         onP2pSendConfirmed(true);
1169     }
1170 
onP2pSendConfirmed(boolean requireConfirmation)1171     private void onP2pSendConfirmed(boolean requireConfirmation) {
1172         if (DBG) Log.d(TAG, "onP2pSendConfirmed()");
1173         synchronized (this) {
1174             if (mLinkState == LINK_STATE_DOWN || (requireConfirmation
1175                     && mSendState != SEND_STATE_NEED_CONFIRMATION)) {
1176                 return;
1177             }
1178             mSendState = SEND_STATE_SENDING;
1179             if (mLinkState == LINK_STATE_UP) {
1180                 if (mLlcpServicesConnected) {
1181                     sendNdefMessage();
1182                 } // else, will send messages when link comes up
1183             } else if (mLinkState == LINK_STATE_DEBOUNCE) {
1184                 // Restart debounce timeout and tell user to tap again
1185                 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CONFIRMED_DEBOUNCE_MS);
1186                 mEventListener.onP2pSendDebounce();
1187             }
1188         }
1189     }
1190 
1191 
1192     @Override
onP2pCanceled()1193     public void onP2pCanceled() {
1194         synchronized (this) {
1195             mSendState = SEND_STATE_CANCELED;
1196             if (mLinkState == LINK_STATE_DOWN) {
1197                 // If we were waiting for the link to come up, stop doing so
1198                 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT);
1199             } else if (mLinkState == LINK_STATE_DEBOUNCE) {
1200                 // We're in debounce state so link is down. Reschedule debounce
1201                 // timeout to occur sooner, we don't want to wait any longer.
1202                 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CANCELED_DEBOUNCE_MS);
1203             } else {
1204                 // Link is up, nothing else to do but wait for link to go down
1205             }
1206         }
1207     }
1208 
scheduleTimeoutLocked(int what, int timeout)1209     void scheduleTimeoutLocked(int what, int timeout) {
1210         // Cancel any outstanding debounce timeouts.
1211         mHandler.removeMessages(what);
1212         mHandler.sendEmptyMessageDelayed(what, timeout);
1213     }
1214 
sendStateToString(int state)1215     static String sendStateToString(int state) {
1216         switch (state) {
1217             case SEND_STATE_NOTHING_TO_SEND:
1218                 return "SEND_STATE_NOTHING_TO_SEND";
1219             case SEND_STATE_NEED_CONFIRMATION:
1220                 return "SEND_STATE_NEED_CONFIRMATION";
1221             case SEND_STATE_SENDING:
1222                 return "SEND_STATE_SENDING";
1223             case SEND_STATE_COMPLETE:
1224                 return "SEND_STATE_COMPLETE";
1225             case SEND_STATE_CANCELED:
1226                 return "SEND_STATE_CANCELED";
1227             default:
1228                 return "<error>";
1229         }
1230     }
1231 
linkStateToString(int state)1232     static String linkStateToString(int state) {
1233         switch (state) {
1234             case LINK_STATE_DOWN:
1235                 return "LINK_STATE_DOWN";
1236             case LINK_STATE_DEBOUNCE:
1237                 return "LINK_STATE_DEBOUNCE";
1238             case LINK_STATE_UP:
1239                 return "LINK_STATE_UP";
1240             default:
1241                 return "<error>";
1242         }
1243     }
1244 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1245     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1246         synchronized (this) {
1247             pw.println("mIsSendEnabled=" + mIsSendEnabled);
1248             pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled);
1249             pw.println("mLinkState=" + linkStateToString(mLinkState));
1250             pw.println("mSendState=" + sendStateToString(mSendState));
1251 
1252             pw.println("mCallbackNdef=" + mCallbackNdef);
1253             pw.println("mMessageToSend=" + mMessageToSend);
1254             pw.println("mUrisToSend=" + mUrisToSend);
1255         }
1256     }
1257 }
1258