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