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