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