• 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.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
doInBackground(VCardService... services)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
onCancelled()77         public void onCancelled() {
78             unbindService(NfcImportVCardActivity.this);
79         }
80 
81         @Override
onPostExecute(ImportRequest request)82         public void onPostExecute(ImportRequest request) {
83             unbindService(NfcImportVCardActivity.this);
84         }
85     }
86 
createImportRequest()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
onServiceConnected(ComponentName name, IBinder binder)139     public void onServiceConnected(ComponentName name, IBinder binder) {
140         VCardService service = ((VCardService.MyBinder) binder).getService();
141         new ImportTask().execute(service);
142     }
143 
144     @Override
onServiceDisconnected(ComponentName name)145     public void onServiceDisconnected(ComponentName name) {
146         // Do nothing
147     }
148 
149     @Override
onCreate(Bundle bundle)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         }
158 
159         NdefMessage msg = (NdefMessage) intent.getParcelableArrayExtra(
160                 NfcAdapter.EXTRA_NDEF_MESSAGES)[0];
161         NdefRecord records[] = msg.getRecords();
162         if (records == null || records.length == 0) {
163             Log.w(TAG, "No records " + intent);
164             finish();
165         }
166 
167         NdefRecord record = records[0];
168         String type = new String(record.getType(), Charset.forName("UTF8"));
169         if (record.getTnf() != NdefRecord.TNF_MIME_MEDIA ||
170                 (!"text/x-vcard".equalsIgnoreCase(type) && !"text/vcard".equals(type))) {
171             Log.w(TAG, "Not a vcard");
172             //setStatus(getString(R.string.fail_reason_not_supported));
173             return;
174         }
175         mRecord = record;
176 
177         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
178         final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
179         if (accountList.size() == 0) {
180             mAccount = null;
181         } else if (accountList.size() == 1) {
182             mAccount = accountList.get(0);
183         } else {
184             startActivityForResult(new Intent(this, SelectAccountActivity.class), SELECT_ACCOUNT);
185             return;
186         }
187 
188         startImport();
189     }
190 
191     @Override
onActivityResult(int requestCode, int resultCode, Intent intent)192     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
193         if (requestCode == SELECT_ACCOUNT) {
194             if (resultCode == RESULT_OK) {
195                 mAccount = new AccountWithDataSet(
196                         intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
197                         intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
198                         intent.getStringExtra(SelectAccountActivity.DATA_SET));
199                 startImport();
200             } else {
201                 finish();
202             }
203         }
204     }
205 
startImport()206     private void startImport() {
207         // We don't want the service finishes itself just after this connection.
208         Intent intent = new Intent(this, VCardService.class);
209         startService(intent);
210         bindService(intent, this, Context.BIND_AUTO_CREATE);
211     }
212 
213     @Override
onImportProcessed(ImportRequest request, int jobId, int sequence)214     public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
215         // do nothing
216     }
217 
218     @Override
onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount, int totalCount)219     public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
220             int totalCount) {
221         // do nothing
222     }
223 
224     @Override
onImportFinished(ImportRequest request, int jobId, Uri uri)225     public void onImportFinished(ImportRequest request, int jobId, Uri uri) {
226         if (isFinishing()) {
227             Log.i(TAG, "Late import -- ignoring");
228             return;
229         }
230 
231         if (uri != null) {
232             Uri contactUri = RawContacts.getContactLookupUri(getContentResolver(), uri);
233             Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
234             startActivity(intent);
235             finish();
236         }
237     }
238 
239     @Override
onImportFailed(ImportRequest request)240     public void onImportFailed(ImportRequest request) {
241         if (isFinishing()) {
242             Log.i(TAG, "Late import failure -- ignoring");
243             return;
244         }
245         // TODO: report failure
246     }
247 
248     @Override
onImportCanceled(ImportRequest request, int jobId)249     public void onImportCanceled(ImportRequest request, int jobId) {
250         // do nothing
251     }
252 
253     @Override
onExportProcessed(ExportRequest request, int jobId)254     public void onExportProcessed(ExportRequest request, int jobId) {
255         // do nothing
256     }
257 
258     @Override
onExportFailed(ExportRequest request)259     public void onExportFailed(ExportRequest request) {
260         // do nothing
261     }
262 
263     @Override
onCancelRequest(CancelRequest request, int type)264     public void onCancelRequest(CancelRequest request, int type) {
265         // do nothing
266     }
267 
268     @Override
onComplete()269     public void onComplete() {
270         // do nothing
271     }
272 }
273