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 17package com.android.nfc; 18 19import android.content.Intent; 20import android.content.pm.UserInfo; 21 22import com.android.nfc.beam.BeamManager; 23import com.android.nfc.beam.BeamSendService; 24import com.android.nfc.beam.BeamTransferRecord; 25 26import android.os.UserManager; 27import com.android.nfc.sneptest.ExtDtaSnepServer; 28import com.android.nfc.sneptest.DtaSnepClient; 29import com.android.nfc.echoserver.EchoServer; 30import com.android.nfc.handover.HandoverClient; 31import com.android.nfc.handover.HandoverDataParser; 32import com.android.nfc.handover.HandoverServer; 33import com.android.nfc.ndefpush.NdefPushClient; 34import com.android.nfc.ndefpush.NdefPushServer; 35import com.android.nfc.snep.SnepClient; 36import com.android.nfc.snep.SnepMessage; 37import com.android.nfc.snep.SnepServer; 38 39import android.content.Context; 40import android.content.SharedPreferences; 41import android.content.pm.ApplicationInfo; 42import android.content.pm.PackageManager; 43import android.content.pm.PackageManager.NameNotFoundException; 44import android.net.Uri; 45import android.nfc.BeamShareData; 46import android.nfc.IAppCallback; 47import android.nfc.NdefMessage; 48import android.nfc.NdefRecord; 49import android.nfc.NfcAdapter; 50import android.os.AsyncTask; 51import android.os.Handler; 52import android.os.Message; 53import android.os.SystemClock; 54import android.os.UserHandle; 55import android.util.Log; 56import java.io.FileDescriptor; 57import java.io.IOException; 58import java.io.PrintWriter; 59import java.nio.charset.StandardCharsets; 60import java.util.Arrays; 61import java.util.List; 62import java.io.UnsupportedEncodingException; 63 64/** 65 * Interface to listen for P2P events. 66 * All callbacks are made from the UI thread. 67 */ 68interface 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 */ 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 */ 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 */ 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 */ 94 public void onP2pSendConfirmationRequested(); 95 96 /** 97 * Called to indicate a send was successful. 98 */ 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 */ 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 */ 113 public void onP2pResumeSend(); 114 115 /** 116 * Called to indicate the remote device does not support connection handover 117 */ 118 public void onP2pHandoverNotSupported(); 119 120 /** 121 * Called to indicate the device is busy with another handover transfer 122 */ 123 public void onP2pHandoverBusy(); 124 125 /** 126 * Called to indicate a receive was successful. 127 */ 128 public void onP2pReceiveComplete(boolean playSound); 129 130 /** 131 * Indicates the P2P device went out of range. 132 */ 133 public void onP2pOutOfRange(); 134 135 public interface Callback { 136 public void onP2pSendConfirmed(); 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 */ 146class 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 393 public void setNdefCallback(IAppCallback callbackNdef, int callingUid) { 394 synchronized (this) { 395 mCallbackNdef = callbackNdef; 396 mNdefCallbackUid = callingUid; 397 } 398 } 399 400 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 */ 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 */ 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 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 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 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 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 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 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 */ 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 667 void onHandoverUnsupported() { 668 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 669 } 670 671 void onHandoverBusy() { 672 mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY); 673 } 674 675 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 676 // Make callbacks on UI thread 677 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 678 } 679 680 void sendNdefMessage() { 681 synchronized (this) { 682 cancelSendNdefMessage(); 683 mSendTask = new SendTask(); 684 mSendTask.execute(); 685 } 686 } 687 688 void cancelSendNdefMessage() { 689 synchronized (P2pLinkManager.this) { 690 if (mSendTask != null) { 691 mSendTask.cancel(true); 692 } 693 } 694 } 695 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 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 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 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 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 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 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 1045 void onReceiveHandover() { 1046 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 1047 } 1048 1049 void onReceiveComplete(NdefMessage msg) { 1050 // Make callbacks on UI thread 1051 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 1052 } 1053 1054 @Override 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 1167 public void onP2pSendConfirmed() { 1168 onP2pSendConfirmed(true); 1169 } 1170 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 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 1209 void scheduleTimeoutLocked(int what, int timeout) { 1210 // Cancel any outstanding debounce timeouts. 1211 mHandler.removeMessages(what); 1212 mHandler.sendEmptyMessageDelayed(what, timeout); 1213 } 1214 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 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 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