177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly/*
277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Copyright (C) 2011 The Android Open Source Project
377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly *
477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * you may not use this file except in compliance with the License.
677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * You may obtain a copy of the License at
777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly *
877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly *
1077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Unless required by applicable law or agreed to in writing, software
1177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
1277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * See the License for the specific language governing permissions and
1477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * limitations under the License.
1577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly */
1677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
1777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellypackage com.android.nfc;
1877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
19b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.content.Intent;
20b42756d47f39774a07654f68af27bf3cc2c41511Andres Moralesimport android.content.pm.UserInfo;
21b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
22b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamManager;
23b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamSendService;
24b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamTransferRecord;
25b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
265c452dad7b24f28223414ce5e953bfcab782570eAndres Moralesimport android.os.UserManager;
276f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenenimport com.android.nfc.echoserver.EchoServer;
28f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.handover.HandoverClient;
29b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.HandoverDataParser;
30f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.handover.HandoverServer;
3177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport com.android.nfc.ndefpush.NdefPushClient;
3277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport com.android.nfc.ndefpush.NdefPushServer;
3377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport com.android.nfc.snep.SnepClient;
3477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport com.android.nfc.snep.SnepMessage;
3577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport com.android.nfc.snep.SnepServer;
3677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
3777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.content.Context;
38416e2fc507d696486a127f932105b3b95519d0cbJeff Hamiltonimport android.content.SharedPreferences;
3977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.content.pm.ApplicationInfo;
4077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.content.pm.PackageManager;
4177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.content.pm.PackageManager.NameNotFoundException;
4277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.net.Uri;
43cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenenimport android.nfc.BeamShareData;
4431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenenimport android.nfc.IAppCallback;
4577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.nfc.NdefMessage;
4677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.nfc.NdefRecord;
47cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenenimport android.nfc.NfcAdapter;
4877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.os.AsyncTask;
4977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.os.Handler;
5077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.os.Message;
51416e2fc507d696486a127f932105b3b95519d0cbJeff Hamiltonimport android.os.SystemClock;
523859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenenimport android.os.UserHandle;
5377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport android.util.Log;
5477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport java.io.FileDescriptor;
5577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport java.io.IOException;
5677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyimport java.io.PrintWriter;
57893bc90a71883f8d2bfc82818abbf21c9745efdaElliott Hughesimport java.nio.charset.StandardCharsets;
58416e2fc507d696486a127f932105b3b95519d0cbJeff Hamiltonimport java.util.Arrays;
59c4ff3393f54403064b237349277cbf65f3277285Martijn Coenenimport java.util.List;
6077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
6177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly/**
6277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Interface to listen for P2P events.
6377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * All callbacks are made from the UI thread.
6477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly */
6577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellyinterface P2pEventListener {
6677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * Indicates the user has expressed an intent to share
689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * over NFC, but a remote device has not come into range
699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * yet. Prompt the user to NFC tap.
709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     */
719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onP2pNfcTapRequested();
729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    /**
749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * Indicates the user has expressed an intent to share over
759340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * NFC, but the link hasn't come up yet and we no longer
769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     * want to wait for it
779340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen     */
789340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onP2pTimeoutWaitingForLink();
799340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
809340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    /**
8177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Indicates a P2P device is in range.
8277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * <p>onP2pInRange() and onP2pOutOfRange() will always be called
8377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * alternately.
8477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
8577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void onP2pInRange();
8677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
8777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
8877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Called when a NDEF payload is prepared to send, and confirmation is
8977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * required. Call Callback.onP2pSendConfirmed() to make the confirmation.
9077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
9177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void onP2pSendConfirmationRequested();
9277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
9377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
948a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly     * Called to indicate a send was successful.
9577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
968a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly    public void onP2pSendComplete();
9777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
9877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
991a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     *
1001a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     * Called to indicate the link has broken while we were trying to send
1011a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     * a message. We'll start a debounce timer for the user to get the devices
1021a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     * back together. UI may show a hint to achieve that
1031a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     */
1041a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    public void onP2pSendDebounce();
1051a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
1061a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    /**
1071a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     * Called to indicate a link has come back up after being temporarily
1081a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     * broken, and sending is resuming
1091a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen     */
1101a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    public void onP2pResumeSend();
1111a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
1121a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    /**
113a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen     * Called to indicate the remote device does not support connection handover
114a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen     */
115a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    public void onP2pHandoverNotSupported();
116a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
117a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    /**
118aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales     * Called to indicate the device is busy with another handover transfer
119aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales     */
120aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    public void onP2pHandoverBusy();
121aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales
122aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    /**
12377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Called to indicate a receive was successful.
12477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
125d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    public void onP2pReceiveComplete(boolean playSound);
12677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
12777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
12877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Indicates the P2P device went out of range.
12977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
13077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void onP2pOutOfRange();
13177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
13277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public interface Callback {
13377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        public void onP2pSendConfirmed();
1349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        public void onP2pCanceled();
13577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
13677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly}
13777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
13877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly/**
13977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Manages sending and receiving NDEF message over LLCP link.
14077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * Does simple debouncing of the LLCP link - so that even if the link
14177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly * drops and returns the user does not know.
14277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly */
143d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Moralesclass P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
14477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final String TAG = "NfcP2pLinkManager";
14577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final boolean DBG = true;
14677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
147eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen    /** Include this constant as a meta-data entry in the manifest
148eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *  of an application to disable beaming the market/AAR link, like this:
149eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *  <pre>{@code
150eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *  <application ...>
151eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *      <meta-data android:name="android.nfc.disable_beam_default"
152eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *          android:value="true" />
153eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *  </application>
154eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     *  }</pre>
155eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen     */
156eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen    static final String DISABLE_BEAM_DEFAULT = "android.nfc.disable_beam_default";
157eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen
1586f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen    /** Enables the LLCP EchoServer, which can be used to test the android
1596f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen     * LLCP stack against nfcpy.
1606f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen     */
1616f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen    static final boolean ECHOSERVER_ENABLED = false;
1626f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen
16377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    // TODO dynamically assign SAP values
16477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int NDEFPUSH_SAP = 0x10;
165f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    static final int HANDOVER_SAP = 0x14;
16677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
1671a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final int LINK_SEND_PENDING_DEBOUNCE_MS = 3000;
1681a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000;
169ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen    static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 500;
1709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int LINK_SEND_CANCELED_DEBOUNCE_MS = 250;
1719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
1729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    // The amount of time we wait for the link to come up
1739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    // after a user has manually invoked Beam.
1749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int WAIT_FOR_LINK_TIMEOUT_MS = 10000;
1759340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
17677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int MSG_DEBOUNCE_TIMEOUT = 1;
17777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int MSG_RECEIVE_COMPLETE = 2;
178d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    static final int MSG_RECEIVE_HANDOVER = 3;
179d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    static final int MSG_SEND_COMPLETE = 4;
180d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    static final int MSG_START_ECHOSERVER = 5;
181d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    static final int MSG_STOP_ECHOSERVER = 6;
182a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    static final int MSG_HANDOVER_NOT_SUPPORTED = 7;
18357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_SHOW_CONFIRMATION_UI = 8;
1849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int MSG_WAIT_FOR_LINK_TIMEOUT = 9;
185aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    static final int MSG_HANDOVER_BUSY = 10;
18677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
18777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    // values for mLinkState
18877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int LINK_STATE_DOWN = 1;
189ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen    static final int LINK_STATE_UP = 2;
190ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen    static final int LINK_STATE_DEBOUNCE = 3;
19177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
19277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    // values for mSendState
19377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int SEND_STATE_NOTHING_TO_SEND = 1;
19477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static final int SEND_STATE_NEED_CONFIRMATION = 2;
1959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int SEND_STATE_PENDING = 3;
1969340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int SEND_STATE_SENDING = 4;
1979340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int SEND_STATE_COMPLETE = 5;
1989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int SEND_STATE_CANCELED = 6;
19977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
200a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    // return values for doSnepProtocol
201a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    static final int SNEP_SUCCESS = 0;
202a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    static final int SNEP_FAILURE = 1;
2033329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
2043329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    // return values for doHandover
2053329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    static final int HANDOVER_SUCCESS = 0;
2063329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    static final int HANDOVER_FAILURE = 1;
2073329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    static final int HANDOVER_UNSUPPORTED = 2;
208aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    static final int HANDOVER_BUSY = 3;
20977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
21077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final NdefPushServer mNdefPushServer;
21177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final SnepServer mDefaultSnepServer;
212f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    final HandoverServer mHandoverServer;
2136f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen    final EchoServer mEchoServer;
21477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final Context mContext;
21577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final P2pEventListener mEventListener;
21677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final Handler mHandler;
217b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    final HandoverDataParser mHandoverDataParser;
21834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    final ForegroundUtils mForegroundUtils;
21977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
220525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    final int mDefaultMiu;
221525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    final int mDefaultRwSize;
222525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
22377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    // Locked on NdefP2pManager.this
2243859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen    PackageManager mPackageManager;
22577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    int mLinkState;
22677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    int mSendState;  // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE
22777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    boolean mIsSendEnabled;
22877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    boolean mIsReceiveEnabled;
2293329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    NdefMessage mMessageToSend;  // not valid in SEND_STATE_NOTHING_TO_SEND
2303329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    Uri[] mUrisToSend;  // not valid in SEND_STATE_NOTHING_TO_SEND
231b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    UserHandle mUserHandle; // not valid in SEND_STATE_NOTHING_TO_SEND
232cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenen    int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND
23331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    IAppCallback mCallbackNdef;
23434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    int mNdefCallbackUid;
23577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    SendTask mSendTask;
236416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    SharedPreferences mPrefs;
2373329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    SnepClient mSnepClient;
2383329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    HandoverClient mHandoverClient;
2393329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    NdefPushClient mNdefPushClient;
2403329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    ConnectTask mConnectTask;
2413329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    boolean mLlcpServicesConnected;
24257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    long mLastLlcpActivationTime;
2432daeeee63456a515693980372908234e1fa14ba5Martijn Coenen    byte mPeerLlcpVersion;
24477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
245b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu,
246525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            int defaultRwSize) {
24777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
248525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
249b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mHandoverServer = new HandoverServer(context, HANDOVER_SAP, handoverDataParser, mHandoverCallback);
250f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
2516f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen        if (ECHOSERVER_ENABLED) {
2526f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            mEchoServer = new EchoServer();
2536f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen        } else {
2546f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            mEchoServer = null;
2556f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen        }
25677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mPackageManager = context.getPackageManager();
25777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mContext = context;
25877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mEventListener = new P2pEventManager(context, this);
25977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mHandler = new Handler(this);
26077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mLinkState = LINK_STATE_DOWN;
26177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mSendState = SEND_STATE_NOTHING_TO_SEND;
26277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mIsSendEnabled = false;
26377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mIsReceiveEnabled = false;
264416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton        mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE);
265b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mHandoverDataParser = handoverDataParser;
266525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDefaultMiu = defaultMiu;
267525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDefaultRwSize = defaultRwSize;
2683329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        mLlcpServicesConnected = false;
26934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        mNdefCallbackUid = -1;
27034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        mForegroundUtils = ForegroundUtils.getInstance();
27177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     }
27277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
27377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
27477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * May be called from any thread.
27577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Assumes that NFC is already on if any parameter is true.
27677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
27777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void enableDisable(boolean sendEnable, boolean receiveEnable) {
27877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
27977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            if (!mIsReceiveEnabled && receiveEnable) {
28077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                mDefaultSnepServer.start();
28177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                mNdefPushServer.start();
282f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                mHandoverServer.start();
2836f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                if (mEchoServer != null) {
2846f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    mHandler.sendEmptyMessage(MSG_START_ECHOSERVER);
2856f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                }
28677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            } else if (mIsReceiveEnabled && !receiveEnable) {
287a8aa07142ea0078d3ae4ae486e094e2f2f4ff732Evan Chu                if (DBG) Log.d(TAG, "enableDisable: llcp deactivate");
288a8aa07142ea0078d3ae4ae486e094e2f2f4ff732Evan Chu                onLlcpDeactivated ();
28977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                mDefaultSnepServer.stop();
29077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                mNdefPushServer.stop();
291f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                mHandoverServer.stop();
2926f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                if (mEchoServer != null) {
2936f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER);
2946f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                }
29577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
29677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mIsSendEnabled = sendEnable;
29777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mIsReceiveEnabled = receiveEnable;
29877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
29977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
30077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
30177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
3027a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen     * May be called from any thread.
3037a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen     * @return whether the LLCP link is in an active or debounce state
3047a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen     */
3057a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen    public boolean isLlcpActive() {
3067a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen        synchronized (this) {
3077a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen            return mLinkState != LINK_STATE_DOWN;
3087a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen        }
3097a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen    }
3107a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen
3117a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen    /**
312c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly     * Set NDEF callback for sending.
31377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * May be called from any thread.
314c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly     * NDEF callbacks may be set at any time (even if NFC is
31577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * currently off or P2P send is currently off). They will become
31677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * active as soon as P2P send is enabled.
31777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
31831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    public void setNdefCallback(IAppCallback callbackNdef, int callingUid) {
31977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
32077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mCallbackNdef = callbackNdef;
32134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            mNdefCallbackUid = callingUid;
32277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
32377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
32477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
3259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
3269340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onManualBeamInvoke(BeamShareData shareData) {
3279340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        synchronized (P2pLinkManager.this)    {
3289340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mLinkState != LINK_STATE_DOWN) {
3299340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                return;
3309340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
331c4ff3393f54403064b237349277cbf65f3277285Martijn Coenen            if (mForegroundUtils.getForegroundUids().contains(mNdefCallbackUid)) {
33234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                // Try to get data from the registered NDEF callback
33334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                prepareMessageToSend(false);
334794585174b5812f47c4fbc3cc34184f4379bdbb8Alex Chau            } else {
335794585174b5812f47c4fbc3cc34184f4379bdbb8Alex Chau                mMessageToSend = null;
336794585174b5812f47c4fbc3cc34184f4379bdbb8Alex Chau                mUrisToSend = null;
33734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            }
3389340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mMessageToSend == null && mUrisToSend == null && shareData != null) {
33934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                // No data from the NDEF callback, get data from ShareData
3409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                if (shareData.uris != null) {
3419340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mUrisToSend = shareData.uris;
3429340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                } else if (shareData.ndefMessage != null) {
3439340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mMessageToSend = shareData.ndefMessage;
3449340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
34595302c119feba7f50a5193861619346908a96164Andres Morales
34695302c119feba7f50a5193861619346908a96164Andres Morales                mUserHandle = shareData.userHandle;
3479340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
3489340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mMessageToSend != null ||
349b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                    (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
3509340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                mSendState = SEND_STATE_PENDING;
3519340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                mEventListener.onP2pNfcTapRequested();
3529340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                scheduleTimeoutLocked(MSG_WAIT_FOR_LINK_TIMEOUT, WAIT_FOR_LINK_TIMEOUT_MS);
3539340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
3549340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
3559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
3569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
35777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
35877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Must be called on UI Thread.
35977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
3602daeeee63456a515693980372908234e1fa14ba5Martijn Coenen    public void onLlcpActivated(byte peerLlcpVersion) {
36177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        Log.i(TAG, "LLCP activated");
36277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (P2pLinkManager.this) {
3636f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            if (mEchoServer != null) {
3646f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                mEchoServer.onLlcpActivated();
3656f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            }
36657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            mLastLlcpActivationTime = SystemClock.elapsedRealtime();
3672daeeee63456a515693980372908234e1fa14ba5Martijn Coenen            mPeerLlcpVersion = peerLlcpVersion;
36877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            switch (mLinkState) {
36977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_DOWN:
37077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "onP2pInRange()");
371ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    // Start taking a screenshot
37277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mEventListener.onP2pInRange();
373ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    mLinkState = LINK_STATE_UP;
374ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    // If we had a pending send (manual Beam invoke),
375ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    // mark it as sending
3769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    if (mSendState == SEND_STATE_PENDING) {
3779340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        mSendState = SEND_STATE_SENDING;
378ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                        mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT);
379ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                        // Immediately try to connect LLCP services
380ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                        connectLlcpServices();
3819340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    } else {
3829340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        mSendState = SEND_STATE_NOTHING_TO_SEND;
3839340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        prepareMessageToSend(true);
3849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        if (mMessageToSend != null ||
385b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                                (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) {
386ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                            // We have data to send, connect LLCP services
387ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                            connectLlcpServices();
3889340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                            if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) {
3899340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                                mSendState = SEND_STATE_SENDING;
3909340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                            } else {
3919340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                                mSendState = SEND_STATE_NEED_CONFIRMATION;
3929340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                            }
393cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenen                        }
39477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
39577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    break;
39677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_UP:
39777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()");
39877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    return;
39977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_DEBOUNCE:
400ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    // Immediately connect and try to send again
401ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    mLinkState = LINK_STATE_UP;
402ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    if (mSendState == SEND_STATE_SENDING ||
403ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                            mSendState == SEND_STATE_NEED_CONFIRMATION) {
404ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                        // If we have something to send still, connect LLCP
40557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                        connectLlcpServices();
40657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    }
40777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
40857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
40957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            }
41057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
41157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
41257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
41357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
41457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Must be called on UI Thread.
41557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
41657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived() {
41757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        synchronized (P2pLinkManager.this) {
41857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime;
41957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU");
42077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
42177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
42277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
423d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales    public void onUserSwitched(int userId) {
4243859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        // Update the cached package manager in case of user switch
4253859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        synchronized (P2pLinkManager.this) {
4263859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            try {
4273859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mPackageManager  = mContext.createPackageContextAsUser("android", 0,
428d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                        new UserHandle(userId)).getPackageManager();
4293859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } catch (NameNotFoundException e) {
4303859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                Log.e(TAG, "Failed to retrieve PackageManager for user");
4313859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            }
4323859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        }
4333859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen    }
4343859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen
4359340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    void prepareMessageToSend(boolean generatePlayLink) {
43677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (P2pLinkManager.this) {
43734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            mMessageToSend = null;
43834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            mUrisToSend = null;
43977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            if (!mIsSendEnabled) {
44077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return;
44177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
44277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
443c4ff3393f54403064b237349277cbf65f3277285Martijn Coenen            List<Integer> foregroundUids = mForegroundUtils.getForegroundUids();
444c4ff3393f54403064b237349277cbf65f3277285Martijn Coenen            if (foregroundUids.isEmpty()) {
44534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                Log.e(TAG, "Could not determine foreground UID.");
4463859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                return;
4473859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            }
4483859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen
4495697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau            if (isBeamDisabled(foregroundUids.get(0))) {
4505697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau                if (DBG) Log.d(TAG, "Beam is disabled by policy.");
4515697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau                return;
4525697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau            }
4535697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau
454fb42b9f2d905015730f2e12772ed9a2a610a3957Isaac Levy            if (mCallbackNdef != null) {
455c4ff3393f54403064b237349277cbf65f3277285Martijn Coenen                if (foregroundUids.contains(mNdefCallbackUid)) {
4563859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    try {
4572daeeee63456a515693980372908234e1fa14ba5Martijn Coenen                        BeamShareData shareData = mCallbackNdef.createBeamShareData(mPeerLlcpVersion);
458cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenen                        mMessageToSend = shareData.ndefMessage;
459cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenen                        mUrisToSend = shareData.uris;
460b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                        mUserHandle = shareData.userHandle;
461cbe27470ef7e67324b9e8cbc32c25088d82e2a86Martijn Coenen                        mSendFlags = shareData.flags;
4623859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                        return;
4635bacd361e693472b7d54d31fe0d23b9d22851988Martijn Coenen                    } catch (Exception e) {
46495302c119feba7f50a5193861619346908a96164Andres Morales                        Log.e(TAG, "Failed NDEF callback: ", e);
4653859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    }
466eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen                } else {
4673859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    // This is not necessarily an error - we no longer unset callbacks from
4683859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    // the app process itself (to prevent IPC calls on every pause).
4693859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    // Hence it may simply be a stale callback.
4703859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                    if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground.");
471eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen                }
4723859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            }
4733859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen
4743859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            // fall back to default NDEF for the foreground activity, unless the
4753859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            // application disabled this explicitly in their manifest.
476c4ff3393f54403064b237349277cbf65f3277285Martijn Coenen            String[] pkgs = mPackageManager.getPackagesForUid(foregroundUids.get(0));
47734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            if (pkgs != null && pkgs.length >= 1) {
4785697d20844cf52e71aa9125ac1fbfc9436bd8ed5Alex Chau                if (!generatePlayLink || beamDefaultDisabled(pkgs[0])) {
47934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                    if (DBG) Log.d(TAG, "Disabling default Beam behavior");
48034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                    mMessageToSend = null;
48134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                    mUrisToSend = null;
48234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                } else {
48334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                    mMessageToSend = createDefaultNdef(pkgs[0]);
48434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                    mUrisToSend = null;
485e15820b67fea55fbe84103ab38e2adc22fab99d8Peng Sun                    mSendFlags = 0;
48634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen                }
487eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            }
4883859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen
48943f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly            if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend);
49083558889207858d7ce8500f9fce8a707a86b495eMartijn Coenen            if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend);
49177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
49277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
49377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
49465860bb589c5802ffadb14540670408d6c8dfaa9Benjamin Franz    private boolean isBeamDisabled(int uid) {
4955c452dad7b24f28223414ce5e953bfcab782570eAndres Morales        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
496b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales        UserInfo userInfo = userManager.getUserInfo(UserHandle.getUserId(uid));
49765860bb589c5802ffadb14540670408d6c8dfaa9Benjamin Franz        return userManager.hasUserRestriction(
498b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales                        UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle());
499b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales
5005c452dad7b24f28223414ce5e953bfcab782570eAndres Morales    }
5015c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
502eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen    boolean beamDefaultDisabled(String pkgName) {
503eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen        try {
504eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName,
505eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen                    PackageManager.GET_META_DATA);
506eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            if (ai == null || ai.metaData == null) {
507eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen                return false;
508eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            }
509eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT);
510eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen        } catch (NameNotFoundException e) {
511eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen            return false;
51277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
513eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen    }
514eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen
515eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen    NdefMessage createDefaultNdef(String pkgName) {
516eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen        NdefRecord appUri = NdefRecord.createUri(Uri.parse(
517eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen                "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam"));
518eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen        NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName);
519eec585407f2cfc47814f572a1e2a0f7d56b41451Martijn Coenen        return new NdefMessage(new NdefRecord[] { appUri, appRecord });
52077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
52177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
5223329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    void disconnectLlcpServices() {
5233329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        synchronized (this) {
5243329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mConnectTask != null) {
5253329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mConnectTask.cancel(true);
5263329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mConnectTask = null;
5273329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
5283329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            // Close any already connected LLCP clients
5293329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mNdefPushClient != null) {
5303329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mNdefPushClient.close();
5313329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mNdefPushClient = null;
5323329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
5333329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mSnepClient != null) {
5343329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mSnepClient.close();
5353329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mSnepClient = null;
5363329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
5373329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mHandoverClient != null) {
5383329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mHandoverClient.close();
5393329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                mHandoverClient = null;
5403329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
5413329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            mLlcpServicesConnected = false;
5423329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
5433329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    }
5443329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
54577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    /**
54677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     * Must be called on UI Thread.
54777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     */
54877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void onLlcpDeactivated() {
54977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        Log.i(TAG, "LLCP deactivated.");
55077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
5516f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            if (mEchoServer != null) {
5526f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                mEchoServer.onLlcpDeactivated();
5536f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            }
5546f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen
55577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            switch (mLinkState) {
55677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_DOWN:
55777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_DEBOUNCE:
55877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    Log.i(TAG, "Duplicate onLlcpDectivated()");
55977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    break;
56077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                case LINK_STATE_UP:
56177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    // Debounce
56277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mLinkState = LINK_STATE_DEBOUNCE;
5631a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    int debounceTimeout = 0;
5641a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    switch (mSendState) {
5651a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                        case SEND_STATE_NOTHING_TO_SEND:
5661a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            debounceTimeout = 0;
5671a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            break;
5681a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                        case SEND_STATE_NEED_CONFIRMATION:
5691a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS;
5701a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            break;
5711a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                        case SEND_STATE_SENDING:
5721a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS;
5731a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            break;
5749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        case SEND_STATE_COMPLETE:
5751a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS;
5761a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                            break;
5779340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                        case SEND_STATE_CANCELED:
5789340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                            debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS;
5791a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    }
5809340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout);
5811a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    if (mSendState == SEND_STATE_SENDING) {
5821a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                        Log.e(TAG, "onP2pSendDebounce()");
5831a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                        mEventListener.onP2pSendDebounce();
5841a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    }
58577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    cancelSendNdefMessage();
5863329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    disconnectLlcpServices();
58777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    break;
58877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
58977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly         }
59077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly     }
59177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
592a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    void onHandoverUnsupported() {
593a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED);
594a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    }
595a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
596aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    void onHandoverBusy() {
597aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales        mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY);
598aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales    }
599aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales
600416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    void onSendComplete(NdefMessage msg, long elapsedRealtime) {
60177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        // Make callbacks on UI thread
6028a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly        mHandler.sendEmptyMessage(MSG_SEND_COMPLETE);
60377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
60477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
60577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    void sendNdefMessage() {
60677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
60777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            cancelSendNdefMessage();
60877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mSendTask = new SendTask();
60977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mSendTask.execute();
61077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
61177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
61277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
61377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    void cancelSendNdefMessage() {
61477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (P2pLinkManager.this) {
61577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            if (mSendTask != null) {
61677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                mSendTask.cancel(true);
61777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
61877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
61977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
62077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
6213329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    void connectLlcpServices() {
6223329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        synchronized (P2pLinkManager.this) {
6233329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mConnectTask != null) {
6243329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                Log.e(TAG, "Still had a reference to mConnectTask!");
6253329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6263329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            mConnectTask = new ConnectTask();
6273329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            mConnectTask.execute();
6283329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
6293329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    }
6303329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
6313329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    // Must be called on UI-thread
6323329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    void onLlcpServicesConnected() {
6333329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        if (DBG) Log.d(TAG, "onLlcpServicesConnected");
6343329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        synchronized (P2pLinkManager.this) {
6353329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (mLinkState != LINK_STATE_UP) {
6363329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                return;
6373329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6383329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            mLlcpServicesConnected = true;
639ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen            if (mSendState == SEND_STATE_NEED_CONFIRMATION) {
640ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()");
641ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                mEventListener.onP2pSendConfirmationRequested();
642ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen            } else if (mSendState == SEND_STATE_SENDING) {
6431a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                mEventListener.onP2pResumeSend();
6443329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                sendNdefMessage();
6453329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            } else {
646ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                // Either nothing to send or canceled/complete, ignore
6473329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6483329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
6493329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    }
6503329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
6513329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    final class ConnectTask extends AsyncTask<Void, Void, Boolean> {
6523329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        @Override
6533329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        protected void onPostExecute(Boolean result)  {
6543329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (isCancelled()) {
6553329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (DBG) Log.d(TAG, "ConnectTask was cancelled");
6563329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                return;
6573329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6583329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (result) {
6593329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                onLlcpServicesConnected();
6603329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            } else {
6613329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                Log.e(TAG, "Could not connect required NFC transports");
6623329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6633329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
6643329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
6653329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        @Override
6663329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        protected Boolean doInBackground(Void... params) {
6673329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            boolean needsHandover = false;
6683329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            boolean needsNdef = false;
6693329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            boolean success = false;
6703329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            HandoverClient handoverClient = null;
6713329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            SnepClient snepClient = null;
6723329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            NdefPushClient nppClient = null;
6733329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
6743329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            synchronized(P2pLinkManager.this) {
6753329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (mUrisToSend != null) {
6763329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    needsHandover = true;
6773329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
6783329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
6793329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (mMessageToSend != null) {
6803329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    needsNdef = true;
6813329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
6823329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6833329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            // We know either is requested - otherwise this task
6843329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            // wouldn't have been started.
6853329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (needsHandover) {
6863329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                handoverClient = new HandoverClient();
6873329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                try {
6883329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    handoverClient.connect();
6893329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    success = true; // Regardless of NDEF result
6903329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                } catch (IOException e) {
6913329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    handoverClient = null;
6923329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
6933329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
6943329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
695d72b205b870f4bccb33d466a0b4f704aca8d060aMartijn Coenen            if (needsNdef || (needsHandover && handoverClient == null)) {
6963329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                snepClient = new SnepClient();
6973329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                try {
6983329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    snepClient.connect();
6993329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    success = true;
7003329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                } catch (IOException e) {
7013329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    snepClient = null;
7023329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7033329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
7043329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (!success) {
7053329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    nppClient = new NdefPushClient();
7063329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    try {
7073329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        nppClient.connect();
7083329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        success = true;
7093329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    } catch (IOException e) {
7103329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        nppClient = null;
7113329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
7123329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7133329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
7143329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
7153329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            synchronized (P2pLinkManager.this) {
7163329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (isCancelled()) {
7173329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // Cancelled by onLlcpDeactivated on UI thread
7183329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    if (handoverClient != null) {
7193329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        handoverClient.close();
7203329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
7213329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    if (snepClient != null) {
7223329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        snepClient.close();
7233329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
7243329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    if (nppClient != null) {
7253329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        nppClient.close();
7263329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
7273329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    return false;
7283329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                } else {
7293329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // Once assigned, these are the responsibility of
7303329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // the code on the UI thread to release - typically
7313329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // through onLlcpDeactivated().
7323329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    mHandoverClient = handoverClient;
7333329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    mSnepClient = snepClient;
7343329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    mNdefPushClient = nppClient;
7353329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    return success;
7363329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7373329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
7383329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
7393329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    };
7403329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
74177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final class SendTask extends AsyncTask<Void, Void, Void> {
7423329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        NdefPushClient nppClient;
7433329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        SnepClient snepClient;
7443329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        HandoverClient handoverClient;
7453329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
746b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        int doHandover(Uri[] uris, UserHandle userHandle) throws IOException {
7473329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            NdefMessage response = null;
748b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            BeamManager beamManager = BeamManager.getInstance();
749b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
750b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            if (beamManager.isBeamInProgress()) {
751aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                return HANDOVER_BUSY;
752b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            }
753b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
754b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            NdefMessage request = mHandoverDataParser.createHandoverRequestMessage();
7553329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (request != null) {
7563329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (handoverClient != null) {
7573329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    response = handoverClient.sendHandoverRequest(request);
7583329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7593329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (response == null && snepClient != null) {
7603329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // Remote device may not support handover service,
7613329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // try the (deprecated) SNEP GET implementation
7623329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    // for devices running Android 4.1
7633329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    SnepMessage snepResponse = snepClient.get(request);
7643329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    response = snepResponse.getNdefMessage();
7653329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7663329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (response == null) {
76773c03d85bfdfc8c4e1255ede5231991bce5e575aRuchi Kandoi                    if (snepClient != null)
76873c03d85bfdfc8c4e1255ede5231991bce5e575aRuchi Kandoi                        return HANDOVER_UNSUPPORTED;
76973c03d85bfdfc8c4e1255ede5231991bce5e575aRuchi Kandoi                    else
77073c03d85bfdfc8c4e1255ede5231991bce5e575aRuchi Kandoi                        return HANDOVER_FAILURE;
7713329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                }
7723329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            } else {
7733329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                return HANDOVER_UNSUPPORTED;
7743329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
775b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
776aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales            if (!beamManager.startBeamSend(mContext,
777b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                    mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) {
778aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                return HANDOVER_BUSY;
779b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            }
780b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
781aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales            return HANDOVER_SUCCESS;
7823329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
7833329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
7843329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        int doSnepProtocol(NdefMessage msg) throws IOException {
7853329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (msg != null) {
7863329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                snepClient.put(msg);
7873329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                return SNEP_SUCCESS;
7883329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            } else {
7893329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                return SNEP_FAILURE;
7903329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
7913329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen        }
7923329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen
79377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        @Override
79477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        public Void doInBackground(Void... args) {
79577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            NdefMessage m;
79683558889207858d7ce8500f9fce8a707a86b495eMartijn Coenen            Uri[] uris;
797b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            UserHandle userHandle;
7983329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            boolean result = false;
79977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
80077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            synchronized (P2pLinkManager.this) {
80177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) {
80277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    return null;
80377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                }
80477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                m = mMessageToSend;
80583558889207858d7ce8500f9fce8a707a86b495eMartijn Coenen                uris = mUrisToSend;
806b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                userHandle = mUserHandle;
8073329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                snepClient = mSnepClient;
8083329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                handoverClient = mHandoverClient;
8093329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                nppClient = mNdefPushClient;
81077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
81177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
812416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton            long time = SystemClock.elapsedRealtime();
81343f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly
8143329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (uris != null) {
8153329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (DBG) Log.d(TAG, "Trying handover request");
8163329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                try {
817b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                    int handoverResult = doHandover(uris, userHandle);
8183329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    switch (handoverResult) {
8193329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        case HANDOVER_SUCCESS:
8203329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = true;
8213329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            break;
8223329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        case HANDOVER_FAILURE:
8233329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = false;
8243329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            break;
8253329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        case HANDOVER_UNSUPPORTED:
8263329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = false;
8273329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            onHandoverUnsupported();
8283329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            break;
829aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                        case HANDOVER_BUSY:
830aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                            result = false;
831aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                            onHandoverBusy();
832aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                            break;
8333329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
8343329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                } catch (IOException e) {
8353329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    result = false;
83677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                }
8373329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
83877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
8393329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (!result && m != null && snepClient != null) {
8403329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                if (DBG) Log.d(TAG, "Sending ndef via SNEP");
8413329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                try {
8423329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    int snepResult = doSnepProtocol(m);
8433329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    switch (snepResult) {
8443329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        case SNEP_SUCCESS:
8453329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = true;
8463329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            break;
8473329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        case SNEP_FAILURE:
8483329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = false;
8493329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            break;
8503329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                        default:
8513329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                            result = false;
8523329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                    }
8533329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                } catch (IOException e) {
8540f2b555fe51f3d8a828cf61d269b8be6eecbf68bMartijn Coenen                    result = false;
8550f2b555fe51f3d8a828cf61d269b8be6eecbf68bMartijn Coenen                }
85677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
857416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton
8583329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (!result && m != null && nppClient != null) {
8593329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen                result = nppClient.push(m);
8603329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            }
861416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton
8623329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            time = SystemClock.elapsedRealtime() - time;
8633329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time);
8648a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly            if (result) {
865416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton                onSendComplete(m, time);
8668a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly            }
86777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
8683329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen            return null;
86977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
8703329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen    };
87177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
87277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
873f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() {
874f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        @Override
875f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        public void onHandoverRequestReceived() {
876f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            onReceiveHandover();
877f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
878aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales
879aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales        @Override
880aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales        public void onHandoverBusy() {
8813ac6710f5a6cf7a9948046abd71f732eebe770b9Satoshi Fujita            P2pLinkManager.this.onHandoverBusy();
882aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales        }
883f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    };
884f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
88577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() {
88677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        @Override
88777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        public void onMessageReceived(NdefMessage msg) {
88877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            onReceiveComplete(msg);
88977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
89077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    };
89177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
89277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() {
89377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        @Override
89477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        public SnepMessage doPut(NdefMessage msg) {
89577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            onReceiveComplete(msg);
89677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS);
89777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
89877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
89977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        @Override
90077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        public SnepMessage doGet(int acceptableLength, NdefMessage msg) {
901f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            // The NFC Forum Default SNEP server is not allowed to respond to
902f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            // SNEP GET requests - see SNEP 1.0 TS section 6.1. However,
903f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            // since Android 4.1 used the NFC Forum default server to
904f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            // implement connection handover, we will support this
905f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            // until we can deprecate it.
906b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            NdefMessage response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect;
90743f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly            if (response != null) {
908d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                onReceiveHandover();
90943f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly                return SnepMessage.getSuccessResponse(response);
91043f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly            } else {
911f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED);
91243f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly            }
91377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
91477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    };
91577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
916d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    void onReceiveHandover() {
917d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen        mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget();
918d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen    }
919d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen
92077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    void onReceiveComplete(NdefMessage msg) {
92177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        // Make callbacks on UI thread
92277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget();
92377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
92477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
92577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    @Override
92677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public boolean handleMessage(Message msg) {
92777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        switch (msg.what) {
9286f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            case MSG_START_ECHOSERVER:
9296f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                synchronized (this) {
9306f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    mEchoServer.start();
9316f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    break;
9326f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                }
9336f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen            case MSG_STOP_ECHOSERVER:
9346f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                synchronized (this) {
9356f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    mEchoServer.stop();
9366f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                    break;
9376f0e3b8e1de5137077127bf3144effa2016c27c6Martijn Coenen                }
9389340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case MSG_WAIT_FOR_LINK_TIMEOUT:
9399340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                synchronized (this) {
9409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    // User wanted to send something but no link
9419340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    // came up. Just cancel the send
9429340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mSendState = SEND_STATE_NOTHING_TO_SEND;
9439340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mEventListener.onP2pTimeoutWaitingForLink();
9449340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
9459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                break;
94677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case MSG_DEBOUNCE_TIMEOUT:
94777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                synchronized (this) {
94877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (mLinkState != LINK_STATE_DEBOUNCE) {
94977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        break;
95077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
95177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "Debounce timeout");
95277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mLinkState = LINK_STATE_DOWN;
95377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mSendState = SEND_STATE_NOTHING_TO_SEND;
95477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mMessageToSend = null;
95583558889207858d7ce8500f9fce8a707a86b495eMartijn Coenen                    mUrisToSend = null;
95677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "onP2pOutOfRange()");
95777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mEventListener.onP2pOutOfRange();
95877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                }
95977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                break;
960d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen            case MSG_RECEIVE_HANDOVER:
961d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                // We're going to do a handover request
962d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                synchronized (this) {
963d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    if (mLinkState == LINK_STATE_DOWN) {
964d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                        break;
965d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    }
966d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    if (mSendState == SEND_STATE_SENDING) {
967d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                        cancelSendNdefMessage();
968d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    }
969d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    mSendState = SEND_STATE_NOTHING_TO_SEND;
970d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    if (DBG) Log.d(TAG, "onP2pReceiveComplete()");
971d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    mEventListener.onP2pReceiveComplete(false);
972d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                }
973d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                break;
97477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case MSG_RECEIVE_COMPLETE:
97577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                NdefMessage m = (NdefMessage) msg.obj;
97677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                synchronized (this) {
97777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (mLinkState == LINK_STATE_DOWN) {
97877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        break;
97977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
98077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (mSendState == SEND_STATE_SENDING) {
98177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        cancelSendNdefMessage();
98277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
98377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mSendState = SEND_STATE_NOTHING_TO_SEND;
98477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "onP2pReceiveComplete()");
985d82d9db81f30ccecd29a0531e6db9b49c9c2cd95Martijn Coenen                    mEventListener.onP2pReceiveComplete(true);
98677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    NfcService.getInstance().sendMockNdefTag(m);
98777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                }
98877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                break;
989a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen            case MSG_HANDOVER_NOT_SUPPORTED:
990a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                synchronized (P2pLinkManager.this) {
991a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    mSendTask = null;
992a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
993a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
994a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                        break;
995a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    }
996a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    mSendState = SEND_STATE_NOTHING_TO_SEND;
997a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()");
998a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                    mEventListener.onP2pHandoverNotSupported();
999a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                }
1000a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen                break;
100177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case MSG_SEND_COMPLETE:
100277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                synchronized (P2pLinkManager.this) {
100377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mSendTask = null;
100477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
100577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
100677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        break;
100777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
10089340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mSendState = SEND_STATE_COMPLETE;
10091a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                    mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT);
101077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (DBG) Log.d(TAG, "onP2pSendComplete()");
10118a558ba19be56e71e6c2015dea862d150e6d07cbNick Pelly                    mEventListener.onP2pSendComplete();
101277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    if (mCallbackNdef != null) {
101377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        try {
10142daeeee63456a515693980372908234e1fa14ba5Martijn Coenen                            mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion);
10155bacd361e693472b7d54d31fe0d23b9d22851988Martijn Coenen                        } catch (Exception e) {
10165bacd361e693472b7d54d31fe0d23b9d22851988Martijn Coenen                            Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage());
10175bacd361e693472b7d54d31fe0d23b9d22851988Martijn Coenen                        }
101877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    }
101977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                }
102077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                break;
1021aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales            case MSG_HANDOVER_BUSY:
1022aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                synchronized (P2pLinkManager.this) {
1023aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    mSendTask = null;
1024aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales
1025aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) {
1026aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                        break;
1027aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    }
1028aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    mSendState = SEND_STATE_NOTHING_TO_SEND;
1029aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    if (DBG) Log.d(TAG, "onP2pHandoverBusy()");
1030aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                    mEventListener.onP2pHandoverBusy();
1031aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales                }
103277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
103377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        return true;
103477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
103577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
1036416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton
103777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    @Override
103877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public void onP2pSendConfirmed() {
1039cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier        onP2pSendConfirmed(true);
1040cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier    }
1041cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier
1042cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier    private void onP2pSendConfirmed(boolean requireConfirmation) {
104377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        if (DBG) Log.d(TAG, "onP2pSendConfirmed()");
104477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
1045cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier            if (mLinkState == LINK_STATE_DOWN || (requireConfirmation
1046cf4ef456bbf2c10f674b291ef7960af8b6bf6efaEmily Bernier                    && mSendState != SEND_STATE_NEED_CONFIRMATION)) {
104777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return;
104877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
104977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mSendState = SEND_STATE_SENDING;
1050ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen            if (mLinkState == LINK_STATE_UP) {
1051ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                if (mLlcpServicesConnected) {
1052ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                    sendNdefMessage();
1053ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                } // else, will send messages when link comes up
10541a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            } else if (mLinkState == LINK_STATE_DEBOUNCE) {
10559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                // Restart debounce timeout and tell user to tap again
10569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CONFIRMED_DEBOUNCE_MS);
10571a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen                mEventListener.onP2pSendDebounce();
105877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            }
105977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
106077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
106177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
10629340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
10639340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
10649340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onP2pCanceled() {
10659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        synchronized (this) {
10669340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            mSendState = SEND_STATE_CANCELED;
10679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mLinkState == LINK_STATE_DOWN) {
10689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                // If we were waiting for the link to come up, stop doing so
10699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT);
10709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else if (mLinkState == LINK_STATE_DEBOUNCE) {
10719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                // We're in debounce state so link is down. Reschedule debounce
10729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                // timeout to occur sooner, we don't want to wait any longer.
10739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CANCELED_DEBOUNCE_MS);
10749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else {
10759340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                // Link is up, nothing else to do but wait for link to go down
10769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
10779340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
10789340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
10799340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
10809340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    void scheduleTimeoutLocked(int what, int timeout) {
10819340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        // Cancel any outstanding debounce timeouts.
10829340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mHandler.removeMessages(what);
10839340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mHandler.sendEmptyMessageDelayed(what, timeout);
10849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
10859340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
108677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static String sendStateToString(int state) {
108777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        switch (state) {
108877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case SEND_STATE_NOTHING_TO_SEND:
108977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "SEND_STATE_NOTHING_TO_SEND";
109077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case SEND_STATE_NEED_CONFIRMATION:
109177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "SEND_STATE_NEED_CONFIRMATION";
109277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case SEND_STATE_SENDING:
109377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "SEND_STATE_SENDING";
10949340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case SEND_STATE_COMPLETE:
10959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                return "SEND_STATE_COMPLETE";
10969340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case SEND_STATE_CANCELED:
10979340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                return "SEND_STATE_CANCELED";
109877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            default:
109977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "<error>";
110077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
110177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
110277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
110377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    static String linkStateToString(int state) {
110477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        switch (state) {
110577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case LINK_STATE_DOWN:
110677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "LINK_STATE_DOWN";
110777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case LINK_STATE_DEBOUNCE:
110877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "LINK_STATE_DEBOUNCE";
110977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            case LINK_STATE_UP:
111077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "LINK_STATE_UP";
111177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            default:
111277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                return "<error>";
111377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
111477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
111577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
111677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
111777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        synchronized (this) {
111877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mIsSendEnabled=" + mIsSendEnabled);
111977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled);
112077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mLinkState=" + linkStateToString(mLinkState));
112177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mSendState=" + sendStateToString(mSendState));
112277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly
112377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mCallbackNdef=" + mCallbackNdef);
112477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            pw.println("mMessageToSend=" + mMessageToSend);
112583558889207858d7ce8500f9fce8a707a86b495eMartijn Coenen            pw.println("mUrisToSend=" + mUrisToSend);
112677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        }
112777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    }
112877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly}
1129