13da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton/*
23da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * Copyright (C) 2010 The Android Open Source Project
33da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton *
43da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
53da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * you may not use this file except in compliance with the License.
63da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * You may obtain a copy of the License at
73da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton *
83da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
93da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton *
103da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * Unless required by applicable law or agreed to in writing, software
113da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
123da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * See the License for the specific language governing permissions and
143da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * limitations under the License.
153da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton */
163da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
173da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonpackage com.android.apps.tag.record;
183da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
193da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport com.android.apps.tag.R;
2041287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardConfig;
2141287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardEntry;
2241287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardEntryConstructor;
2341287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardEntryHandler;
2441287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardParser;
2541287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.VCardParser_V21;
264a9765f25e654a2bd8e7c5082767a34307053497Jason parksimport com.android.vcard.VCardParser_V30;
2741287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport com.android.vcard.exception.VCardException;
284a9765f25e654a2bd8e7c5082767a34307053497Jason parksimport com.android.vcard.exception.VCardVersionException;
294e5e65bec8bb28f563d2764a262aa90182336a57Jeff Hamiltonimport com.google.android.collect.Lists;
303da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport com.google.common.base.Preconditions;
313da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
323da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.app.Activity;
3340d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parksimport android.content.ActivityNotFoundException;
34856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.content.ContentUris;
35856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.content.Context;
363da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.content.Intent;
37856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.content.pm.PackageManager;
38856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.content.pm.ResolveInfo;
39856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.content.res.AssetFileDescriptor;
40856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.database.Cursor;
4141287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport android.graphics.BitmapFactory;
4241287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport android.graphics.drawable.BitmapDrawable;
43856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.graphics.drawable.Drawable;
44856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.net.Uri;
453da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.nfc.NdefRecord;
4620bb7f715556bb336d1335fe09fdb41d9b742c94Ben Komaloimport android.os.AsyncTask;
47856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.os.Parcel;
48856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.os.Parcelable;
49856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.provider.ContactsContract;
504a9765f25e654a2bd8e7c5082767a34307053497Jason parksimport android.text.TextUtils;
5140d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parksimport android.util.Log;
523da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.view.LayoutInflater;
533da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.view.View;
543da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.view.View.OnClickListener;
553da1ea5658992857304ecc0bda0d079327580f02Jeff Hamiltonimport android.view.ViewGroup;
56856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.widget.ImageView;
57856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport android.widget.TextView;
58856d92e0bef58446cf8678e550f489d684ff727bBen Komalo
5941287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komaloimport java.io.ByteArrayInputStream;
60856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport java.io.FileInputStream;
61856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport java.io.FileNotFoundException;
62856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport java.io.IOException;
63856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport java.io.InputStream;
6420bb7f715556bb336d1335fe09fdb41d9b742c94Ben Komaloimport java.lang.ref.WeakReference;
654a9765f25e654a2bd8e7c5082767a34307053497Jason parksimport java.util.ArrayList;
66856d92e0bef58446cf8678e550f489d684ff727bBen Komaloimport java.util.List;
67a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parksimport java.util.Locale;
683da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
693da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton/**
703da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton * VCard Ndef Record object
713da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton */
7240d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parkspublic class VCardRecord extends ParsedNdefRecord implements OnClickListener {
7340d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks    private static final String TAG = VCardRecord.class.getSimpleName();
743da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
75856d92e0bef58446cf8678e550f489d684ff727bBen Komalo    public static final String RECORD_TYPE = "vcard";
76856d92e0bef58446cf8678e550f489d684ff727bBen Komalo
77856d92e0bef58446cf8678e550f489d684ff727bBen Komalo    private final byte[] mVCard;
783da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
798833d906e3c2d0d4e1b339d6c8fdd87cc23640c8Ben Komalo    private VCardRecord(byte[] content) {
803da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        mVCard = content;
813da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    }
823da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
833da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    @Override
8440d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks    public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent, int offset) {
8540d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks
8640d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        Uri uri = activity.getIntent().getData();
8740d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        uri = Uri.withAppendedPath(uri, Integer.toString(offset));
8840d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        uri = Uri.withAppendedPath(uri, "mime");
8940d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks
9041287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komalo        // TODO: parse content and display something nicer.
9140d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
924a9765f25e654a2bd8e7c5082767a34307053497Jason parks
934a9765f25e654a2bd8e7c5082767a34307053497Jason parks        CharSequence template = activity.getResources().getText(R.string.import_vcard);
944a9765f25e654a2bd8e7c5082767a34307053497Jason parks        String description = TextUtils.expandTemplate(template, getDisplayName()).toString();
954a9765f25e654a2bd8e7c5082767a34307053497Jason parks
964a9765f25e654a2bd8e7c5082767a34307053497Jason parks        return RecordUtils.getViewsForIntent(activity, inflater, parent, this, intent, description);
973da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    }
983da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
99a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks    @Override
100a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks    public String getSnippet(Context context, Locale locale) {
1014a9765f25e654a2bd8e7c5082767a34307053497Jason parks        CharSequence template = context.getResources().getText(R.string.vcard_title);
1024a9765f25e654a2bd8e7c5082767a34307053497Jason parks        return TextUtils.expandTemplate(template, getDisplayName()).toString();
1034a9765f25e654a2bd8e7c5082767a34307053497Jason parks    }
1044a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1054a9765f25e654a2bd8e7c5082767a34307053497Jason parks    public String getDisplayName() {
1064a9765f25e654a2bd8e7c5082767a34307053497Jason parks        try {
1074a9765f25e654a2bd8e7c5082767a34307053497Jason parks            ArrayList<VCardEntry> entries = getVCardEntries();
1084a9765f25e654a2bd8e7c5082767a34307053497Jason parks            if (!entries.isEmpty()) {
1094a9765f25e654a2bd8e7c5082767a34307053497Jason parks                return entries.get(0).getDisplayName();
1104a9765f25e654a2bd8e7c5082767a34307053497Jason parks            }
1114a9765f25e654a2bd8e7c5082767a34307053497Jason parks        } catch (Exception e) {
1124a9765f25e654a2bd8e7c5082767a34307053497Jason parks        }
1134a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1144a9765f25e654a2bd8e7c5082767a34307053497Jason parks        return "vCard";
1154a9765f25e654a2bd8e7c5082767a34307053497Jason parks    }
1164a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1174a9765f25e654a2bd8e7c5082767a34307053497Jason parks    private ArrayList<VCardEntry> getVCardEntries() throws IOException, VCardException {
1184a9765f25e654a2bd8e7c5082767a34307053497Jason parks        final ArrayList<VCardEntry> entries = Lists.newArrayList();
1194a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1204a9765f25e654a2bd8e7c5082767a34307053497Jason parks        final int type = VCardConfig.VCARD_TYPE_UNKNOWN;
1214a9765f25e654a2bd8e7c5082767a34307053497Jason parks        final VCardEntryConstructor constructor = new VCardEntryConstructor(type);
1224a9765f25e654a2bd8e7c5082767a34307053497Jason parks        constructor.addEntryHandler(new VCardEntryHandler() {
1234a9765f25e654a2bd8e7c5082767a34307053497Jason parks            @Override public void onStart() {}
1244a9765f25e654a2bd8e7c5082767a34307053497Jason parks            @Override public void onEnd() {}
1254a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1264a9765f25e654a2bd8e7c5082767a34307053497Jason parks            @Override
1274a9765f25e654a2bd8e7c5082767a34307053497Jason parks            public void onEntryCreated(VCardEntry entry) {
1284a9765f25e654a2bd8e7c5082767a34307053497Jason parks                entries.add(entry);
1294a9765f25e654a2bd8e7c5082767a34307053497Jason parks            }
1304a9765f25e654a2bd8e7c5082767a34307053497Jason parks        });
1314a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1324a9765f25e654a2bd8e7c5082767a34307053497Jason parks        VCardParser parser = new VCardParser_V21(type);
1334a9765f25e654a2bd8e7c5082767a34307053497Jason parks        try {
1344a9765f25e654a2bd8e7c5082767a34307053497Jason parks            parser.parse(new ByteArrayInputStream(mVCard), constructor);
1354a9765f25e654a2bd8e7c5082767a34307053497Jason parks        } catch (VCardVersionException e) {
1364a9765f25e654a2bd8e7c5082767a34307053497Jason parks            try {
1374a9765f25e654a2bd8e7c5082767a34307053497Jason parks                parser = new VCardParser_V30(type);
1384a9765f25e654a2bd8e7c5082767a34307053497Jason parks                parser.parse(new ByteArrayInputStream(mVCard), constructor);
1394a9765f25e654a2bd8e7c5082767a34307053497Jason parks            } finally {
1404a9765f25e654a2bd8e7c5082767a34307053497Jason parks            }
1414a9765f25e654a2bd8e7c5082767a34307053497Jason parks        }
1424a9765f25e654a2bd8e7c5082767a34307053497Jason parks
1434a9765f25e654a2bd8e7c5082767a34307053497Jason parks        return entries;
144a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks    }
145a6855221fb6e5c6c19d31283a18ced44cccdf442Jason parks
14641287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komalo    private static Intent getPickContactIntent() {
14774c0ecd074be40f95485f65f588d23dda09b7b90Ben Komalo        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
14874c0ecd074be40f95485f65f588d23dda09b7b90Ben Komalo        intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
14941287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komalo        return intent;
15041287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komalo    }
15141287c837506ad8a088676e0fd3bc3aafa18c3f2Ben Komalo
1523da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    public static VCardRecord parse(NdefRecord record) {
1533da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        MimeRecord underlyingRecord = MimeRecord.parse(record);
1543da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
1553da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        // TODO: Add support for other vcard mime types.
156116871653662979554a7326991ba4fd599ac44ffNick Pelly        Preconditions.checkArgument("text/x-vcard".equals(underlyingRecord.getMimeType()));
1573da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        return new VCardRecord(underlyingRecord.getContent());
1583da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    }
1593da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
160856d92e0bef58446cf8678e550f489d684ff727bBen Komalo    public static NdefRecord newVCardRecord(byte[] data) {
161116871653662979554a7326991ba4fd599ac44ffNick Pelly        return MimeRecord.newMimeRecord("text/x-vcard", data);
162856d92e0bef58446cf8678e550f489d684ff727bBen Komalo    }
163856d92e0bef58446cf8678e550f489d684ff727bBen Komalo
1643da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    @Override
1653da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    public void onClick(View view) {
16640d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        RecordUtils.ClickInfo info = (RecordUtils.ClickInfo) view.getTag();
16740d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        try {
16840d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks            info.activity.startActivity(info.intent);
16940d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks            info.activity.finish();
17040d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        } catch (ActivityNotFoundException e) {
17140d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks            // The activity wansn't found for some reason. Don't crash, but don't do anything.
17240d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks            Log.e(TAG, "Failed to launch activity for intent " + info.intent, e);
17340d9a0cd0a37d184ee737b2d7138a39e4292ce3eJason parks        }
1743da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    }
1753da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton
1763da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    public static boolean isVCard(NdefRecord record) {
1773da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        try {
1783da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton            parse(record);
1793da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton            return true;
1803da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        } catch (IllegalArgumentException e) {
1813da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton            return false;
1823da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton        }
1833da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton    }
1843da1ea5658992857304ecc0bda0d079327580f02Jeff Hamilton}
185