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