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 com.android.nfc.echoserver.EchoServer; 20 import com.android.nfc.handover.HandoverClient; 21 import com.android.nfc.handover.HandoverManager; 22 import com.android.nfc.handover.HandoverServer; 23 import com.android.nfc.ndefpush.NdefPushClient; 24 import com.android.nfc.ndefpush.NdefPushServer; 25 import com.android.nfc.snep.SnepClient; 26 import com.android.nfc.snep.SnepMessage; 27 import com.android.nfc.snep.SnepServer; 28 29 import android.app.ActivityManager; 30 import android.app.ActivityManager.RunningTaskInfo; 31 import android.content.Context; 32 import android.content.SharedPreferences; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.NameNotFoundException; 36 import android.net.Uri; 37 import android.nfc.BeamShareData; 38 import android.nfc.INdefPushCallback; 39 import android.nfc.NdefMessage; 40 import android.nfc.NdefRecord; 41 import android.nfc.NfcAdapter; 42 import android.os.AsyncTask; 43 import android.os.Handler; 44 import android.os.Message; 45 import android.os.SystemClock; 46 import android.os.UserHandle; 47 import android.util.Log; 48 49 import java.io.FileDescriptor; 50 import java.io.IOException; 51 import java.io.PrintWriter; 52 import java.nio.charset.Charsets; 53 import java.util.Arrays; 54 import java.util.List; 55 56 /** 57 * Interface to listen for P2P events. 58 * All callbacks are made from the UI thread. 59 */ 60 interface P2pEventListener { 61 /** 62 * Indicates a P2P device is in range. 63 * <p>onP2pInRange() and onP2pOutOfRange() will always be called 64 * alternately. 65 * <p>All other callbacks will only occur while a P2P device is in range. 66 */ 67 public void onP2pInRange(); 68 69 /** 70 * Called when a NDEF payload is prepared to send, and confirmation is 71 * required. Call Callback.onP2pSendConfirmed() to make the confirmation. 72 */ 73 public void onP2pSendConfirmationRequested(); 74 75 /** 76 * Called to indicate a send was successful. 77 */ 78 public void onP2pSendComplete(); 79 80 /** 81 * 82 * Called to indicate the link has broken while we were trying to send 83 * a message. We'll start a debounce timer for the user to get the devices 84 * back together. UI may show a hint to achieve that 85 */ 86 public void onP2pSendDebounce(); 87 88 /** 89 * Called to indicate a link has come back up after being temporarily 90 * broken, and sending is resuming 91 */ 92 public void onP2pResumeSend(); 93 94 /** 95 * Called to indicate the remote device does not support connection handover 96 */ 97 public void onP2pHandoverNotSupported(); 98 99 /** 100 * Called to indicate a receive was successful. 101 */ 102 public void onP2pReceiveComplete(boolean playSound); 103 104 /** 105 * Indicates the P2P device went out of range. 106 */ 107 public void onP2pOutOfRange(); 108 109 public interface Callback { 110 public void onP2pSendConfirmed(); 111 } 112 } 113 114 /** 115 * Manages sending and receiving NDEF message over LLCP link. 116 * Does simple debouncing of the LLCP link - so that even if the link 117 * drops and returns the user does not know. 118 */ 119 public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback { 120 static final String TAG = "NfcP2pLinkManager"; 121 static final boolean DBG = true; 122 123 /** Include this constant as a meta-data entry in the manifest 124 * of an application to disable beaming the market/AAR link, like this: 125 * <pre>{@code 126 * <application ...> 127 * <meta-data android:name="android.nfc.disable_beam_default" 128 * android:value="true" /> 129 * </application> 130 * }</pre> 131 */ 132 static final String DISABLE_BEAM_DEFAULT = "android.nfc.disable_beam_default"; 133 134 /** Enables the LLCP EchoServer, which can be used to test the android 135 * LLCP stack against nfcpy. 136 */ 137 static final boolean ECHOSERVER_ENABLED = false; 138 139 // TODO dynamically assign SAP values 140 static final int NDEFPUSH_SAP = 0x10; 141 static final int HANDOVER_SAP = 0x14; 142 143 static final int LINK_FIRST_PDU_LIMIT_MS = 200; 144 static final int LINK_NOTHING_TO_SEND_DEBOUNCE_MS = 750; 145 static final int LINK_SEND_PENDING_DEBOUNCE_MS = 3000; 146 static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000; 147 static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 250; 148 static final int MSG_DEBOUNCE_TIMEOUT = 1; 149 static final int MSG_RECEIVE_COMPLETE = 2; 150 static final int MSG_RECEIVE_HANDOVER = 3; 151 static final int MSG_SEND_COMPLETE = 4; 152 static final int MSG_START_ECHOSERVER = 5; 153 static final int MSG_STOP_ECHOSERVER = 6; 154 static final int MSG_HANDOVER_NOT_SUPPORTED = 7; 155 static final int MSG_SHOW_CONFIRMATION_UI = 8; 156 157 // values for mLinkState 158 static final int LINK_STATE_DOWN = 1; 159 static final int LINK_STATE_WAITING_PDU = 2; 160 static final int LINK_STATE_UP = 3; 161 static final int LINK_STATE_DEBOUNCE = 4; 162 163 // values for mSendState 164 static final int SEND_STATE_NOTHING_TO_SEND = 1; 165 static final int SEND_STATE_NEED_CONFIRMATION = 2; 166 static final int SEND_STATE_SENDING = 3; 167 static final int SEND_STATE_SEND_COMPLETE = 4; 168 169 // return values for doSnepProtocol 170 static final int SNEP_SUCCESS = 0; 171 static final int SNEP_FAILURE = 1; 172 173 // return values for doHandover 174 static final int HANDOVER_SUCCESS = 0; 175 static final int HANDOVER_FAILURE = 1; 176 static final int HANDOVER_UNSUPPORTED = 2; 177 178 final NdefPushServer mNdefPushServer; 179 final SnepServer mDefaultSnepServer; 180 final HandoverServer mHandoverServer; 181 final EchoServer mEchoServer; 182 final ActivityManager mActivityManager; 183 final Context mContext; 184 final P2pEventListener mEventListener; 185 final Handler mHandler; 186 final HandoverManager mHandoverManager; 187 188 final int mDefaultMiu; 189 final int mDefaultRwSize; 190 191 // Locked on NdefP2pManager.this 192 PackageManager mPackageManager; 193 int mLinkState; 194 int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE 195 boolean mIsSendEnabled; 196 boolean mIsReceiveEnabled; 197 NdefMessage mMessageToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 198 Uri[] mUrisToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 199 int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND 200 INdefPushCallback mCallbackNdef; 201 String[] mValidCallbackPackages; 202 SendTask mSendTask; 203 SharedPreferences mPrefs; 204 boolean mFirstBeam; 205 SnepClient mSnepClient; 206 HandoverClient mHandoverClient; 207 NdefPushClient mNdefPushClient; 208 ConnectTask mConnectTask; 209 boolean mLlcpServicesConnected; 210 boolean mLlcpConnectDelayed; 211 long mLastLlcpActivationTime; 212 213 public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu, 214 int defaultRwSize) { 215 mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); 216 mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize); 217 mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback); 218 219 if (ECHOSERVER_ENABLED) { 220 mEchoServer = new EchoServer(); 221 } else { 222 mEchoServer = null; 223 } 224 mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 225 mPackageManager = context.getPackageManager(); 226 mContext = context; 227 mEventListener = new P2pEventManager(context, this); 228 mHandler = new Handler(this); 229 mLinkState = LINK_STATE_DOWN; 230 mSendState = SEND_STATE_NOTHING_TO_SEND; 231 mIsSendEnabled = false; 232 mIsReceiveEnabled = false; 233 mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE); 234 mFirstBeam = mPrefs.getBoolean(NfcService.PREF_FIRST_BEAM, true); 235 mHandoverManager = handoverManager; 236 mDefaultMiu = defaultMiu; 237 mDefaultRwSize = defaultRwSize; 238 mLlcpServicesConnected = false; 239 } 240 241 /** 242 * May be called from any thread. 243 * Assumes that NFC is already on if any parameter is true. 244 */ 245 public void enableDisable(boolean sendEnable, boolean receiveEnable) { 246 synchronized (this) { 247 if (!mIsReceiveEnabled && receiveEnable) { 248 mDefaultSnepServer.start(); 249 mNdefPushServer.start(); 250 mHandoverServer.start(); 251 if (mEchoServer != null) { 252 mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); 253 } 254 } else if (mIsReceiveEnabled && !receiveEnable) { 255 mDefaultSnepServer.stop(); 256 mNdefPushServer.stop(); 257 mHandoverServer.stop(); 258 if (mEchoServer != null) { 259 mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); 260 } 261 } 262 mIsSendEnabled = sendEnable; 263 mIsReceiveEnabled = receiveEnable; 264 } 265 } 266 267 /** 268 * May be called from any thread. 269 * @return whether the LLCP link is in an active or debounce state 270 */ 271 public boolean isLlcpActive() { 272 synchronized (this) { 273 return mLinkState != LINK_STATE_DOWN; 274 } 275 } 276 277 /** 278 * Set NDEF callback for sending. 279 * May be called from any thread. 280 * NDEF callbacks may be set at any time (even if NFC is 281 * currently off or P2P send is currently off). They will become 282 * active as soon as P2P send is enabled. 283 */ 284 public void setNdefCallback(INdefPushCallback callbackNdef, int callingUid) { 285 synchronized (this) { 286 mCallbackNdef = callbackNdef; 287 mValidCallbackPackages = mPackageManager.getPackagesForUid(callingUid); 288 } 289 } 290 291 /** 292 * Must be called on UI Thread. 293 */ 294 public void onLlcpActivated() { 295 Log.i(TAG, "LLCP activated"); 296 297 synchronized (P2pLinkManager.this) { 298 if (mEchoServer != null) { 299 mEchoServer.onLlcpActivated(); 300 } 301 mLastLlcpActivationTime = SystemClock.elapsedRealtime(); 302 mLlcpConnectDelayed = false; 303 switch (mLinkState) { 304 case LINK_STATE_DOWN: 305 mLinkState = LINK_STATE_WAITING_PDU; 306 mSendState = SEND_STATE_NOTHING_TO_SEND; 307 if (DBG) Log.d(TAG, "onP2pInRange()"); 308 mEventListener.onP2pInRange(); 309 prepareMessageToSend(); 310 if (mMessageToSend != null || 311 (mUrisToSend != null && mHandoverManager.isHandoverSupported())) { 312 // Ideally we would delay showing the Beam animation until 313 // we know for certain the other side has SNEP/handover. 314 // Unfortunately, the NXP LLCP implementation has a bug that 315 // delays the first SYMM for 750ms if it is the initiator. 316 // This will cause our SNEP connect to be delayed as well, 317 // and the animation will be delayed for about a second. 318 // Alternatively, we could have used WKS as a hint to start 319 // the animation, but we are only correctly setting the WKS 320 // since Jelly Bean. 321 if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) { 322 mSendState = SEND_STATE_SENDING; 323 onP2pSendConfirmed(false); 324 } else { 325 mSendState = SEND_STATE_NEED_CONFIRMATION; 326 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()"); 327 mEventListener.onP2pSendConfirmationRequested(); 328 } 329 } 330 break; 331 case LINK_STATE_WAITING_PDU: 332 if (DBG) Log.d(TAG, "Unexpected onLlcpActivated() in LINK_STATE_WAITING_PDU"); 333 return; 334 case LINK_STATE_UP: 335 if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()"); 336 return; 337 case LINK_STATE_DEBOUNCE: 338 if (mSendState == SEND_STATE_SENDING) { 339 // Immediately connect and try to send again 340 mLinkState = LINK_STATE_UP; 341 connectLlcpServices(); 342 } else { 343 mLinkState = LINK_STATE_WAITING_PDU; 344 } 345 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 346 break; 347 } 348 } 349 } 350 351 /** 352 * Must be called on UI Thread. 353 */ 354 public void onLlcpFirstPacketReceived() { 355 synchronized (P2pLinkManager.this) { 356 long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime; 357 if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU"); 358 switch (mLinkState) { 359 case LINK_STATE_UP: 360 if (DBG) Log.d(TAG, "Dropping first LLCP packet received"); 361 break; 362 case LINK_STATE_DOWN: 363 case LINK_STATE_DEBOUNCE: 364 Log.e(TAG, "Unexpected first LLCP packet received"); 365 break; 366 case LINK_STATE_WAITING_PDU: 367 mLinkState = LINK_STATE_UP; 368 if (mSendState == SEND_STATE_NOTHING_TO_SEND) 369 break; 370 if (totalTime < LINK_FIRST_PDU_LIMIT_MS || mSendState == SEND_STATE_SENDING) { 371 connectLlcpServices(); 372 } else { 373 mLlcpConnectDelayed = true; 374 } 375 break; 376 } 377 } 378 } 379 380 public void onUserSwitched() { 381 // Update the cached package manager in case of user switch 382 synchronized (P2pLinkManager.this) { 383 try { 384 mPackageManager = mContext.createPackageContextAsUser("android", 0, 385 new UserHandle(ActivityManager.getCurrentUser())).getPackageManager(); 386 } catch (NameNotFoundException e) { 387 Log.e(TAG, "Failed to retrieve PackageManager for user"); 388 } 389 } 390 } 391 392 void prepareMessageToSend() { 393 synchronized (P2pLinkManager.this) { 394 if (!mIsSendEnabled) { 395 mMessageToSend = null; 396 mUrisToSend = null; 397 return; 398 } 399 400 String runningPackage = null; 401 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1); 402 if (tasks.size() > 0) { 403 runningPackage = tasks.get(0).topActivity.getPackageName(); 404 } 405 406 if (runningPackage == null) { 407 Log.e(TAG, "Could not determine running package."); 408 mMessageToSend = null; 409 mUrisToSend = null; 410 return; 411 } 412 413 // Try application callback first 414 if (mCallbackNdef != null) { 415 // Check to see if the package currently running 416 // is the one that registered any callbacks 417 boolean callbackValid = false; 418 419 if (mValidCallbackPackages != null) { 420 for (String pkg : mValidCallbackPackages) { 421 if (pkg.equals(runningPackage)) { 422 callbackValid = true; 423 break; 424 } 425 } 426 } 427 428 if (callbackValid) { 429 try { 430 BeamShareData shareData = mCallbackNdef.createBeamShareData(); 431 mMessageToSend = shareData.ndefMessage; 432 mUrisToSend = shareData.uris; 433 mSendFlags = shareData.flags; 434 return; 435 } catch (Exception e) { 436 Log.e(TAG, "Failed NDEF callback: " + e.getMessage()); 437 } 438 } else { 439 // This is not necessarily an error - we no longer unset callbacks from 440 // the app process itself (to prevent IPC calls on every pause). 441 // Hence it may simply be a stale callback. 442 if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground."); 443 } 444 } 445 446 // fall back to default NDEF for the foreground activity, unless the 447 // application disabled this explicitly in their manifest. 448 if (beamDefaultDisabled(runningPackage)) { 449 Log.d(TAG, "Disabling default Beam behavior"); 450 mMessageToSend = null; 451 mUrisToSend = null; 452 } else { 453 mMessageToSend = createDefaultNdef(runningPackage); 454 mUrisToSend = null; 455 } 456 457 if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend); 458 if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend); 459 } 460 } 461 462 boolean beamDefaultDisabled(String pkgName) { 463 try { 464 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName, 465 PackageManager.GET_META_DATA); 466 if (ai == null || ai.metaData == null) { 467 return false; 468 } 469 return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT); 470 } catch (NameNotFoundException e) { 471 return false; 472 } 473 } 474 475 NdefMessage createDefaultNdef(String pkgName) { 476 NdefRecord appUri = NdefRecord.createUri(Uri.parse( 477 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam")); 478 NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName); 479 return new NdefMessage(new NdefRecord[] { appUri, appRecord }); 480 } 481 482 void disconnectLlcpServices() { 483 synchronized (this) { 484 if (mConnectTask != null) { 485 mConnectTask.cancel(true); 486 mConnectTask = null; 487 } 488 // Close any already connected LLCP clients 489 if (mNdefPushClient != null) { 490 mNdefPushClient.close(); 491 mNdefPushClient = null; 492 } 493 if (mSnepClient != null) { 494 mSnepClient.close(); 495 mSnepClient = null; 496 } 497 if (mHandoverClient != null) { 498 mHandoverClient.close(); 499 mHandoverClient = null; 500 } 501 mLlcpServicesConnected = false; 502 } 503 } 504 505 /** 506 * Must be called on UI Thread. 507 */ 508 public void onLlcpDeactivated() { 509 Log.i(TAG, "LLCP deactivated."); 510 synchronized (this) { 511 if (mEchoServer != null) { 512 mEchoServer.onLlcpDeactivated(); 513 } 514 515 switch (mLinkState) { 516 case LINK_STATE_DOWN: 517 case LINK_STATE_DEBOUNCE: 518 Log.i(TAG, "Duplicate onLlcpDectivated()"); 519 break; 520 case LINK_STATE_WAITING_PDU: 521 case LINK_STATE_UP: 522 // Debounce 523 mLinkState = LINK_STATE_DEBOUNCE; 524 int debounceTimeout = 0; 525 switch (mSendState) { 526 case SEND_STATE_NOTHING_TO_SEND: 527 debounceTimeout = 0; 528 break; 529 case SEND_STATE_NEED_CONFIRMATION: 530 debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS; 531 break; 532 case SEND_STATE_SENDING: 533 debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS; 534 break; 535 case SEND_STATE_SEND_COMPLETE: 536 debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS; 537 break; 538 } 539 mHandler.sendEmptyMessageDelayed(MSG_DEBOUNCE_TIMEOUT, debounceTimeout); 540 if (mSendState == SEND_STATE_SENDING) { 541 Log.e(TAG, "onP2pSendDebounce()"); 542 mEventListener.onP2pSendDebounce(); 543 } 544 cancelSendNdefMessage(); 545 disconnectLlcpServices(); 546 break; 547 } 548 } 549 } 550 551 void onHandoverUnsupported() { 552 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 553 } 554 555 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 556 if (mFirstBeam) { 557 EventLogTags.writeNfcFirstShare(); 558 mPrefs.edit().putBoolean(NfcService.PREF_FIRST_BEAM, false).apply(); 559 mFirstBeam = false; 560 } 561 EventLogTags.writeNfcShare(getMessageSize(msg), getMessageTnf(msg), getMessageType(msg), 562 getMessageAarPresent(msg), (int) elapsedRealtime); 563 // Make callbacks on UI thread 564 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 565 } 566 567 void sendNdefMessage() { 568 synchronized (this) { 569 cancelSendNdefMessage(); 570 mSendTask = new SendTask(); 571 mSendTask.execute(); 572 } 573 } 574 575 void cancelSendNdefMessage() { 576 synchronized (P2pLinkManager.this) { 577 if (mSendTask != null) { 578 mSendTask.cancel(true); 579 } 580 } 581 } 582 583 void connectLlcpServices() { 584 synchronized (P2pLinkManager.this) { 585 if (mConnectTask != null) { 586 Log.e(TAG, "Still had a reference to mConnectTask!"); 587 } 588 mConnectTask = new ConnectTask(); 589 mConnectTask.execute(); 590 } 591 } 592 593 // Must be called on UI-thread 594 void onLlcpServicesConnected() { 595 if (DBG) Log.d(TAG, "onLlcpServicesConnected"); 596 synchronized (P2pLinkManager.this) { 597 if (mLinkState != LINK_STATE_UP) { 598 return; 599 } 600 mLlcpServicesConnected = true; 601 if (mSendState == SEND_STATE_SENDING) { 602 // FIXME Keep state to make sure this is only called when in debounce 603 // and remove logic in P2pEventManager to keep track. 604 mEventListener.onP2pResumeSend(); 605 sendNdefMessage(); 606 } else { 607 // User still needs to confirm, or we may have received something already. 608 } 609 } 610 } 611 612 final class ConnectTask extends AsyncTask<Void, Void, Boolean> { 613 @Override 614 protected void onPostExecute(Boolean result) { 615 if (isCancelled()) { 616 if (DBG) Log.d(TAG, "ConnectTask was cancelled"); 617 return; 618 } 619 if (result) { 620 onLlcpServicesConnected(); 621 } else { 622 Log.e(TAG, "Could not connect required NFC transports"); 623 } 624 } 625 626 @Override 627 protected Boolean doInBackground(Void... params) { 628 boolean needsHandover = false; 629 boolean needsNdef = false; 630 boolean success = false; 631 HandoverClient handoverClient = null; 632 SnepClient snepClient = null; 633 NdefPushClient nppClient = null; 634 635 synchronized(P2pLinkManager.this) { 636 if (mUrisToSend != null) { 637 needsHandover = true; 638 } 639 640 if (mMessageToSend != null) { 641 needsNdef = true; 642 } 643 } 644 // We know either is requested - otherwise this task 645 // wouldn't have been started. 646 if (needsHandover) { 647 handoverClient = new HandoverClient(); 648 try { 649 handoverClient.connect(); 650 success = true; // Regardless of NDEF result 651 } catch (IOException e) { 652 handoverClient = null; 653 } 654 } 655 656 if (needsNdef || (needsHandover && handoverClient == null)) { 657 snepClient = new SnepClient(); 658 try { 659 snepClient.connect(); 660 success = true; 661 } catch (IOException e) { 662 snepClient = null; 663 } 664 665 if (!success) { 666 nppClient = new NdefPushClient(); 667 try { 668 nppClient.connect(); 669 success = true; 670 } catch (IOException e) { 671 nppClient = null; 672 } 673 } 674 } 675 676 synchronized (P2pLinkManager.this) { 677 if (isCancelled()) { 678 // Cancelled by onLlcpDeactivated on UI thread 679 if (handoverClient != null) { 680 handoverClient.close(); 681 } 682 if (snepClient != null) { 683 snepClient.close(); 684 } 685 if (nppClient != null) { 686 nppClient.close(); 687 } 688 return false; 689 } else { 690 // Once assigned, these are the responsibility of 691 // the code on the UI thread to release - typically 692 // through onLlcpDeactivated(). 693 mHandoverClient = handoverClient; 694 mSnepClient = snepClient; 695 mNdefPushClient = nppClient; 696 return success; 697 } 698 } 699 } 700 }; 701 702 final class SendTask extends AsyncTask<Void, Void, Void> { 703 NdefPushClient nppClient; 704 SnepClient snepClient; 705 HandoverClient handoverClient; 706 707 int doHandover(Uri[] uris) throws IOException { 708 NdefMessage response = null; 709 NdefMessage request = mHandoverManager.createHandoverRequestMessage(); 710 if (request != null) { 711 if (handoverClient != null) { 712 response = handoverClient.sendHandoverRequest(request); 713 } 714 if (response == null && snepClient != null) { 715 // Remote device may not support handover service, 716 // try the (deprecated) SNEP GET implementation 717 // for devices running Android 4.1 718 SnepMessage snepResponse = snepClient.get(request); 719 response = snepResponse.getNdefMessage(); 720 } 721 if (response == null) { 722 return HANDOVER_UNSUPPORTED; 723 } 724 } else { 725 return HANDOVER_UNSUPPORTED; 726 } 727 mHandoverManager.doHandoverUri(uris, response); 728 return HANDOVER_SUCCESS; 729 } 730 731 int doSnepProtocol(NdefMessage msg) throws IOException { 732 if (msg != null) { 733 snepClient.put(msg); 734 return SNEP_SUCCESS; 735 } else { 736 return SNEP_FAILURE; 737 } 738 } 739 740 @Override 741 public Void doInBackground(Void... args) { 742 NdefMessage m; 743 Uri[] uris; 744 boolean result = false; 745 746 synchronized (P2pLinkManager.this) { 747 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) { 748 return null; 749 } 750 m = mMessageToSend; 751 uris = mUrisToSend; 752 snepClient = mSnepClient; 753 handoverClient = mHandoverClient; 754 nppClient = mNdefPushClient; 755 } 756 757 long time = SystemClock.elapsedRealtime(); 758 759 if (uris != null) { 760 if (DBG) Log.d(TAG, "Trying handover request"); 761 try { 762 int handoverResult = doHandover(uris); 763 switch (handoverResult) { 764 case HANDOVER_SUCCESS: 765 result = true; 766 break; 767 case HANDOVER_FAILURE: 768 result = false; 769 break; 770 case HANDOVER_UNSUPPORTED: 771 result = false; 772 onHandoverUnsupported(); 773 break; 774 } 775 } catch (IOException e) { 776 result = false; 777 } 778 } 779 780 if (!result && m != null && snepClient != null) { 781 if (DBG) Log.d(TAG, "Sending ndef via SNEP"); 782 try { 783 int snepResult = doSnepProtocol(m); 784 switch (snepResult) { 785 case SNEP_SUCCESS: 786 result = true; 787 break; 788 case SNEP_FAILURE: 789 result = false; 790 break; 791 default: 792 result = false; 793 } 794 } catch (IOException e) { 795 result = false; 796 } 797 } 798 799 if (!result && m != null && nppClient != null) { 800 result = nppClient.push(m); 801 } 802 803 time = SystemClock.elapsedRealtime() - time; 804 if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time); 805 if (result) { 806 onSendComplete(m, time); 807 } 808 809 return null; 810 } 811 }; 812 813 814 final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { 815 @Override 816 public void onHandoverRequestReceived() { 817 onReceiveHandover(); 818 } 819 }; 820 821 final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { 822 @Override 823 public void onMessageReceived(NdefMessage msg) { 824 onReceiveComplete(msg); 825 } 826 }; 827 828 final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() { 829 @Override 830 public SnepMessage doPut(NdefMessage msg) { 831 onReceiveComplete(msg); 832 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 833 } 834 835 @Override 836 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 837 // The NFC Forum Default SNEP server is not allowed to respond to 838 // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, 839 // since Android 4.1 used the NFC Forum default server to 840 // implement connection handover, we will support this 841 // until we can deprecate it. 842 NdefMessage response = mHandoverManager.tryHandoverRequest(msg); 843 if (response != null) { 844 onReceiveHandover(); 845 return SnepMessage.getSuccessResponse(response); 846 } else { 847 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 848 } 849 } 850 }; 851 852 void onReceiveHandover() { 853 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 854 } 855 856 void onReceiveComplete(NdefMessage msg) { 857 EventLogTags.writeNfcNdefReceived(getMessageSize(msg), getMessageTnf(msg), 858 getMessageType(msg), getMessageAarPresent(msg)); 859 // Make callbacks on UI thread 860 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 861 } 862 863 @Override 864 public boolean handleMessage(Message msg) { 865 switch (msg.what) { 866 case MSG_START_ECHOSERVER: 867 synchronized (this) { 868 mEchoServer.start(); 869 break; 870 } 871 case MSG_STOP_ECHOSERVER: 872 synchronized (this) { 873 mEchoServer.stop(); 874 break; 875 } 876 case MSG_DEBOUNCE_TIMEOUT: 877 synchronized (this) { 878 if (mLinkState != LINK_STATE_DEBOUNCE) { 879 break; 880 } 881 if (mSendState == SEND_STATE_SENDING) { 882 EventLogTags.writeNfcShareFail(getMessageSize(mMessageToSend), 883 getMessageTnf(mMessageToSend), getMessageType(mMessageToSend), 884 getMessageAarPresent(mMessageToSend)); 885 } 886 if (DBG) Log.d(TAG, "Debounce timeout"); 887 mLinkState = LINK_STATE_DOWN; 888 mSendState = SEND_STATE_NOTHING_TO_SEND; 889 mMessageToSend = null; 890 mUrisToSend = null; 891 if (DBG) Log.d(TAG, "onP2pOutOfRange()"); 892 mEventListener.onP2pOutOfRange(); 893 } 894 break; 895 case MSG_RECEIVE_HANDOVER: 896 // We're going to do a handover request 897 synchronized (this) { 898 if (mLinkState == LINK_STATE_DOWN) { 899 break; 900 } 901 if (mSendState == SEND_STATE_SENDING) { 902 cancelSendNdefMessage(); 903 } 904 mSendState = SEND_STATE_NOTHING_TO_SEND; 905 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 906 mEventListener.onP2pReceiveComplete(false); 907 } 908 break; 909 case MSG_RECEIVE_COMPLETE: 910 NdefMessage m = (NdefMessage) msg.obj; 911 synchronized (this) { 912 if (mLinkState == LINK_STATE_DOWN) { 913 break; 914 } 915 if (mSendState == SEND_STATE_SENDING) { 916 cancelSendNdefMessage(); 917 } 918 mSendState = SEND_STATE_NOTHING_TO_SEND; 919 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 920 mEventListener.onP2pReceiveComplete(true); 921 NfcService.getInstance().sendMockNdefTag(m); 922 } 923 break; 924 case MSG_HANDOVER_NOT_SUPPORTED: 925 synchronized (P2pLinkManager.this) { 926 mSendTask = null; 927 928 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 929 break; 930 } 931 mSendState = SEND_STATE_NOTHING_TO_SEND; 932 if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()"); 933 mEventListener.onP2pHandoverNotSupported(); 934 } 935 break; 936 case MSG_SEND_COMPLETE: 937 synchronized (P2pLinkManager.this) { 938 mSendTask = null; 939 940 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 941 break; 942 } 943 mSendState = SEND_STATE_SEND_COMPLETE; 944 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 945 if (DBG) Log.d(TAG, "onP2pSendComplete()"); 946 mEventListener.onP2pSendComplete(); 947 if (mCallbackNdef != null) { 948 try { 949 mCallbackNdef.onNdefPushComplete(); 950 } catch (Exception e) { 951 Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage()); 952 } 953 } 954 } 955 break; 956 } 957 return true; 958 } 959 960 int getMessageSize(NdefMessage msg) { 961 if (msg != null) { 962 return msg.toByteArray().length; 963 } else { 964 return 0; 965 } 966 } 967 968 int getMessageTnf(NdefMessage msg) { 969 if (msg == null) { 970 return NdefRecord.TNF_EMPTY; 971 } 972 NdefRecord records[] = msg.getRecords(); 973 if (records == null || records.length == 0) { 974 return NdefRecord.TNF_EMPTY; 975 } 976 return records[0].getTnf(); 977 } 978 979 String getMessageType(NdefMessage msg) { 980 if (msg == null) { 981 return "null"; 982 } 983 NdefRecord records[] = msg.getRecords(); 984 if (records == null || records.length == 0) { 985 return "null"; 986 } 987 NdefRecord record = records[0]; 988 switch (record.getTnf()) { 989 case NdefRecord.TNF_ABSOLUTE_URI: 990 // The actual URI is in the type field, don't log it 991 return "uri"; 992 case NdefRecord.TNF_EXTERNAL_TYPE: 993 case NdefRecord.TNF_MIME_MEDIA: 994 case NdefRecord.TNF_WELL_KNOWN: 995 return new String(record.getType(), Charsets.UTF_8); 996 default: 997 return "unknown"; 998 } 999 } 1000 1001 int getMessageAarPresent(NdefMessage msg) { 1002 if (msg == null) { 1003 return 0; 1004 } 1005 NdefRecord records[] = msg.getRecords(); 1006 if (records == null) { 1007 return 0; 1008 } 1009 for (NdefRecord record : records) { 1010 if (record.getTnf() == NdefRecord.TNF_EXTERNAL_TYPE && 1011 Arrays.equals(NdefRecord.RTD_ANDROID_APP, record.getType())) { 1012 return 1; 1013 } 1014 } 1015 return 0; 1016 } 1017 1018 @Override 1019 public void onP2pSendConfirmed() { 1020 onP2pSendConfirmed(true); 1021 } 1022 1023 private void onP2pSendConfirmed(boolean requireConfirmation) { 1024 if (DBG) Log.d(TAG, "onP2pSendConfirmed()"); 1025 synchronized (this) { 1026 if (mLinkState == LINK_STATE_DOWN || (requireConfirmation 1027 && mSendState != SEND_STATE_NEED_CONFIRMATION)) { 1028 return; 1029 } 1030 mSendState = SEND_STATE_SENDING; 1031 if (mLinkState == LINK_STATE_WAITING_PDU) { 1032 // We could decide to wait for the first PDU here; but 1033 // that makes us vulnerable to cases where for some reason 1034 // this event is not propagated up by the stack. Instead, 1035 // try to connect now. 1036 mLinkState = LINK_STATE_UP; 1037 connectLlcpServices(); 1038 } else if (mLinkState == LINK_STATE_UP && mLlcpServicesConnected) { 1039 sendNdefMessage(); 1040 } else if (mLinkState == LINK_STATE_UP && mLlcpConnectDelayed) { 1041 // Connect was delayed to interop with pre-MR2 stacks; send connect now. 1042 connectLlcpServices(); 1043 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1044 // Restart debounce timeout 1045 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 1046 mHandler.sendEmptyMessageDelayed(MSG_DEBOUNCE_TIMEOUT, 1047 LINK_SEND_CONFIRMED_DEBOUNCE_MS); 1048 // Tell user to tap devices again 1049 mEventListener.onP2pSendDebounce(); 1050 } 1051 } 1052 } 1053 1054 static String sendStateToString(int state) { 1055 switch (state) { 1056 case SEND_STATE_NOTHING_TO_SEND: 1057 return "SEND_STATE_NOTHING_TO_SEND"; 1058 case SEND_STATE_NEED_CONFIRMATION: 1059 return "SEND_STATE_NEED_CONFIRMATION"; 1060 case SEND_STATE_SENDING: 1061 return "SEND_STATE_SENDING"; 1062 default: 1063 return "<error>"; 1064 } 1065 } 1066 1067 static String linkStateToString(int state) { 1068 switch (state) { 1069 case LINK_STATE_DOWN: 1070 return "LINK_STATE_DOWN"; 1071 case LINK_STATE_DEBOUNCE: 1072 return "LINK_STATE_DEBOUNCE"; 1073 case LINK_STATE_UP: 1074 return "LINK_STATE_UP"; 1075 case LINK_STATE_WAITING_PDU: 1076 return "LINK_STATE_WAITING_PDU"; 1077 default: 1078 return "<error>"; 1079 } 1080 } 1081 1082 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1083 synchronized (this) { 1084 pw.println("mIsSendEnabled=" + mIsSendEnabled); 1085 pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled); 1086 pw.println("mLinkState=" + linkStateToString(mLinkState)); 1087 pw.println("mSendState=" + sendStateToString(mSendState)); 1088 1089 pw.println("mCallbackNdef=" + mCallbackNdef); 1090 pw.println("mMessageToSend=" + mMessageToSend); 1091 pw.println("mUrisToSend=" + mUrisToSend); 1092 } 1093 } 1094 } 1095