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 } 486 } 487 488 if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend); 489 if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend); 490 } 491 } 492 493 private boolean isBeamDisabled(int uid) { 494 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 495 UserInfo userInfo = userManager.getUserInfo(UserHandle.getUserId(uid)); 496 return userManager.hasUserRestriction( 497 UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle()); 498 499 } 500 501 boolean beamDefaultDisabled(String pkgName) { 502 try { 503 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName, 504 PackageManager.GET_META_DATA); 505 if (ai == null || ai.metaData == null) { 506 return false; 507 } 508 return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT); 509 } catch (NameNotFoundException e) { 510 return false; 511 } 512 } 513 514 NdefMessage createDefaultNdef(String pkgName) { 515 NdefRecord appUri = NdefRecord.createUri(Uri.parse( 516 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam")); 517 NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName); 518 return new NdefMessage(new NdefRecord[] { appUri, appRecord }); 519 } 520 521 void disconnectLlcpServices() { 522 synchronized (this) { 523 if (mConnectTask != null) { 524 mConnectTask.cancel(true); 525 mConnectTask = null; 526 } 527 // Close any already connected LLCP clients 528 if (mNdefPushClient != null) { 529 mNdefPushClient.close(); 530 mNdefPushClient = null; 531 } 532 if (mSnepClient != null) { 533 mSnepClient.close(); 534 mSnepClient = null; 535 } 536 if (mHandoverClient != null) { 537 mHandoverClient.close(); 538 mHandoverClient = null; 539 } 540 mLlcpServicesConnected = false; 541 } 542 } 543 544 /** 545 * Must be called on UI Thread. 546 */ 547 public void onLlcpDeactivated() { 548 Log.i(TAG, "LLCP deactivated."); 549 synchronized (this) { 550 if (mEchoServer != null) { 551 mEchoServer.onLlcpDeactivated(); 552 } 553 554 switch (mLinkState) { 555 case LINK_STATE_DOWN: 556 case LINK_STATE_DEBOUNCE: 557 Log.i(TAG, "Duplicate onLlcpDectivated()"); 558 break; 559 case LINK_STATE_UP: 560 // Debounce 561 mLinkState = LINK_STATE_DEBOUNCE; 562 int debounceTimeout = 0; 563 switch (mSendState) { 564 case SEND_STATE_NOTHING_TO_SEND: 565 debounceTimeout = 0; 566 break; 567 case SEND_STATE_NEED_CONFIRMATION: 568 debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS; 569 break; 570 case SEND_STATE_SENDING: 571 debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS; 572 break; 573 case SEND_STATE_COMPLETE: 574 debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS; 575 break; 576 case SEND_STATE_CANCELED: 577 debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS; 578 } 579 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout); 580 if (mSendState == SEND_STATE_SENDING) { 581 Log.e(TAG, "onP2pSendDebounce()"); 582 mEventListener.onP2pSendDebounce(); 583 } 584 cancelSendNdefMessage(); 585 disconnectLlcpServices(); 586 break; 587 } 588 } 589 } 590 591 void onHandoverUnsupported() { 592 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 593 } 594 595 void onHandoverBusy() { 596 mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY); 597 } 598 599 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 600 // Make callbacks on UI thread 601 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 602 } 603 604 void sendNdefMessage() { 605 synchronized (this) { 606 cancelSendNdefMessage(); 607 mSendTask = new SendTask(); 608 mSendTask.execute(); 609 } 610 } 611 612 void cancelSendNdefMessage() { 613 synchronized (P2pLinkManager.this) { 614 if (mSendTask != null) { 615 mSendTask.cancel(true); 616 } 617 } 618 } 619 620 void connectLlcpServices() { 621 synchronized (P2pLinkManager.this) { 622 if (mConnectTask != null) { 623 Log.e(TAG, "Still had a reference to mConnectTask!"); 624 } 625 mConnectTask = new ConnectTask(); 626 mConnectTask.execute(); 627 } 628 } 629 630 // Must be called on UI-thread 631 void onLlcpServicesConnected() { 632 if (DBG) Log.d(TAG, "onLlcpServicesConnected"); 633 synchronized (P2pLinkManager.this) { 634 if (mLinkState != LINK_STATE_UP) { 635 return; 636 } 637 mLlcpServicesConnected = true; 638 if (mSendState == SEND_STATE_NEED_CONFIRMATION) { 639 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()"); 640 mEventListener.onP2pSendConfirmationRequested(); 641 } else if (mSendState == SEND_STATE_SENDING) { 642 mEventListener.onP2pResumeSend(); 643 sendNdefMessage(); 644 } else { 645 // Either nothing to send or canceled/complete, ignore 646 } 647 } 648 } 649 650 final class ConnectTask extends AsyncTask<Void, Void, Boolean> { 651 @Override 652 protected void onPostExecute(Boolean result) { 653 if (isCancelled()) { 654 if (DBG) Log.d(TAG, "ConnectTask was cancelled"); 655 return; 656 } 657 if (result) { 658 onLlcpServicesConnected(); 659 } else { 660 Log.e(TAG, "Could not connect required NFC transports"); 661 } 662 } 663 664 @Override 665 protected Boolean doInBackground(Void... params) { 666 boolean needsHandover = false; 667 boolean needsNdef = false; 668 boolean success = false; 669 HandoverClient handoverClient = null; 670 SnepClient snepClient = null; 671 NdefPushClient nppClient = null; 672 673 synchronized(P2pLinkManager.this) { 674 if (mUrisToSend != null) { 675 needsHandover = true; 676 } 677 678 if (mMessageToSend != null) { 679 needsNdef = true; 680 } 681 } 682 // We know either is requested - otherwise this task 683 // wouldn't have been started. 684 if (needsHandover) { 685 handoverClient = new HandoverClient(); 686 try { 687 handoverClient.connect(); 688 success = true; // Regardless of NDEF result 689 } catch (IOException e) { 690 handoverClient = null; 691 } 692 } 693 694 if (needsNdef || (needsHandover && handoverClient == null)) { 695 snepClient = new SnepClient(); 696 try { 697 snepClient.connect(); 698 success = true; 699 } catch (IOException e) { 700 snepClient = null; 701 } 702 703 if (!success) { 704 nppClient = new NdefPushClient(); 705 try { 706 nppClient.connect(); 707 success = true; 708 } catch (IOException e) { 709 nppClient = null; 710 } 711 } 712 } 713 714 synchronized (P2pLinkManager.this) { 715 if (isCancelled()) { 716 // Cancelled by onLlcpDeactivated on UI thread 717 if (handoverClient != null) { 718 handoverClient.close(); 719 } 720 if (snepClient != null) { 721 snepClient.close(); 722 } 723 if (nppClient != null) { 724 nppClient.close(); 725 } 726 return false; 727 } else { 728 // Once assigned, these are the responsibility of 729 // the code on the UI thread to release - typically 730 // through onLlcpDeactivated(). 731 mHandoverClient = handoverClient; 732 mSnepClient = snepClient; 733 mNdefPushClient = nppClient; 734 return success; 735 } 736 } 737 } 738 }; 739 740 final class SendTask extends AsyncTask<Void, Void, Void> { 741 NdefPushClient nppClient; 742 SnepClient snepClient; 743 HandoverClient handoverClient; 744 745 int doHandover(Uri[] uris, UserHandle userHandle) throws IOException { 746 NdefMessage response = null; 747 BeamManager beamManager = BeamManager.getInstance(); 748 749 if (beamManager.isBeamInProgress()) { 750 return HANDOVER_BUSY; 751 } 752 753 NdefMessage request = mHandoverDataParser.createHandoverRequestMessage(); 754 if (request != null) { 755 if (handoverClient != null) { 756 response = handoverClient.sendHandoverRequest(request); 757 } 758 if (response == null && snepClient != null) { 759 // Remote device may not support handover service, 760 // try the (deprecated) SNEP GET implementation 761 // for devices running Android 4.1 762 SnepMessage snepResponse = snepClient.get(request); 763 response = snepResponse.getNdefMessage(); 764 } 765 if (response == null) { 766 return HANDOVER_UNSUPPORTED; 767 } 768 } else { 769 return HANDOVER_UNSUPPORTED; 770 } 771 772 if (!beamManager.startBeamSend(mContext, 773 mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) { 774 return HANDOVER_BUSY; 775 } 776 777 return HANDOVER_SUCCESS; 778 } 779 780 int doSnepProtocol(NdefMessage msg) throws IOException { 781 if (msg != null) { 782 snepClient.put(msg); 783 return SNEP_SUCCESS; 784 } else { 785 return SNEP_FAILURE; 786 } 787 } 788 789 @Override 790 public Void doInBackground(Void... args) { 791 NdefMessage m; 792 Uri[] uris; 793 UserHandle userHandle; 794 boolean result = false; 795 796 synchronized (P2pLinkManager.this) { 797 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) { 798 return null; 799 } 800 m = mMessageToSend; 801 uris = mUrisToSend; 802 userHandle = mUserHandle; 803 snepClient = mSnepClient; 804 handoverClient = mHandoverClient; 805 nppClient = mNdefPushClient; 806 } 807 808 long time = SystemClock.elapsedRealtime(); 809 810 if (uris != null) { 811 if (DBG) Log.d(TAG, "Trying handover request"); 812 try { 813 int handoverResult = doHandover(uris, userHandle); 814 switch (handoverResult) { 815 case HANDOVER_SUCCESS: 816 result = true; 817 break; 818 case HANDOVER_FAILURE: 819 result = false; 820 break; 821 case HANDOVER_UNSUPPORTED: 822 result = false; 823 onHandoverUnsupported(); 824 break; 825 case HANDOVER_BUSY: 826 result = false; 827 onHandoverBusy(); 828 break; 829 } 830 } catch (IOException e) { 831 result = false; 832 } 833 } 834 835 if (!result && m != null && snepClient != null) { 836 if (DBG) Log.d(TAG, "Sending ndef via SNEP"); 837 try { 838 int snepResult = doSnepProtocol(m); 839 switch (snepResult) { 840 case SNEP_SUCCESS: 841 result = true; 842 break; 843 case SNEP_FAILURE: 844 result = false; 845 break; 846 default: 847 result = false; 848 } 849 } catch (IOException e) { 850 result = false; 851 } 852 } 853 854 if (!result && m != null && nppClient != null) { 855 result = nppClient.push(m); 856 } 857 858 time = SystemClock.elapsedRealtime() - time; 859 if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time); 860 if (result) { 861 onSendComplete(m, time); 862 } 863 864 return null; 865 } 866 }; 867 868 869 final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { 870 @Override 871 public void onHandoverRequestReceived() { 872 onReceiveHandover(); 873 } 874 875 @Override 876 public void onHandoverBusy() { 877 P2pLinkManager.this.onHandoverBusy(); 878 } 879 }; 880 881 final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { 882 @Override 883 public void onMessageReceived(NdefMessage msg) { 884 onReceiveComplete(msg); 885 } 886 }; 887 888 final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() { 889 @Override 890 public SnepMessage doPut(NdefMessage msg) { 891 onReceiveComplete(msg); 892 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 893 } 894 895 @Override 896 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 897 // The NFC Forum Default SNEP server is not allowed to respond to 898 // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, 899 // since Android 4.1 used the NFC Forum default server to 900 // implement connection handover, we will support this 901 // until we can deprecate it. 902 NdefMessage response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect; 903 if (response != null) { 904 onReceiveHandover(); 905 return SnepMessage.getSuccessResponse(response); 906 } else { 907 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 908 } 909 } 910 }; 911 912 void onReceiveHandover() { 913 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 914 } 915 916 void onReceiveComplete(NdefMessage msg) { 917 // Make callbacks on UI thread 918 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 919 } 920 921 @Override 922 public boolean handleMessage(Message msg) { 923 switch (msg.what) { 924 case MSG_START_ECHOSERVER: 925 synchronized (this) { 926 mEchoServer.start(); 927 break; 928 } 929 case MSG_STOP_ECHOSERVER: 930 synchronized (this) { 931 mEchoServer.stop(); 932 break; 933 } 934 case MSG_WAIT_FOR_LINK_TIMEOUT: 935 synchronized (this) { 936 // User wanted to send something but no link 937 // came up. Just cancel the send 938 mSendState = SEND_STATE_NOTHING_TO_SEND; 939 mEventListener.onP2pTimeoutWaitingForLink(); 940 } 941 break; 942 case MSG_DEBOUNCE_TIMEOUT: 943 synchronized (this) { 944 if (mLinkState != LINK_STATE_DEBOUNCE) { 945 break; 946 } 947 if (DBG) Log.d(TAG, "Debounce timeout"); 948 mLinkState = LINK_STATE_DOWN; 949 mSendState = SEND_STATE_NOTHING_TO_SEND; 950 mMessageToSend = null; 951 mUrisToSend = null; 952 if (DBG) Log.d(TAG, "onP2pOutOfRange()"); 953 mEventListener.onP2pOutOfRange(); 954 } 955 break; 956 case MSG_RECEIVE_HANDOVER: 957 // We're going to do a handover request 958 synchronized (this) { 959 if (mLinkState == LINK_STATE_DOWN) { 960 break; 961 } 962 if (mSendState == SEND_STATE_SENDING) { 963 cancelSendNdefMessage(); 964 } 965 mSendState = SEND_STATE_NOTHING_TO_SEND; 966 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 967 mEventListener.onP2pReceiveComplete(false); 968 } 969 break; 970 case MSG_RECEIVE_COMPLETE: 971 NdefMessage m = (NdefMessage) msg.obj; 972 synchronized (this) { 973 if (mLinkState == LINK_STATE_DOWN) { 974 break; 975 } 976 if (mSendState == SEND_STATE_SENDING) { 977 cancelSendNdefMessage(); 978 } 979 mSendState = SEND_STATE_NOTHING_TO_SEND; 980 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 981 mEventListener.onP2pReceiveComplete(true); 982 NfcService.getInstance().sendMockNdefTag(m); 983 } 984 break; 985 case MSG_HANDOVER_NOT_SUPPORTED: 986 synchronized (P2pLinkManager.this) { 987 mSendTask = null; 988 989 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 990 break; 991 } 992 mSendState = SEND_STATE_NOTHING_TO_SEND; 993 if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()"); 994 mEventListener.onP2pHandoverNotSupported(); 995 } 996 break; 997 case MSG_SEND_COMPLETE: 998 synchronized (P2pLinkManager.this) { 999 mSendTask = null; 1000 1001 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1002 break; 1003 } 1004 mSendState = SEND_STATE_COMPLETE; 1005 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 1006 if (DBG) Log.d(TAG, "onP2pSendComplete()"); 1007 mEventListener.onP2pSendComplete(); 1008 if (mCallbackNdef != null) { 1009 try { 1010 mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion); 1011 } catch (Exception e) { 1012 Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage()); 1013 } 1014 } 1015 } 1016 break; 1017 case MSG_HANDOVER_BUSY: 1018 synchronized (P2pLinkManager.this) { 1019 mSendTask = null; 1020 1021 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1022 break; 1023 } 1024 mSendState = SEND_STATE_NOTHING_TO_SEND; 1025 if (DBG) Log.d(TAG, "onP2pHandoverBusy()"); 1026 mEventListener.onP2pHandoverBusy(); 1027 } 1028 } 1029 return true; 1030 } 1031 1032 1033 @Override 1034 public void onP2pSendConfirmed() { 1035 onP2pSendConfirmed(true); 1036 } 1037 1038 private void onP2pSendConfirmed(boolean requireConfirmation) { 1039 if (DBG) Log.d(TAG, "onP2pSendConfirmed()"); 1040 synchronized (this) { 1041 if (mLinkState == LINK_STATE_DOWN || (requireConfirmation 1042 && mSendState != SEND_STATE_NEED_CONFIRMATION)) { 1043 return; 1044 } 1045 mSendState = SEND_STATE_SENDING; 1046 if (mLinkState == LINK_STATE_UP) { 1047 if (mLlcpServicesConnected) { 1048 sendNdefMessage(); 1049 } // else, will send messages when link comes up 1050 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1051 // Restart debounce timeout and tell user to tap again 1052 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CONFIRMED_DEBOUNCE_MS); 1053 mEventListener.onP2pSendDebounce(); 1054 } 1055 } 1056 } 1057 1058 1059 @Override 1060 public void onP2pCanceled() { 1061 synchronized (this) { 1062 mSendState = SEND_STATE_CANCELED; 1063 if (mLinkState == LINK_STATE_DOWN) { 1064 // If we were waiting for the link to come up, stop doing so 1065 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT); 1066 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1067 // We're in debounce state so link is down. Reschedule debounce 1068 // timeout to occur sooner, we don't want to wait any longer. 1069 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CANCELED_DEBOUNCE_MS); 1070 } else { 1071 // Link is up, nothing else to do but wait for link to go down 1072 } 1073 } 1074 } 1075 1076 void scheduleTimeoutLocked(int what, int timeout) { 1077 // Cancel any outstanding debounce timeouts. 1078 mHandler.removeMessages(what); 1079 mHandler.sendEmptyMessageDelayed(what, timeout); 1080 } 1081 1082 static String sendStateToString(int state) { 1083 switch (state) { 1084 case SEND_STATE_NOTHING_TO_SEND: 1085 return "SEND_STATE_NOTHING_TO_SEND"; 1086 case SEND_STATE_NEED_CONFIRMATION: 1087 return "SEND_STATE_NEED_CONFIRMATION"; 1088 case SEND_STATE_SENDING: 1089 return "SEND_STATE_SENDING"; 1090 case SEND_STATE_COMPLETE: 1091 return "SEND_STATE_COMPLETE"; 1092 case SEND_STATE_CANCELED: 1093 return "SEND_STATE_CANCELED"; 1094 default: 1095 return "<error>"; 1096 } 1097 } 1098 1099 static String linkStateToString(int state) { 1100 switch (state) { 1101 case LINK_STATE_DOWN: 1102 return "LINK_STATE_DOWN"; 1103 case LINK_STATE_DEBOUNCE: 1104 return "LINK_STATE_DEBOUNCE"; 1105 case LINK_STATE_UP: 1106 return "LINK_STATE_UP"; 1107 default: 1108 return "<error>"; 1109 } 1110 } 1111 1112 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1113 synchronized (this) { 1114 pw.println("mIsSendEnabled=" + mIsSendEnabled); 1115 pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled); 1116 pw.println("mLinkState=" + linkStateToString(mLinkState)); 1117 pw.println("mSendState=" + sendStateToString(mSendState)); 1118 1119 pw.println("mCallbackNdef=" + mCallbackNdef); 1120 pw.println("mMessageToSend=" + mMessageToSend); 1121 pw.println("mUrisToSend=" + mUrisToSend); 1122 } 1123 } 1124 } 1125