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_SEND_PENDING_DEBOUNCE_MS = 3000; 168 static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000; 169 static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 500; 170 static final int LINK_SEND_CANCELED_DEBOUNCE_MS = 250; 171 172 // The amount of time we wait for the link to come up 173 // after a user has manually invoked Beam. 174 static final int WAIT_FOR_LINK_TIMEOUT_MS = 10000; 175 176 static final int MSG_DEBOUNCE_TIMEOUT = 1; 177 static final int MSG_RECEIVE_COMPLETE = 2; 178 static final int MSG_RECEIVE_HANDOVER = 3; 179 static final int MSG_SEND_COMPLETE = 4; 180 static final int MSG_START_ECHOSERVER = 5; 181 static final int MSG_STOP_ECHOSERVER = 6; 182 static final int MSG_HANDOVER_NOT_SUPPORTED = 7; 183 static final int MSG_SHOW_CONFIRMATION_UI = 8; 184 static final int MSG_WAIT_FOR_LINK_TIMEOUT = 9; 185 static final int MSG_HANDOVER_BUSY = 10; 186 187 // values for mLinkState 188 static final int LINK_STATE_DOWN = 1; 189 static final int LINK_STATE_UP = 2; 190 static final int LINK_STATE_DEBOUNCE = 3; 191 192 // values for mSendState 193 static final int SEND_STATE_NOTHING_TO_SEND = 1; 194 static final int SEND_STATE_NEED_CONFIRMATION = 2; 195 static final int SEND_STATE_PENDING = 3; 196 static final int SEND_STATE_SENDING = 4; 197 static final int SEND_STATE_COMPLETE = 5; 198 static final int SEND_STATE_CANCELED = 6; 199 200 // return values for doSnepProtocol 201 static final int SNEP_SUCCESS = 0; 202 static final int SNEP_FAILURE = 1; 203 204 // return values for doHandover 205 static final int HANDOVER_SUCCESS = 0; 206 static final int HANDOVER_FAILURE = 1; 207 static final int HANDOVER_UNSUPPORTED = 2; 208 static final int HANDOVER_BUSY = 3; 209 210 final NdefPushServer mNdefPushServer; 211 final SnepServer mDefaultSnepServer; 212 final HandoverServer mHandoverServer; 213 final EchoServer mEchoServer; 214 final Context mContext; 215 final P2pEventListener mEventListener; 216 final Handler mHandler; 217 final HandoverDataParser mHandoverDataParser; 218 final ForegroundUtils mForegroundUtils; 219 220 final int mDefaultMiu; 221 final int mDefaultRwSize; 222 223 // Locked on NdefP2pManager.this 224 PackageManager mPackageManager; 225 int mLinkState; 226 int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE 227 boolean mIsSendEnabled; 228 boolean mIsReceiveEnabled; 229 NdefMessage mMessageToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 230 Uri[] mUrisToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 231 UserHandle mUserHandle; // not valid in SEND_STATE_NOTHING_TO_SEND 232 int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND 233 IAppCallback mCallbackNdef; 234 int mNdefCallbackUid; 235 SendTask mSendTask; 236 SharedPreferences mPrefs; 237 SnepClient mSnepClient; 238 HandoverClient mHandoverClient; 239 NdefPushClient mNdefPushClient; 240 ConnectTask mConnectTask; 241 boolean mLlcpServicesConnected; 242 long mLastLlcpActivationTime; 243 byte mPeerLlcpVersion; 244 245 public P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu, 246 int defaultRwSize) { 247 mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); 248 mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize); 249 mHandoverServer = new HandoverServer(context, HANDOVER_SAP, handoverDataParser, mHandoverCallback); 250 251 if (ECHOSERVER_ENABLED) { 252 mEchoServer = new EchoServer(); 253 } else { 254 mEchoServer = null; 255 } 256 mPackageManager = context.getPackageManager(); 257 mContext = context; 258 mEventListener = new P2pEventManager(context, this); 259 mHandler = new Handler(this); 260 mLinkState = LINK_STATE_DOWN; 261 mSendState = SEND_STATE_NOTHING_TO_SEND; 262 mIsSendEnabled = false; 263 mIsReceiveEnabled = false; 264 mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE); 265 mHandoverDataParser = handoverDataParser; 266 mDefaultMiu = defaultMiu; 267 mDefaultRwSize = defaultRwSize; 268 mLlcpServicesConnected = false; 269 mNdefCallbackUid = -1; 270 mForegroundUtils = ForegroundUtils.getInstance(); 271 } 272 273 /** 274 * May be called from any thread. 275 * Assumes that NFC is already on if any parameter is true. 276 */ 277 public void enableDisable(boolean sendEnable, boolean receiveEnable) { 278 synchronized (this) { 279 if (!mIsReceiveEnabled && receiveEnable) { 280 mDefaultSnepServer.start(); 281 mNdefPushServer.start(); 282 mHandoverServer.start(); 283 if (mEchoServer != null) { 284 mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); 285 } 286 } else if (mIsReceiveEnabled && !receiveEnable) { 287 if (DBG) Log.d(TAG, "enableDisable: llcp deactivate"); 288 onLlcpDeactivated (); 289 mDefaultSnepServer.stop(); 290 mNdefPushServer.stop(); 291 mHandoverServer.stop(); 292 if (mEchoServer != null) { 293 mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); 294 } 295 } 296 mIsSendEnabled = sendEnable; 297 mIsReceiveEnabled = receiveEnable; 298 } 299 } 300 301 /** 302 * May be called from any thread. 303 * @return whether the LLCP link is in an active or debounce state 304 */ 305 public boolean isLlcpActive() { 306 synchronized (this) { 307 return mLinkState != LINK_STATE_DOWN; 308 } 309 } 310 311 /** 312 * Set NDEF callback for sending. 313 * May be called from any thread. 314 * NDEF callbacks may be set at any time (even if NFC is 315 * currently off or P2P send is currently off). They will become 316 * active as soon as P2P send is enabled. 317 */ 318 public void setNdefCallback(IAppCallback callbackNdef, int callingUid) { 319 synchronized (this) { 320 mCallbackNdef = callbackNdef; 321 mNdefCallbackUid = callingUid; 322 } 323 } 324 325 326 public void onManualBeamInvoke(BeamShareData shareData) { 327 synchronized (P2pLinkManager.this) { 328 if (mLinkState != LINK_STATE_DOWN) { 329 return; 330 } 331 if (mForegroundUtils.getForegroundUids().contains(mNdefCallbackUid)) { 332 // Try to get data from the registered NDEF callback 333 prepareMessageToSend(false); 334 } else { 335 mMessageToSend = null; 336 mUrisToSend = null; 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(byte peerLlcpVersion) { 361 Log.i(TAG, "LLCP activated"); 362 synchronized (P2pLinkManager.this) { 363 if (mEchoServer != null) { 364 mEchoServer.onLlcpActivated(); 365 } 366 mLastLlcpActivationTime = SystemClock.elapsedRealtime(); 367 mPeerLlcpVersion = peerLlcpVersion; 368 switch (mLinkState) { 369 case LINK_STATE_DOWN: 370 if (DBG) Log.d(TAG, "onP2pInRange()"); 371 // Start taking a screenshot 372 mEventListener.onP2pInRange(); 373 mLinkState = LINK_STATE_UP; 374 // If we had a pending send (manual Beam invoke), 375 // mark it as sending 376 if (mSendState == SEND_STATE_PENDING) { 377 mSendState = SEND_STATE_SENDING; 378 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT); 379 // Immediately try to connect LLCP services 380 connectLlcpServices(); 381 } else { 382 mSendState = SEND_STATE_NOTHING_TO_SEND; 383 prepareMessageToSend(true); 384 if (mMessageToSend != null || 385 (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) { 386 // We have data to send, connect LLCP services 387 connectLlcpServices(); 388 if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) { 389 mSendState = SEND_STATE_SENDING; 390 } else { 391 mSendState = SEND_STATE_NEED_CONFIRMATION; 392 } 393 } 394 } 395 break; 396 case LINK_STATE_UP: 397 if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()"); 398 return; 399 case LINK_STATE_DEBOUNCE: 400 // Immediately connect and try to send again 401 mLinkState = LINK_STATE_UP; 402 if (mSendState == SEND_STATE_SENDING || 403 mSendState == SEND_STATE_NEED_CONFIRMATION) { 404 // If we have something to send still, connect LLCP 405 connectLlcpServices(); 406 } 407 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 408 break; 409 } 410 } 411 } 412 413 /** 414 * Must be called on UI Thread. 415 */ 416 public void onLlcpFirstPacketReceived() { 417 synchronized (P2pLinkManager.this) { 418 long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime; 419 if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU"); 420 } 421 } 422 423 public void onUserSwitched(int userId) { 424 // Update the cached package manager in case of user switch 425 synchronized (P2pLinkManager.this) { 426 try { 427 mPackageManager = mContext.createPackageContextAsUser("android", 0, 428 new UserHandle(userId)).getPackageManager(); 429 } catch (NameNotFoundException e) { 430 Log.e(TAG, "Failed to retrieve PackageManager for user"); 431 } 432 } 433 } 434 435 void prepareMessageToSend(boolean generatePlayLink) { 436 synchronized (P2pLinkManager.this) { 437 mMessageToSend = null; 438 mUrisToSend = null; 439 if (!mIsSendEnabled) { 440 return; 441 } 442 443 List<Integer> foregroundUids = mForegroundUtils.getForegroundUids(); 444 if (foregroundUids.isEmpty()) { 445 Log.e(TAG, "Could not determine foreground UID."); 446 return; 447 } 448 449 if (isBeamDisabled(foregroundUids.get(0))) { 450 if (DBG) Log.d(TAG, "Beam is disabled by policy."); 451 return; 452 } 453 454 if (mCallbackNdef != null) { 455 if (foregroundUids.contains(mNdefCallbackUid)) { 456 try { 457 BeamShareData shareData = mCallbackNdef.createBeamShareData(mPeerLlcpVersion); 458 mMessageToSend = shareData.ndefMessage; 459 mUrisToSend = shareData.uris; 460 mUserHandle = shareData.userHandle; 461 mSendFlags = shareData.flags; 462 return; 463 } catch (Exception e) { 464 Log.e(TAG, "Failed NDEF callback: ", e); 465 } 466 } else { 467 // This is not necessarily an error - we no longer unset callbacks from 468 // the app process itself (to prevent IPC calls on every pause). 469 // Hence it may simply be a stale callback. 470 if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground."); 471 } 472 } 473 474 // fall back to default NDEF for the foreground activity, unless the 475 // application disabled this explicitly in their manifest. 476 String[] pkgs = mPackageManager.getPackagesForUid(foregroundUids.get(0)); 477 if (pkgs != null && pkgs.length >= 1) { 478 if (!generatePlayLink || beamDefaultDisabled(pkgs[0])) { 479 if (DBG) Log.d(TAG, "Disabling default Beam behavior"); 480 mMessageToSend = null; 481 mUrisToSend = null; 482 } else { 483 mMessageToSend = createDefaultNdef(pkgs[0]); 484 mUrisToSend = null; 485 mSendFlags = 0; 486 } 487 } 488 489 if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend); 490 if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend); 491 } 492 } 493 494 private boolean isBeamDisabled(int uid) { 495 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 496 UserInfo userInfo = userManager.getUserInfo(UserHandle.getUserId(uid)); 497 return userManager.hasUserRestriction( 498 UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle()); 499 500 } 501 502 boolean beamDefaultDisabled(String pkgName) { 503 try { 504 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName, 505 PackageManager.GET_META_DATA); 506 if (ai == null || ai.metaData == null) { 507 return false; 508 } 509 return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT); 510 } catch (NameNotFoundException e) { 511 return false; 512 } 513 } 514 515 NdefMessage createDefaultNdef(String pkgName) { 516 NdefRecord appUri = NdefRecord.createUri(Uri.parse( 517 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam")); 518 NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName); 519 return new NdefMessage(new NdefRecord[] { appUri, appRecord }); 520 } 521 522 void disconnectLlcpServices() { 523 synchronized (this) { 524 if (mConnectTask != null) { 525 mConnectTask.cancel(true); 526 mConnectTask = null; 527 } 528 // Close any already connected LLCP clients 529 if (mNdefPushClient != null) { 530 mNdefPushClient.close(); 531 mNdefPushClient = null; 532 } 533 if (mSnepClient != null) { 534 mSnepClient.close(); 535 mSnepClient = null; 536 } 537 if (mHandoverClient != null) { 538 mHandoverClient.close(); 539 mHandoverClient = null; 540 } 541 mLlcpServicesConnected = false; 542 } 543 } 544 545 /** 546 * Must be called on UI Thread. 547 */ 548 public void onLlcpDeactivated() { 549 Log.i(TAG, "LLCP deactivated."); 550 synchronized (this) { 551 if (mEchoServer != null) { 552 mEchoServer.onLlcpDeactivated(); 553 } 554 555 switch (mLinkState) { 556 case LINK_STATE_DOWN: 557 case LINK_STATE_DEBOUNCE: 558 Log.i(TAG, "Duplicate onLlcpDectivated()"); 559 break; 560 case LINK_STATE_UP: 561 // Debounce 562 mLinkState = LINK_STATE_DEBOUNCE; 563 int debounceTimeout = 0; 564 switch (mSendState) { 565 case SEND_STATE_NOTHING_TO_SEND: 566 debounceTimeout = 0; 567 break; 568 case SEND_STATE_NEED_CONFIRMATION: 569 debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS; 570 break; 571 case SEND_STATE_SENDING: 572 debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS; 573 break; 574 case SEND_STATE_COMPLETE: 575 debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS; 576 break; 577 case SEND_STATE_CANCELED: 578 debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS; 579 } 580 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout); 581 if (mSendState == SEND_STATE_SENDING) { 582 Log.e(TAG, "onP2pSendDebounce()"); 583 mEventListener.onP2pSendDebounce(); 584 } 585 cancelSendNdefMessage(); 586 disconnectLlcpServices(); 587 break; 588 } 589 } 590 } 591 592 void onHandoverUnsupported() { 593 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 594 } 595 596 void onHandoverBusy() { 597 mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY); 598 } 599 600 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 601 // Make callbacks on UI thread 602 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 603 } 604 605 void sendNdefMessage() { 606 synchronized (this) { 607 cancelSendNdefMessage(); 608 mSendTask = new SendTask(); 609 mSendTask.execute(); 610 } 611 } 612 613 void cancelSendNdefMessage() { 614 synchronized (P2pLinkManager.this) { 615 if (mSendTask != null) { 616 mSendTask.cancel(true); 617 } 618 } 619 } 620 621 void connectLlcpServices() { 622 synchronized (P2pLinkManager.this) { 623 if (mConnectTask != null) { 624 Log.e(TAG, "Still had a reference to mConnectTask!"); 625 } 626 mConnectTask = new ConnectTask(); 627 mConnectTask.execute(); 628 } 629 } 630 631 // Must be called on UI-thread 632 void onLlcpServicesConnected() { 633 if (DBG) Log.d(TAG, "onLlcpServicesConnected"); 634 synchronized (P2pLinkManager.this) { 635 if (mLinkState != LINK_STATE_UP) { 636 return; 637 } 638 mLlcpServicesConnected = true; 639 if (mSendState == SEND_STATE_NEED_CONFIRMATION) { 640 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()"); 641 mEventListener.onP2pSendConfirmationRequested(); 642 } else if (mSendState == SEND_STATE_SENDING) { 643 mEventListener.onP2pResumeSend(); 644 sendNdefMessage(); 645 } else { 646 // Either nothing to send or canceled/complete, ignore 647 } 648 } 649 } 650 651 final class ConnectTask extends AsyncTask<Void, Void, Boolean> { 652 @Override 653 protected void onPostExecute(Boolean result) { 654 if (isCancelled()) { 655 if (DBG) Log.d(TAG, "ConnectTask was cancelled"); 656 return; 657 } 658 if (result) { 659 onLlcpServicesConnected(); 660 } else { 661 Log.e(TAG, "Could not connect required NFC transports"); 662 } 663 } 664 665 @Override 666 protected Boolean doInBackground(Void... params) { 667 boolean needsHandover = false; 668 boolean needsNdef = false; 669 boolean success = false; 670 HandoverClient handoverClient = null; 671 SnepClient snepClient = null; 672 NdefPushClient nppClient = null; 673 674 synchronized(P2pLinkManager.this) { 675 if (mUrisToSend != null) { 676 needsHandover = true; 677 } 678 679 if (mMessageToSend != null) { 680 needsNdef = true; 681 } 682 } 683 // We know either is requested - otherwise this task 684 // wouldn't have been started. 685 if (needsHandover) { 686 handoverClient = new HandoverClient(); 687 try { 688 handoverClient.connect(); 689 success = true; // Regardless of NDEF result 690 } catch (IOException e) { 691 handoverClient = null; 692 } 693 } 694 695 if (needsNdef || (needsHandover && handoverClient == null)) { 696 snepClient = new SnepClient(); 697 try { 698 snepClient.connect(); 699 success = true; 700 } catch (IOException e) { 701 snepClient = null; 702 } 703 704 if (!success) { 705 nppClient = new NdefPushClient(); 706 try { 707 nppClient.connect(); 708 success = true; 709 } catch (IOException e) { 710 nppClient = null; 711 } 712 } 713 } 714 715 synchronized (P2pLinkManager.this) { 716 if (isCancelled()) { 717 // Cancelled by onLlcpDeactivated on UI thread 718 if (handoverClient != null) { 719 handoverClient.close(); 720 } 721 if (snepClient != null) { 722 snepClient.close(); 723 } 724 if (nppClient != null) { 725 nppClient.close(); 726 } 727 return false; 728 } else { 729 // Once assigned, these are the responsibility of 730 // the code on the UI thread to release - typically 731 // through onLlcpDeactivated(). 732 mHandoverClient = handoverClient; 733 mSnepClient = snepClient; 734 mNdefPushClient = nppClient; 735 return success; 736 } 737 } 738 } 739 }; 740 741 final class SendTask extends AsyncTask<Void, Void, Void> { 742 NdefPushClient nppClient; 743 SnepClient snepClient; 744 HandoverClient handoverClient; 745 746 int doHandover(Uri[] uris, UserHandle userHandle) throws IOException { 747 NdefMessage response = null; 748 BeamManager beamManager = BeamManager.getInstance(); 749 750 if (beamManager.isBeamInProgress()) { 751 return HANDOVER_BUSY; 752 } 753 754 NdefMessage request = mHandoverDataParser.createHandoverRequestMessage(); 755 if (request != null) { 756 if (handoverClient != null) { 757 response = handoverClient.sendHandoverRequest(request); 758 } 759 if (response == null && snepClient != null) { 760 // Remote device may not support handover service, 761 // try the (deprecated) SNEP GET implementation 762 // for devices running Android 4.1 763 SnepMessage snepResponse = snepClient.get(request); 764 response = snepResponse.getNdefMessage(); 765 } 766 if (response == null) { 767 if (snepClient != null) 768 return HANDOVER_UNSUPPORTED; 769 else 770 return HANDOVER_FAILURE; 771 } 772 } else { 773 return HANDOVER_UNSUPPORTED; 774 } 775 776 if (!beamManager.startBeamSend(mContext, 777 mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) { 778 return HANDOVER_BUSY; 779 } 780 781 return HANDOVER_SUCCESS; 782 } 783 784 int doSnepProtocol(NdefMessage msg) throws IOException { 785 if (msg != null) { 786 snepClient.put(msg); 787 return SNEP_SUCCESS; 788 } else { 789 return SNEP_FAILURE; 790 } 791 } 792 793 @Override 794 public Void doInBackground(Void... args) { 795 NdefMessage m; 796 Uri[] uris; 797 UserHandle userHandle; 798 boolean result = false; 799 800 synchronized (P2pLinkManager.this) { 801 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) { 802 return null; 803 } 804 m = mMessageToSend; 805 uris = mUrisToSend; 806 userHandle = mUserHandle; 807 snepClient = mSnepClient; 808 handoverClient = mHandoverClient; 809 nppClient = mNdefPushClient; 810 } 811 812 long time = SystemClock.elapsedRealtime(); 813 814 if (uris != null) { 815 if (DBG) Log.d(TAG, "Trying handover request"); 816 try { 817 int handoverResult = doHandover(uris, userHandle); 818 switch (handoverResult) { 819 case HANDOVER_SUCCESS: 820 result = true; 821 break; 822 case HANDOVER_FAILURE: 823 result = false; 824 break; 825 case HANDOVER_UNSUPPORTED: 826 result = false; 827 onHandoverUnsupported(); 828 break; 829 case HANDOVER_BUSY: 830 result = false; 831 onHandoverBusy(); 832 break; 833 } 834 } catch (IOException e) { 835 result = false; 836 } 837 } 838 839 if (!result && m != null && snepClient != null) { 840 if (DBG) Log.d(TAG, "Sending ndef via SNEP"); 841 try { 842 int snepResult = doSnepProtocol(m); 843 switch (snepResult) { 844 case SNEP_SUCCESS: 845 result = true; 846 break; 847 case SNEP_FAILURE: 848 result = false; 849 break; 850 default: 851 result = false; 852 } 853 } catch (IOException e) { 854 result = false; 855 } 856 } 857 858 if (!result && m != null && nppClient != null) { 859 result = nppClient.push(m); 860 } 861 862 time = SystemClock.elapsedRealtime() - time; 863 if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time); 864 if (result) { 865 onSendComplete(m, time); 866 } 867 868 return null; 869 } 870 }; 871 872 873 final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { 874 @Override 875 public void onHandoverRequestReceived() { 876 onReceiveHandover(); 877 } 878 879 @Override 880 public void onHandoverBusy() { 881 P2pLinkManager.this.onHandoverBusy(); 882 } 883 }; 884 885 final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { 886 @Override 887 public void onMessageReceived(NdefMessage msg) { 888 onReceiveComplete(msg); 889 } 890 }; 891 892 final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() { 893 @Override 894 public SnepMessage doPut(NdefMessage msg) { 895 onReceiveComplete(msg); 896 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 897 } 898 899 @Override 900 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 901 // The NFC Forum Default SNEP server is not allowed to respond to 902 // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, 903 // since Android 4.1 used the NFC Forum default server to 904 // implement connection handover, we will support this 905 // until we can deprecate it. 906 NdefMessage response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect; 907 if (response != null) { 908 onReceiveHandover(); 909 return SnepMessage.getSuccessResponse(response); 910 } else { 911 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 912 } 913 } 914 }; 915 916 void onReceiveHandover() { 917 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 918 } 919 920 void onReceiveComplete(NdefMessage msg) { 921 // Make callbacks on UI thread 922 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 923 } 924 925 @Override 926 public boolean handleMessage(Message msg) { 927 switch (msg.what) { 928 case MSG_START_ECHOSERVER: 929 synchronized (this) { 930 mEchoServer.start(); 931 break; 932 } 933 case MSG_STOP_ECHOSERVER: 934 synchronized (this) { 935 mEchoServer.stop(); 936 break; 937 } 938 case MSG_WAIT_FOR_LINK_TIMEOUT: 939 synchronized (this) { 940 // User wanted to send something but no link 941 // came up. Just cancel the send 942 mSendState = SEND_STATE_NOTHING_TO_SEND; 943 mEventListener.onP2pTimeoutWaitingForLink(); 944 } 945 break; 946 case MSG_DEBOUNCE_TIMEOUT: 947 synchronized (this) { 948 if (mLinkState != LINK_STATE_DEBOUNCE) { 949 break; 950 } 951 if (DBG) Log.d(TAG, "Debounce timeout"); 952 mLinkState = LINK_STATE_DOWN; 953 mSendState = SEND_STATE_NOTHING_TO_SEND; 954 mMessageToSend = null; 955 mUrisToSend = null; 956 if (DBG) Log.d(TAG, "onP2pOutOfRange()"); 957 mEventListener.onP2pOutOfRange(); 958 } 959 break; 960 case MSG_RECEIVE_HANDOVER: 961 // We're going to do a handover request 962 synchronized (this) { 963 if (mLinkState == LINK_STATE_DOWN) { 964 break; 965 } 966 if (mSendState == SEND_STATE_SENDING) { 967 cancelSendNdefMessage(); 968 } 969 mSendState = SEND_STATE_NOTHING_TO_SEND; 970 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 971 mEventListener.onP2pReceiveComplete(false); 972 } 973 break; 974 case MSG_RECEIVE_COMPLETE: 975 NdefMessage m = (NdefMessage) msg.obj; 976 synchronized (this) { 977 if (mLinkState == LINK_STATE_DOWN) { 978 break; 979 } 980 if (mSendState == SEND_STATE_SENDING) { 981 cancelSendNdefMessage(); 982 } 983 mSendState = SEND_STATE_NOTHING_TO_SEND; 984 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 985 mEventListener.onP2pReceiveComplete(true); 986 NfcService.getInstance().sendMockNdefTag(m); 987 } 988 break; 989 case MSG_HANDOVER_NOT_SUPPORTED: 990 synchronized (P2pLinkManager.this) { 991 mSendTask = null; 992 993 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 994 break; 995 } 996 mSendState = SEND_STATE_NOTHING_TO_SEND; 997 if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()"); 998 mEventListener.onP2pHandoverNotSupported(); 999 } 1000 break; 1001 case MSG_SEND_COMPLETE: 1002 synchronized (P2pLinkManager.this) { 1003 mSendTask = null; 1004 1005 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1006 break; 1007 } 1008 mSendState = SEND_STATE_COMPLETE; 1009 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 1010 if (DBG) Log.d(TAG, "onP2pSendComplete()"); 1011 mEventListener.onP2pSendComplete(); 1012 if (mCallbackNdef != null) { 1013 try { 1014 mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion); 1015 } catch (Exception e) { 1016 Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage()); 1017 } 1018 } 1019 } 1020 break; 1021 case MSG_HANDOVER_BUSY: 1022 synchronized (P2pLinkManager.this) { 1023 mSendTask = null; 1024 1025 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1026 break; 1027 } 1028 mSendState = SEND_STATE_NOTHING_TO_SEND; 1029 if (DBG) Log.d(TAG, "onP2pHandoverBusy()"); 1030 mEventListener.onP2pHandoverBusy(); 1031 } 1032 } 1033 return true; 1034 } 1035 1036 1037 @Override 1038 public void onP2pSendConfirmed() { 1039 onP2pSendConfirmed(true); 1040 } 1041 1042 private void onP2pSendConfirmed(boolean requireConfirmation) { 1043 if (DBG) Log.d(TAG, "onP2pSendConfirmed()"); 1044 synchronized (this) { 1045 if (mLinkState == LINK_STATE_DOWN || (requireConfirmation 1046 && mSendState != SEND_STATE_NEED_CONFIRMATION)) { 1047 return; 1048 } 1049 mSendState = SEND_STATE_SENDING; 1050 if (mLinkState == LINK_STATE_UP) { 1051 if (mLlcpServicesConnected) { 1052 sendNdefMessage(); 1053 } // else, will send messages when link comes up 1054 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1055 // Restart debounce timeout and tell user to tap again 1056 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CONFIRMED_DEBOUNCE_MS); 1057 mEventListener.onP2pSendDebounce(); 1058 } 1059 } 1060 } 1061 1062 1063 @Override 1064 public void onP2pCanceled() { 1065 synchronized (this) { 1066 mSendState = SEND_STATE_CANCELED; 1067 if (mLinkState == LINK_STATE_DOWN) { 1068 // If we were waiting for the link to come up, stop doing so 1069 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT); 1070 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1071 // We're in debounce state so link is down. Reschedule debounce 1072 // timeout to occur sooner, we don't want to wait any longer. 1073 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CANCELED_DEBOUNCE_MS); 1074 } else { 1075 // Link is up, nothing else to do but wait for link to go down 1076 } 1077 } 1078 } 1079 1080 void scheduleTimeoutLocked(int what, int timeout) { 1081 // Cancel any outstanding debounce timeouts. 1082 mHandler.removeMessages(what); 1083 mHandler.sendEmptyMessageDelayed(what, timeout); 1084 } 1085 1086 static String sendStateToString(int state) { 1087 switch (state) { 1088 case SEND_STATE_NOTHING_TO_SEND: 1089 return "SEND_STATE_NOTHING_TO_SEND"; 1090 case SEND_STATE_NEED_CONFIRMATION: 1091 return "SEND_STATE_NEED_CONFIRMATION"; 1092 case SEND_STATE_SENDING: 1093 return "SEND_STATE_SENDING"; 1094 case SEND_STATE_COMPLETE: 1095 return "SEND_STATE_COMPLETE"; 1096 case SEND_STATE_CANCELED: 1097 return "SEND_STATE_CANCELED"; 1098 default: 1099 return "<error>"; 1100 } 1101 } 1102 1103 static String linkStateToString(int state) { 1104 switch (state) { 1105 case LINK_STATE_DOWN: 1106 return "LINK_STATE_DOWN"; 1107 case LINK_STATE_DEBOUNCE: 1108 return "LINK_STATE_DEBOUNCE"; 1109 case LINK_STATE_UP: 1110 return "LINK_STATE_UP"; 1111 default: 1112 return "<error>"; 1113 } 1114 } 1115 1116 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1117 synchronized (this) { 1118 pw.println("mIsSendEnabled=" + mIsSendEnabled); 1119 pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled); 1120 pw.println("mLinkState=" + linkStateToString(mLinkState)); 1121 pw.println("mSendState=" + sendStateToString(mSendState)); 1122 1123 pw.println("mCallbackNdef=" + mCallbackNdef); 1124 pw.println("mMessageToSend=" + mMessageToSend); 1125 pw.println("mUrisToSend=" + mUrisToSend); 1126 } 1127 } 1128 } 1129