• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
doInBackground(VCardService... services)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
onCancelled()76         public void onCancelled() {
77             unbindService(NfcImportVCardActivity.this);
78         }
79 
80         @Override
onPostExecute(ImportRequest request)81         public void onPostExecute(ImportRequest request) {
82             unbindService(NfcImportVCardActivity.this);
83         }
84     }
85 
createImportRequest()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
onServiceConnected(ComponentName name, IBinder binder)138     public void onServiceConnected(ComponentName name, IBinder binder) {
139         VCardService service = ((VCardService.MyBinder) binder).getService();
140         new ImportTask().execute(service);
141     }
142 
143     @Override
onServiceDisconnected(ComponentName name)144     public void onServiceDisconnected(ComponentName name) {
145         // Do nothing
146     }
147 
148     @Override
onCreate(Bundle bundle)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
onActivityResult(int requestCode, int resultCode, Intent intent)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 
startImport()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
onImportProcessed(ImportRequest request, int jobId, int sequence)208     public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
209         // do nothing
210     }
211 
212     @Override
onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount, int totalCount)213     public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
214             int totalCount) {
215         // do nothing
216     }
217 
218     @Override
onImportFinished(ImportRequest request, int jobId, Uri uri)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
onImportFailed(ImportRequest request)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
onImportCanceled(ImportRequest request, int jobId)243     public void onImportCanceled(ImportRequest request, int jobId) {
244         // do nothing
245     }
246 
247     @Override
onExportProcessed(ExportRequest request, int jobId)248     public void onExportProcessed(ExportRequest request, int jobId) {
249         // do nothing
250     }
251 
252     @Override
onExportFailed(ExportRequest request)253     public void onExportFailed(ExportRequest request) {
254         // do nothing
255     }
256 
257     @Override
onCancelRequest(CancelRequest request, int type)258     public void onCancelRequest(CancelRequest request, int type) {
259         // do nothing
260     }
261 
262     @Override
onComplete()263     public void onComplete() {
264         // do nothing
265     }
266 }
267