Home | History | Annotate | Download | only in vcard
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.contacts.vcard;
     18 
     19 import com.android.contacts.R;
     20 import com.android.contacts.model.AccountTypeManager;
     21 import com.android.contacts.model.AccountWithDataSet;
     22 import com.android.vcard.VCardEntry;
     23 import com.android.vcard.VCardEntryCounter;
     24 import com.android.vcard.VCardParser;
     25 import com.android.vcard.VCardParser_V21;
     26 import com.android.vcard.VCardParser_V30;
     27 import com.android.vcard.VCardSourceDetector;
     28 import com.android.vcard.exception.VCardException;
     29 import com.android.vcard.exception.VCardNestedException;
     30 import com.android.vcard.exception.VCardVersionException;
     31 
     32 import android.app.Activity;
     33 import android.content.ComponentName;
     34 import android.content.Context;
     35 import android.content.Intent;
     36 import android.content.ServiceConnection;
     37 import android.net.Uri;
     38 import android.nfc.NdefMessage;
     39 import android.nfc.NdefRecord;
     40 import android.nfc.NfcAdapter;
     41 import android.os.AsyncTask;
     42 import android.os.Bundle;
     43 import android.os.IBinder;
     44 import android.provider.ContactsContract.RawContacts;
     45 import android.util.Log;
     46 
     47 import java.io.ByteArrayInputStream;
     48 import java.io.IOException;
     49 import java.nio.charset.Charset;
     50 import java.util.ArrayList;
     51 import java.util.List;
     52 
     53 public class NfcImportVCardActivity extends Activity implements ServiceConnection,
     54         VCardImportExportListener {
     55     private static final String TAG = "NfcImportVCardActivity";
     56 
     57     private static final int SELECT_ACCOUNT = 1;
     58 
     59     private NdefRecord mRecord;
     60     private AccountWithDataSet mAccount;
     61 
     62     /* package */ class ImportTask extends AsyncTask<VCardService, Void, ImportRequest> {
     63         @Override
     64         public ImportRequest doInBackground(VCardService... services) {
     65             ImportRequest request = createImportRequest();
     66             if (request == null) {
     67                 return null;
     68             }
     69 
     70             ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>();
     71             requests.add(request);
     72             services[0].handleImportRequest(requests, NfcImportVCardActivity.this);
     73             return request;
     74         }
     75 
     76         @Override
     77         public void onCancelled() {
     78             unbindService(NfcImportVCardActivity.this);
     79         }
     80 
     81         @Override
     82         public void onPostExecute(ImportRequest request) {
     83             unbindService(NfcImportVCardActivity.this);
     84         }
     85     }
     86 
     87     /* package */ ImportRequest createImportRequest() {
     88         VCardParser parser;
     89         VCardEntryCounter counter = null;
     90         VCardSourceDetector detector = null;
     91         int vcardVersion = ImportVCardActivity.VCARD_VERSION_V21;
     92         try {
     93             ByteArrayInputStream is = new ByteArrayInputStream(mRecord.getPayload());
     94             is.mark(0);
     95             parser = new VCardParser_V21();
     96             try {
     97                 counter = new VCardEntryCounter();
     98                 detector = new VCardSourceDetector();
     99                 parser.addInterpreter(counter);
    100                 parser.addInterpreter(detector);
    101                 parser.parse(is);
    102             } catch (VCardVersionException e1) {
    103                 is.reset();
    104                 vcardVersion = ImportVCardActivity.VCARD_VERSION_V30;
    105                 parser = new VCardParser_V30();
    106                 try {
    107                     counter = new VCardEntryCounter();
    108                     detector = new VCardSourceDetector();
    109                     parser.addInterpreter(counter);
    110                     parser.addInterpreter(detector);
    111                     parser.parse(is);
    112                 } catch (VCardVersionException e2) {
    113                     return null;
    114                 }
    115             } finally {
    116                 try {
    117                     if (is != null) is.close();
    118                 } catch (IOException e) {
    119                 }
    120             }
    121         } catch (IOException e) {
    122             Log.e(TAG, "Failed reading vcard data", e);
    123             return null;
    124         } catch (VCardNestedException e) {
    125             Log.w(TAG, "Nested Exception is found (it may be false-positive).");
    126             // Go through without throwing the Exception, as we may be able to detect the
    127             // version before it
    128         } catch (VCardException e) {
    129             Log.e(TAG, "Error parsing vcard", e);
    130             return null;
    131         }
    132 
    133         return new ImportRequest(mAccount, mRecord.getPayload(), null,
    134                 getString(R.string.nfc_vcard_file_name), detector.getEstimatedType(),
    135                 detector.getEstimatedCharset(), vcardVersion, counter.getCount());
    136     }
    137 
    138     @Override
    139     public void onServiceConnected(ComponentName name, IBinder binder) {
    140         VCardService service = ((VCardService.MyBinder) binder).getService();
    141         new ImportTask().execute(service);
    142     }
    143 
    144     @Override
    145     public void onServiceDisconnected(ComponentName name) {
    146         // Do nothing
    147     }
    148 
    149     @Override
    150     protected void onCreate(Bundle bundle) {
    151         super.onCreate(bundle);
    152 
    153         Intent intent = getIntent();
    154         if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
    155             Log.w(TAG, "Unknowon intent " + intent);
    156             finish();
    157             return;
    158         }
    159 
    160         String type = intent.getType();
    161         if (type == null ||
    162                 (!"text/x-vcard".equals(type) && !"text/vcard".equals(type))) {
    163             Log.w(TAG, "Not a vcard");
    164             //setStatus(getString(R.string.fail_reason_not_supported));
    165             finish();
    166             return;
    167         }
    168         NdefMessage msg = (NdefMessage) intent.getParcelableArrayExtra(
    169                 NfcAdapter.EXTRA_NDEF_MESSAGES)[0];
    170         mRecord = msg.getRecords()[0];
    171 
    172         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
    173         final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
    174         if (accountList.size() == 0) {
    175             mAccount = null;
    176         } else if (accountList.size() == 1) {
    177             mAccount = accountList.get(0);
    178         } else {
    179             startActivityForResult(new Intent(this, SelectAccountActivity.class), SELECT_ACCOUNT);
    180             return;
    181         }
    182 
    183         startImport();
    184     }
    185 
    186     @Override
    187     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    188         if (requestCode == SELECT_ACCOUNT) {
    189             if (resultCode == RESULT_OK) {
    190                 mAccount = new AccountWithDataSet(
    191                         intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
    192                         intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
    193                         intent.getStringExtra(SelectAccountActivity.DATA_SET));
    194                 startImport();
    195             } else {
    196                 finish();
    197             }
    198         }
    199     }
    200 
    201     private void startImport() {
    202         // We don't want the service finishes itself just after this connection.
    203         Intent intent = new Intent(this, VCardService.class);
    204         startService(intent);
    205         bindService(intent, this, Context.BIND_AUTO_CREATE);
    206     }
    207 
    208     @Override
    209     public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
    210         // do nothing
    211     }
    212 
    213     @Override
    214     public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
    215             int totalCount) {
    216         // do nothing
    217     }
    218 
    219     @Override
    220     public void onImportFinished(ImportRequest request, int jobId, Uri uri) {
    221         if (isFinishing()) {
    222             Log.i(TAG, "Late import -- ignoring");
    223             return;
    224         }
    225 
    226         if (uri != null) {
    227             Uri contactUri = RawContacts.getContactLookupUri(getContentResolver(), uri);
    228             Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
    229             startActivity(intent);
    230             finish();
    231         }
    232     }
    233 
    234     @Override
    235     public void onImportFailed(ImportRequest request) {
    236         if (isFinishing()) {
    237             Log.i(TAG, "Late import failure -- ignoring");
    238             return;
    239         }
    240         // TODO: report failure
    241     }
    242 
    243     @Override
    244     public void onImportCanceled(ImportRequest request, int jobId) {
    245         // do nothing
    246     }
    247 
    248     @Override
    249     public void onExportProcessed(ExportRequest request, int jobId) {
    250         // do nothing
    251     }
    252 
    253     @Override
    254     public void onExportFailed(ExportRequest request) {
    255         // do nothing
    256     }
    257 
    258     @Override
    259     public void onCancelRequest(CancelRequest request, int type) {
    260         // do nothing
    261     }
    262 
    263     @Override
    264     public void onComplete() {
    265         // do nothing
    266     }
    267 }
    268