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