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