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