1b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen/*
2b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * Copyright (C) 2011 The Android Open Source Project
3b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen *
4b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
5b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * you may not use this file except in compliance with the License.
6b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * You may obtain a copy of the License at
7b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen *
8b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
9b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen *
10b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * Unless required by applicable law or agreed to in writing, software
11b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
12b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * See the License for the specific language governing permissions and
14b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen * limitations under the License.
15b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen */
16b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
17b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenenpackage com.android.browser;
18b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
19b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenenimport android.app.Activity;
20b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenenimport android.nfc.NdefMessage;
21b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenenimport android.nfc.NdefRecord;
22b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenenimport android.nfc.NfcAdapter;
23b5fd1162998b37b47aceff431992f484e422d03fNick Pellyimport android.nfc.NfcEvent;
246b6a3bf89303c7ef84910b28d59523d6441364beBen Murdochimport android.os.Handler;
256b6a3bf89303c7ef84910b28d59523d6441364beBen Murdochimport android.os.Message;
268e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pellyimport android.util.Log;
276b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch
286b6a3bf89303c7ef84910b28d59523d6441364beBen Murdochimport java.util.concurrent.CountDownLatch;
29b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
30b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen/** This class implements sharing the URL of the currently
31b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen  * shown browser page over NFC. Sharing is only active
32b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen  * when the activity is in the foreground and resumed.
33b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen  * Incognito tabs will not be shared over NFC.
34b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen  */
35b5fd1162998b37b47aceff431992f484e422d03fNick Pellypublic class NfcHandler implements NfcAdapter.CreateNdefMessageCallback {
368e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly    static final String TAG = "BrowserNfcHandler";
37b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    static final int GET_PRIVATE_BROWSING_STATE_MSG = 100;
38b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
39b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    final Controller mController;
40eee2126458da109b65bbed42904c6c407872c3afMartijn Coenen
41b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    Tab mCurrentTab;
42b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    boolean mIsPrivate;
43b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    CountDownLatch mPrivateBrowsingSignal;
44b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
45b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    public static void register(Activity activity, Controller controller) {
46b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(activity.getApplicationContext());
47b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        if (adapter == null) {
48b5fd1162998b37b47aceff431992f484e422d03fNick Pelly            return;  // NFC not available on this device
49b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen        }
50015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        NfcHandler handler = null;
51015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        if (controller != null) {
52015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch            handler = new NfcHandler(controller);
53015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        }
54015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch
55015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        adapter.setNdefPushMessageCallback(handler, activity);
56015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch    }
57015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch
58015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch    public static void unregister(Activity activity) {
59015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        // Passing a null controller causes us to disable
60015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        // the callback and release the ref to out activity.
61015e1e3145ac284aa5879c973f9d2381c8cd48feBen Murdoch        register(activity, null);
62b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen    }
63b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
64b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    public NfcHandler(Controller controller) {
65b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        mController = controller;
66b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen    }
67b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen
68b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    final Handler mHandler = new Handler() {
69b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        @Override
70b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        public void handleMessage(Message msg) {
71b5fd1162998b37b47aceff431992f484e422d03fNick Pelly            if (msg.what == GET_PRIVATE_BROWSING_STATE_MSG) {
72b5fd1162998b37b47aceff431992f484e422d03fNick Pelly                mIsPrivate = mCurrentTab.getWebView().isPrivateBrowsingEnabled();
73b5fd1162998b37b47aceff431992f484e422d03fNick Pelly                mPrivateBrowsingSignal.countDown();
74b5fd1162998b37b47aceff431992f484e422d03fNick Pelly            }
75b5fd1162998b37b47aceff431992f484e422d03fNick Pelly        }
76b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    };
77b5fd1162998b37b47aceff431992f484e422d03fNick Pelly
78b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen    @Override
79b5fd1162998b37b47aceff431992f484e422d03fNick Pelly    public NdefMessage createNdefMessage(NfcEvent event) {
806b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        mCurrentTab = mController.getCurrentTab();
816b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        if ((mCurrentTab != null) && (mCurrentTab.getWebView() != null)) {
826b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            // We can only read the WebView state on the UI thread, so post
836b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            // a message and wait.
846b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            mPrivateBrowsingSignal = new CountDownLatch(1);
856b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            mHandler.sendMessage(mHandler.obtainMessage(GET_PRIVATE_BROWSING_STATE_MSG));
866b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            try {
876b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch                mPrivateBrowsingSignal.await();
886b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            } catch (InterruptedException e) {
896b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch                return null;
906b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            }
916b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        }
926b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch
936b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        if ((mCurrentTab == null) || mIsPrivate) {
946b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch            return null;
956b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        }
966b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch
976b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        String currentUrl = mCurrentTab.getUrl();
986b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        if (currentUrl != null) {
998e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly            try {
1008e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly                return new NdefMessage(NdefRecord.createUri(currentUrl));
1018e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly            } catch (IllegalArgumentException e) {
1028e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly                Log.e(TAG, "IllegalArgumentException creating URI NdefRecord", e);
1038e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly                return null;
1048e201435ca7796ed2f5a9dac67eef1a87a166dcfNick Pelly            }
1056b6a3bf89303c7ef84910b28d59523d6441364beBen Murdoch        } else {
106b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen            return null;
107b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen        }
108b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen    }
109b2f93556ac91fe06eb8f6acab05b6a6d1b2fdbe1Martijn Coenen}
110