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