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