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