18bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen/*
28bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * Copyright (C) 2011 The Android Open Source Project
38bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen *
48bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
58bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * you may not use this file except in compliance with the License.
68bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * You may obtain a copy of the License at
78bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen *
88bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
98bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen *
108bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * Unless required by applicable law or agreed to in writing, software
118bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
128bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * See the License for the specific language governing permissions and
148bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen * limitations under the License.
158bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen */
168bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
178bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenpackage com.android.contacts;
188bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
198bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.app.Activity;
208bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.content.ContentResolver;
218bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.net.Uri;
228bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.nfc.NdefMessage;
238bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.nfc.NdefRecord;
248bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.nfc.NfcAdapter;
25a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pellyimport android.nfc.NfcEvent;
268bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.provider.ContactsContract.Contacts;
2792165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenenimport android.provider.ContactsContract.Profile;
288bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport android.util.Log;
298bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
30e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.detail.ContactDetailFragment;
31e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
328bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport java.io.ByteArrayOutputStream;
338bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport java.io.IOException;
348bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenenimport java.io.InputStream;
358bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
36194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen/**
37194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * This class implements sharing the currently displayed
38194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * contact to another device using NFC. NFC sharing is only
39194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * enabled when the activity is in the foreground and resumed.
40194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * When an NFC link is established, {@link #createMessage}
41194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * will be called to create the data to be sent over the link,
42194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  * which is a vCard in this case.
43194cdd3b71e3fdb1a77a4fa5435a6b6319407e91Martijn Coenen  */
44a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pellypublic class NfcHandler implements NfcAdapter.CreateNdefMessageCallback {
458bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
4692165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen    private static final String TAG = "ContactNfcHandler";
4792165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen    private static final String PROFILE_LOOKUP_KEY = "profile";
4892165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen    private final ContactDetailFragment mContactFragment;
49a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly
50a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly    public static void register(Activity activity, ContactDetailFragment contactFragment) {
51a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(activity.getApplicationContext());
52a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        if (adapter == null) {
53a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly            return;  // NFC not available on this device
548bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        }
55a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        adapter.setNdefPushMessageCallback(new NfcHandler(contactFragment), activity);
568bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen    }
578bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
58a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly    public NfcHandler(ContactDetailFragment contactFragment) {
59a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        mContactFragment = contactFragment;
608bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen    }
618bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
628bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen    @Override
63a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly    public NdefMessage createNdefMessage(NfcEvent event) {
648bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        // Get the current contact URI
658bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        Uri contactUri = mContactFragment.getUri();
668bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        ContentResolver resolver = mContactFragment.getActivity().getContentResolver();
678bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        if (contactUri != null) {
688bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            final String lookupKey = Uri.encode(contactUri.getPathSegments().get(2));
6992165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            final Uri shareUri;
7092165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            // TODO find out where to get this constant from, or find another way
7192165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            // of determining this.
7292165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            if (lookupKey.equals(PROFILE_LOOKUP_KEY)) {
7392165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                shareUri = Profile.CONTENT_VCARD_URI.buildUpon().
7492165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                appendQueryParameter(Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, "true").
7592165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                build();
7692165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            } else {
7792165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                shareUri = Contacts.CONTENT_VCARD_URI.buildUpon().
7892165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                appendPath(lookupKey).
7992165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                appendQueryParameter(Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, "true").
8092165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen                build();
8192165c6938a6d62205c97ec8f7195117362a8d62Martijn Coenen            }
828bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            ByteArrayOutputStream ndefBytes = new ByteArrayOutputStream();
838bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            byte[] buffer = new byte[1024];
848bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            int r;
858bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            try {
868bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                InputStream vcardInputStream = resolver.openInputStream(shareUri);
878bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                while ((r = vcardInputStream.read(buffer)) > 0) {
888bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                    ndefBytes.write(buffer, 0, r);
898bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                }
908bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen
91cd564c953280182b64b2391c49e36a8c858f1e0dNick Pelly                NdefRecord record = NdefRecord.createMime("text/x-vcard", ndefBytes.toByteArray());
92cd564c953280182b64b2391c49e36a8c858f1e0dNick Pelly                return new NdefMessage(record);
938bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            } catch (IOException e) {
948bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                Log.e(TAG, "IOException creating vcard.");
958bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen                return null;
968bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            }
978bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        } else {
988bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            Log.w(TAG, "No contact URI to share.");
998bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen            return null;
1008bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen        }
1018bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen    }
1028bd4065141c64a4ab249aec46e5f32d25a862f64Martijn Coenen}
103