17903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng/* 27903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Copyright (C) 2009 The Android Open Source Project 37903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 47903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 57903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * you may not use this file except in compliance with the License. 67903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * You may obtain a copy of the License at 77903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 87903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 97903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Unless required by applicable law or agreed to in writing, software 117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * See the License for the specific language governing permissions and 147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * limitations under the License. 157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengpackage com.android.contacts.common.vcard; 187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.Activity; 207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.AlertDialog; 217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.Dialog; 227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.Notification; 237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.NotificationManager; 247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.ProgressDialog; 257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.ComponentName; 267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.ContentResolver; 277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.Context; 287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.DialogInterface; 297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.DialogInterface.OnCancelListener; 307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.DialogInterface.OnClickListener; 317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.Intent; 327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.ServiceConnection; 337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.database.Cursor; 347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.net.Uri; 357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.os.Bundle; 367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.os.Environment; 377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.os.Handler; 387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.os.IBinder; 397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.os.PowerManager; 407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.provider.OpenableColumns; 417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.text.SpannableStringBuilder; 427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.text.Spanned; 437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.text.TextUtils; 447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.text.style.RelativeSizeSpan; 457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.util.Log; 467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.widget.Toast; 477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.contacts.common.R; 497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.contacts.common.model.AccountTypeManager; 507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.contacts.common.model.account.AccountWithDataSet; 517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.contacts.common.util.AccountSelectionUtil; 527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardEntryCounter; 537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardParser; 547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardParser_V21; 557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardParser_V30; 567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardSourceDetector; 577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.exception.VCardException; 587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.exception.VCardNestedException; 597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.exception.VCardVersionException; 607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.ByteArrayInputStream; 627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.File; 637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.IOException; 647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.InputStream; 657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.nio.ByteBuffer; 667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.nio.channels.Channels; 677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.nio.channels.ReadableByteChannel; 687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.nio.channels.WritableByteChannel; 697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.text.DateFormat; 707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.text.SimpleDateFormat; 717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.ArrayList; 727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.Arrays; 737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.Date; 747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.HashSet; 757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.List; 767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.Set; 777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.util.Vector; 787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng/** 807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * The class letting users to import vCard. This includes the UI part for letting them select 817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * an Account and posssibly a file if there's no Uri is given from its caller Activity. 827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Note that this Activity assumes that the instance is a "one-shot Activity", which will be 847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * finished (with the method {@link Activity#finish()}) after the import and never reuse 857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * any Dialog in the instance. So this code is careless about the management around managed 867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * dialogs stuffs (like how onCreateDialog() is used). 877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengpublic class ImportVCardActivity extends Activity { 897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private static final String LOG_TAG = "VCardImport"; 907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private static final int SELECT_ACCOUNT = 0; 927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ static final String VCARD_URI_ARRAY = "vcard_uri"; 947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ static final String ESTIMATED_VCARD_TYPE_ARRAY = "estimated_vcard_type"; 957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ static final String ESTIMATED_CHARSET_ARRAY = "estimated_charset"; 967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ static final String VCARD_VERSION_ARRAY = "vcard_version"; 977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ static final String ENTRY_COUNT_ARRAY = "entry_count"; 987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0; 1007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ final static int VCARD_VERSION_V21 = 1; 1017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ final static int VCARD_VERSION_V30 = 2; 1027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private static final String SECURE_DIRECTORY_NAME = ".android_secure"; 1047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 1067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Notification id used when error happened before sending an import request to VCardServer. 1077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 1087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private static final int FAILURE_NOTIFICATION_ID = 1; 1097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final static String CACHED_URIS = "cached_uris"; 1117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private AccountSelectionUtil.AccountSelectedListener mAccountSelectionListener; 1137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private AccountWithDataSet mAccount; 1157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private ProgressDialog mProgressDialogForScanVCard; 1177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private ProgressDialog mProgressDialogForCachingVCard; 1187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private List<VCardFile> mAllVCardFileList; 1207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private VCardScanThread mVCardScanThread; 1217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private VCardCacheThread mVCardCacheThread; 1237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private ImportRequestConnection mConnection; 1247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ VCardImportExportListener mListener; 1257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private String mErrorMessage; 1277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Handler mHandler = new Handler(); 1297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private static class VCardFile { 1317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final String mName; 1327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final String mCanonicalPath; 1337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final long mLastModified; 1347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public VCardFile(String name, String canonicalPath, long lastModified) { 1367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mName = name; 1377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanonicalPath = canonicalPath; 1387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mLastModified = lastModified; 1397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public String getName() { 1427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mName; 1437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public String getCanonicalPath() { 1467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mCanonicalPath; 1477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public long getLastModified() { 1507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mLastModified; 1517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Runs on the UI thread. 1557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class DialogDisplayer implements Runnable { 1567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final int mResId; 1577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public DialogDisplayer(int resId) { 1587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mResId = resId; 1597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public DialogDisplayer(String errorMessage) { 1617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mResId = R.id.dialog_error_with_message; 1627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mErrorMessage = errorMessage; 1637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 1657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void run() { 1667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!isFinishing()) { 1677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(mResId); 1687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class CancelListener 1737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener { 1747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 1757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onClick(DialogInterface dialog, int which) { 1767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 1777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 1797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onCancel(DialogInterface dialog) { 1807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 1817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private CancelListener mCancelListener = new CancelListener(); 1857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class ImportRequestConnection implements ServiceConnection { 1877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private VCardService mService; 1887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void sendImportRequest(final List<ImportRequest> requests) { 1907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Send an import request"); 1917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mService.handleImportRequest(requests, mListener); 1927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 1937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 1947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 1957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onServiceConnected(ComponentName name, IBinder binder) { 1967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mService = ((VCardService.MyBinder) binder).getService(); 1977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, 1987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String.format("Connected to VCardService. Kick a vCard cache thread (uri: %s)", 1997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Arrays.toString(mVCardCacheThread.getSourceUris()))); 2007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardCacheThread.start(); 2017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 2047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onServiceDisconnected(ComponentName name) { 2057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Disconnected from VCardService"); 2067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 2107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Caches given vCard files into a local directory, and sends actual import request to 2117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * {@link VCardService}. 2127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 2137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * We need to cache given files into local storage. One of reasons is that some data (as Uri) 2147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * may have special permissions. Callers may allow only this Activity to access that content, 2157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * not what this Activity launched (like {@link VCardService}). 2167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 2177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class VCardCacheThread extends Thread 2187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng implements DialogInterface.OnCancelListener { 2197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private boolean mCanceled; 2207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private PowerManager.WakeLock mWakeLock; 2217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private VCardParser mVCardParser; 2227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final Uri[] mSourceUris; // Given from a caller. 2237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final byte[] mSource; 2247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private final String mDisplayName; 2257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public VCardCacheThread(final Uri[] sourceUris) { 2277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mSourceUris = sourceUris; 2287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mSource = null; 2297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Context context = ImportVCardActivity.this; 2307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final PowerManager powerManager = 2317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng (PowerManager)context.getSystemService(Context.POWER_SERVICE); 2327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock = powerManager.newWakeLock( 2337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng PowerManager.SCREEN_DIM_WAKE_LOCK | 2347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng PowerManager.ON_AFTER_RELEASE, LOG_TAG); 2357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mDisplayName = null; 2367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 2397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void finalize() { 2407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mWakeLock != null && mWakeLock.isHeld()) { 2417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "WakeLock is being held."); 2427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock.release(); 2437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 2477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void run() { 2487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "vCard cache thread starts running."); 2497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mConnection == null) { 2507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new NullPointerException("vCard cache thread must be launched " 2517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng + "after a service connection is established"); 2527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock.acquire(); 2557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 2567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled == true) { 2577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "vCard cache operation is canceled."); 2587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 2597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 2617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Context context = ImportVCardActivity.this; 2627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Uris given from caller applications may not be opened twice: consider when 2637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // it is not from local storage (e.g. "file:///...") but from some special 2647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // provider (e.g. "content://..."). 2657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Thus we have to once copy the content of Uri into local storage, and read 2667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // it after it. 2677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // 2687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // We may be able to read content of each vCard file during copying them 2697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // to local storage, but currently vCard code does not allow us to do so. 2707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int cache_index = 0; 2717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>(); 2727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSource != null) { 2737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 2747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng requests.add(constructImportRequest(mSource, null, mDisplayName)); 2757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (VCardException e) { 2767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "Maybe the file is in wrong format", e); 2777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showFailureNotification(R.string.fail_reason_not_supported); 2787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 2797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 2817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final ContentResolver resolver = 2827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng ImportVCardActivity.this.getContentResolver(); 2837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (Uri sourceUri : mSourceUris) { 2847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String filename = null; 2857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Note: caches are removed by VCardService. 2867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng while (true) { 2877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng filename = VCardService.CACHE_FILE_PREFIX + cache_index + ".vcf"; 2887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final File file = context.getFileStreamPath(filename); 2897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!file.exists()) { 2907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 2917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 2927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (cache_index == Integer.MAX_VALUE) { 2937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new RuntimeException("Exceeded cache limit"); 2947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng cache_index++; 2967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 2987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Uri localDataUri = copyTo(sourceUri, filename); 2997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 3007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "vCard cache operation is canceled."); 3017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 3027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (localDataUri == null) { 3047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "destUri is null"); 3057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 3067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 3087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String displayName = null; 3097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Cursor cursor = null; 3107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Try to get a display name from the given Uri. If it fails, we just 3117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // pick up the last part of the Uri. 3127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 3137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng cursor = resolver.query(sourceUri, 3147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng new String[] { OpenableColumns.DISPLAY_NAME }, 3157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng null, null, null); 3167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { 3177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (cursor.getCount() > 1) { 3187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Unexpected multiple rows: " 3197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng + cursor.getCount()); 3207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); 3227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (index >= 0) { 3237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng displayName = cursor.getString(index); 3247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } finally { 3277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (cursor != null) { 3287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng cursor.close(); 3297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (TextUtils.isEmpty(displayName)){ 3327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng displayName = sourceUri.getLastPathSegment(); 3337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 3357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final ImportRequest request; 3367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 3377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng request = constructImportRequest(null, localDataUri, displayName); 3387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (VCardException e) { 3397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "Maybe the file is in wrong format", e); 3407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showFailureNotification(R.string.fail_reason_not_supported); 3417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 3427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 3437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "Unexpected IOException", e); 3447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showFailureNotification(R.string.fail_reason_io_error); 3457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 3467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 3487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "vCard cache operation is canceled."); 3497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 3507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng requests.add(request); 3527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!requests.isEmpty()) { 3557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mConnection.sendImportRequest(requests); 3567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 3577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Empty import requests. Ignore it."); 3587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (OutOfMemoryError e) { 3607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "OutOfMemoryError occured during caching vCard"); 3617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng System.gc(); 3627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer( 3637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.fail_reason_low_memory_during_import))); 3647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 3657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "IOException during caching vCard", e); 3667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer( 3677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.fail_reason_io_error))); 3687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } finally { 3697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Finished caching vCard."); 3707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock.release(); 3717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng unbindService(mConnection); 3727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard.dismiss(); 3737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard = null; 3747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 3757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 3787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 3797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Copy the content of sourceUri to the destination. 3807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 3817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Uri copyTo(final Uri sourceUri, String filename) throws IOException { 3827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, String.format("Copy a Uri to app local storage (%s -> %s)", 3837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng sourceUri, filename)); 3847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Context context = ImportVCardActivity.this; 3857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final ContentResolver resolver = context.getContentResolver(); 3867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng ReadableByteChannel inputChannel = null; 3877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng WritableByteChannel outputChannel = null; 3887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Uri destUri = null; 3897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 3907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng inputChannel = Channels.newChannel(resolver.openInputStream(sourceUri)); 3917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng destUri = Uri.parse(context.getFileStreamPath(filename).toURI().toString()); 3927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng outputChannel = context.openFileOutput(filename, Context.MODE_PRIVATE).getChannel(); 3937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final ByteBuffer buffer = ByteBuffer.allocateDirect(8192); 3947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng while (inputChannel.read(buffer) != -1) { 3957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 3967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.d(LOG_TAG, "Canceled during caching " + sourceUri); 3977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return null; 3987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 3997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng buffer.flip(); 4007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng outputChannel.write(buffer); 4017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng buffer.compact(); 4027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng buffer.flip(); 4047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng while (buffer.hasRemaining()) { 4057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng outputChannel.write(buffer); 4067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } finally { 4087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (inputChannel != null) { 4097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng inputChannel.close(); 4117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 4127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Failed to close inputChannel."); 4137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (outputChannel != null) { 4167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng outputChannel.close(); 4187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch(IOException e) { 4197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Failed to close outputChannel"); 4207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return destUri; 4247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 4267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 4277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Reads localDataUri (possibly multiple times) and constructs {@link ImportRequest} from 4287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * its content. 4297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * 4307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * @arg localDataUri Uri actually used for the import. Should be stored in 4317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * app local storage, as we cannot guarantee other types of Uris can be read 4327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * multiple times. This variable populates {@link ImportRequest#uri}. 4337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * @arg displayName Used for displaying information to the user. This variable populates 4347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * {@link ImportRequest#displayName}. 4357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 4367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private ImportRequest constructImportRequest(final byte[] data, 4377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Uri localDataUri, final String displayName) 4387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throws IOException, VCardException { 4397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final ContentResolver resolver = ImportVCardActivity.this.getContentResolver(); 4407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng VCardEntryCounter counter = null; 4417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng VCardSourceDetector detector = null; 4427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int vcardVersion = VCARD_VERSION_V21; 4437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng boolean shouldUseV30 = false; 4457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng InputStream is; 4467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (data != null) { 4477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is = new ByteArrayInputStream(data); 4487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 4497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is = resolver.openInputStream(localDataUri); 4507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser = new VCardParser_V21(); 4527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng counter = new VCardEntryCounter(); 4547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng detector = new VCardSourceDetector(); 4557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.addInterpreter(counter); 4567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.addInterpreter(detector); 4577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.parse(is); 4587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (VCardVersionException e1) { 4597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is.close(); 4617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 4627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 4647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng shouldUseV30 = true; 4657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (data != null) { 4667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is = new ByteArrayInputStream(data); 4677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 4687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is = resolver.openInputStream(localDataUri); 4697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser = new VCardParser_V30(); 4717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng counter = new VCardEntryCounter(); 4737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng detector = new VCardSourceDetector(); 4747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.addInterpreter(counter); 4757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.addInterpreter(detector); 4767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.parse(is); 4777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (VCardVersionException e2) { 4787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new VCardException("vCard with unspported version."); 4797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } finally { 4817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (is != null) { 4827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 4837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng is.close(); 4847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 4857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 4897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21; 4907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (VCardNestedException e) { 4917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive)."); 4927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Go through without throwing the Exception, as we may be able to detect the 4937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // version before it 4947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 4957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return new ImportRequest(mAccount, 4967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng data, localDataUri, displayName, 4977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng detector.getEstimatedType(), 4987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng detector.getEstimatedCharset(), 4997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng vcardVersion, counter.getCount()); 5007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public Uri[] getSourceUris() { 5037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mSourceUris; 5047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void cancel() { 5077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanceled = true; 5087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mVCardParser != null) { 5097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardParser.cancel(); 5107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 5147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onCancel(DialogInterface dialog) { 5157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Cancel request has come. Abort caching vCard."); 5167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng cancel(); 5177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class ImportTypeSelectedListener implements 5217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng DialogInterface.OnClickListener { 5227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public static final int IMPORT_ONE = 0; 5237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public static final int IMPORT_MULTIPLE = 1; 5247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public static final int IMPORT_ALL = 2; 5257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public static final int IMPORT_TYPE_SIZE = 3; 5267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private int mCurrentIndex; 5287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onClick(DialogInterface dialog, int which) { 5307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (which == DialogInterface.BUTTON_POSITIVE) { 5317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng switch (mCurrentIndex) { 5327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case IMPORT_ALL: 5337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCardFromSDCard(mAllVCardFileList); 5347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 5357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case IMPORT_MULTIPLE: 5367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_select_multiple_vcard); 5377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 5387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng default: 5397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_select_one_vcard); 5407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng break; 5417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (which == DialogInterface.BUTTON_NEGATIVE) { 5437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 5447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 5457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCurrentIndex = which; 5467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class VCardSelectedListener implements 5517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener { 5527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private int mCurrentIndex; 5537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Set<Integer> mSelectedIndexSet; 5547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public VCardSelectedListener(boolean multipleSelect) { 5567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCurrentIndex = 0; 5577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (multipleSelect) { 5587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mSelectedIndexSet = new HashSet<Integer>(); 5597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onClick(DialogInterface dialog, int which) { 5637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (which == DialogInterface.BUTTON_POSITIVE) { 5647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSelectedIndexSet != null) { 5657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng List<VCardFile> selectedVCardFileList = new ArrayList<VCardFile>(); 5667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final int size = mAllVCardFileList.size(); 5677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // We'd like to sort the files by its index, so we do not use Set iterator. 5687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (int i = 0; i < size; i++) { 5697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSelectedIndexSet.contains(i)) { 5707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng selectedVCardFileList.add(mAllVCardFileList.get(i)); 5717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCardFromSDCard(selectedVCardFileList); 5747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 5757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCardFromSDCard(mAllVCardFileList.get(mCurrentIndex)); 5767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (which == DialogInterface.BUTTON_NEGATIVE) { 5787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 5797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 5807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Some file is selected. 5817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCurrentIndex = which; 5827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSelectedIndexSet != null) { 5837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSelectedIndexSet.contains(which)) { 5847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mSelectedIndexSet.remove(which); 5857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 5867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mSelectedIndexSet.add(which); 5877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 5927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onClick(DialogInterface dialog, int which, boolean isChecked) { 5937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mSelectedIndexSet == null || (mSelectedIndexSet.contains(which) == isChecked)) { 5947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, String.format("Inconsist state in index %d (%s)", which, 5957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAllVCardFileList.get(which).getCanonicalPath())); 5967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 5977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng onClick(dialog, which); 5987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 5997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 6037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Thread scanning VCard from SDCard. After scanning, the dialog which lets a user select 6047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * a vCard file is shown. After the choice, VCardReadThread starts running. 6057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 6067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class VCardScanThread extends Thread implements OnCancelListener, OnClickListener { 6077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private boolean mCanceled; 6087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private boolean mGotIOException; 6097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private File mRootDirectory; 6107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // To avoid recursive link. 6127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Set<String> mCheckedPaths; 6137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private PowerManager.WakeLock mWakeLock; 6147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private class CanceledException extends Exception { 6167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public VCardScanThread(File sdcardDirectory) { 6197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanceled = false; 6207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mGotIOException = false; 6217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mRootDirectory = sdcardDirectory; 6227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCheckedPaths = new HashSet<String>(); 6237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng PowerManager powerManager = (PowerManager)ImportVCardActivity.this.getSystemService( 6247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Context.POWER_SERVICE); 6257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock = powerManager.newWakeLock( 6267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng PowerManager.SCREEN_DIM_WAKE_LOCK | 6277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng PowerManager.ON_AFTER_RELEASE, LOG_TAG); 6287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 6317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void run() { 6327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAllVCardFileList = new Vector<VCardFile>(); 6337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng try { 6347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock.acquire(); 6357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getVCardFileRecursively(mRootDirectory); 6367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (CanceledException e) { 6377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanceled = true; 6387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } catch (IOException e) { 6397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mGotIOException = true; 6407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } finally { 6417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mWakeLock.release(); 6427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 6457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAllVCardFileList = null; 6467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForScanVCard.dismiss(); 6497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForScanVCard = null; 6507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mGotIOException) { 6527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer(R.id.dialog_io_exception)); 6537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (mCanceled) { 6547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 6557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 6567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int size = mAllVCardFileList.size(); 6577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Context context = ImportVCardActivity.this; 6587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (size == 0) { 6597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer(R.id.dialog_vcard_not_found)); 6607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 6617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startVCardSelectAndImport(); 6627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void getVCardFileRecursively(File directory) 6677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throws CanceledException, IOException { 6687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 6697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new CanceledException(); 6707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // e.g. secured directory may return null toward listFiles(). 6737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final File[] files = directory.listFiles(); 6747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (files == null) { 6757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String currentDirectoryPath = directory.getCanonicalPath(); 6767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String secureDirectoryPath = 6777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mRootDirectory.getCanonicalPath().concat(SECURE_DIRECTORY_NAME); 6787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!TextUtils.equals(currentDirectoryPath, secureDirectoryPath)) { 6797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "listFiles() returned null (directory: " + directory + ")"); 6807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 6827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (File file : directory.listFiles()) { 6847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCanceled) { 6857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new CanceledException(); 6867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String canonicalPath = file.getCanonicalPath(); 6887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mCheckedPaths.contains(canonicalPath)) { 6897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng continue; 6907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 6917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCheckedPaths.add(canonicalPath); 6937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 6947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (file.isDirectory()) { 6957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getVCardFileRecursively(file); 6967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (canonicalPath.toLowerCase().endsWith(".vcf") && 6977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng file.canRead()){ 6987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String fileName = file.getName(); 6997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng VCardFile vcardFile = new VCardFile( 7007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng fileName, canonicalPath, file.lastModified()); 7017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAllVCardFileList.add(vcardFile); 7027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onCancel(DialogInterface dialog) { 7077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanceled = true; 7087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onClick(DialogInterface dialog, int which) { 7117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (which == DialogInterface.BUTTON_NEGATIVE) { 7127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mCanceled = true; 7137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void startVCardSelectAndImport() { 7187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int size = mAllVCardFileList.size(); 7197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (getResources().getBoolean(R.bool.config_import_all_vcard_from_sdcard_automatically) || 7207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng size == 1) { 7217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCardFromSDCard(mAllVCardFileList); 7227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (getResources().getBoolean(R.bool.config_allow_users_select_all_vcard_import)) { 7237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer(R.id.dialog_select_import_type)); 7247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 7257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new DialogDisplayer(R.id.dialog_select_one_vcard)); 7267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void importVCardFromSDCard(final List<VCardFile> selectedVCardFileList) { 7307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final int size = selectedVCardFileList.size(); 7317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String[] uriStrings = new String[size]; 7327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int i = 0; 7337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (VCardFile vcardFile : selectedVCardFileList) { 7347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng uriStrings[i] = "file://" + vcardFile.getCanonicalPath(); 7357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng i++; 7367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCard(uriStrings); 7387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void importVCardFromSDCard(final VCardFile vcardFile) { 7417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCard(new Uri[] {Uri.parse("file://" + vcardFile.getCanonicalPath())}); 7427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void importVCard(final Uri uri) { 7457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCard(new Uri[] {uri}); 7467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void importVCard(final String[] uriStrings) { 7497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final int length = uriStrings.length; 7507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Uri[] uris = new Uri[length]; 7517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (int i = 0; i < length; i++) { 7527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng uris[i] = Uri.parse(uriStrings[i]); 7537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCard(uris); 7557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void importVCard(final Uri[] uris) { 7587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng runOnUiThread(new Runnable() { 7597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 7607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void run() { 7617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!isFinishing()) { 7627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardCacheThread = new VCardCacheThread(uris); 7637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mListener = new NotificationImportExportListener(ImportVCardActivity.this); 7647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_cache_vcard); 7657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng }); 7687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Dialog getSelectImportTypeDialog() { 7717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final DialogInterface.OnClickListener listener = new ImportTypeSelectedListener(); 7727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final AlertDialog.Builder builder = new AlertDialog.Builder(this) 7737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setTitle(R.string.select_vcard_title) 7747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, listener) 7757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 7767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setNegativeButton(android.R.string.cancel, mCancelListener); 7777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String[] items = new String[ImportTypeSelectedListener.IMPORT_TYPE_SIZE]; 7797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng items[ImportTypeSelectedListener.IMPORT_ONE] = 7807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.import_one_vcard_string); 7817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng items[ImportTypeSelectedListener.IMPORT_MULTIPLE] = 7827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.import_multiple_vcard_string); 7837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng items[ImportTypeSelectedListener.IMPORT_ALL] = 7847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.import_all_vcard_string); 7857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng builder.setSingleChoiceItems(items, ImportTypeSelectedListener.IMPORT_ONE, listener); 7867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 7877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 7887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private Dialog getVCardFileSelectDialog(boolean multipleSelect) { 7907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final int size = mAllVCardFileList.size(); 7917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final VCardSelectedListener listener = new VCardSelectedListener(multipleSelect); 7927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final AlertDialog.Builder builder = 7937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng new AlertDialog.Builder(this) 7947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setTitle(R.string.select_vcard_title) 7957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, listener) 7967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 7977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setNegativeButton(android.R.string.cancel, mCancelListener); 7987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 7997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng CharSequence[] items = new CharSequence[size]; 8007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 8017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng for (int i = 0; i < size; i++) { 8027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng VCardFile vcardFile = mAllVCardFileList.get(i); 8037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); 8047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng stringBuilder.append(vcardFile.getName()); 8057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng stringBuilder.append('\n'); 8067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng int indexToBeSpanned = stringBuilder.length(); 8077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Smaller date text looks better, since each file name becomes easier to read. 8087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // The value set to RelativeSizeSpan is arbitrary. You can change it to any other 8097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // value (but the value bigger than 1.0f would not make nice appearance :) 8107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng stringBuilder.append( 8117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng "(" + dateFormat.format(new Date(vcardFile.getLastModified())) + ")"); 8127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng stringBuilder.setSpan( 8137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng new RelativeSizeSpan(0.7f), indexToBeSpanned, stringBuilder.length(), 8147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 8157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng items[i] = stringBuilder; 8167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (multipleSelect) { 8187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng builder.setMultiChoiceItems(items, (boolean[])null, listener); 8197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng builder.setSingleChoiceItems(items, 0, listener); 8217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 8237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 8267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng protected void onCreate(Bundle bundle) { 8277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng super.onCreate(bundle); 8287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String accountName = null; 8307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String accountType = null; 8317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String dataSet = null; 8327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Intent intent = getIntent(); 8337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (intent != null) { 8347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng accountName = intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME); 8357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng accountType = intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE); 8367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng dataSet = intent.getStringExtra(SelectAccountActivity.DATA_SET); 8377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "intent does not exist"); 8397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 8427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAccount = new AccountWithDataSet(accountName, accountType, dataSet); 8437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this); 8457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true); 8467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (accountList.size() == 0) { 8477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAccount = null; 8487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else if (accountList.size() == 1) { 8497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAccount = accountList.get(0); 8507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startActivityForResult(new Intent(this, SelectAccountActivity.class), 8527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng SELECT_ACCOUNT); 8537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return; 8547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startImport(); 8587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 8617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void onActivityResult(int requestCode, int resultCode, Intent intent) { 8627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (requestCode == SELECT_ACCOUNT) { 8637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (resultCode == Activity.RESULT_OK) { 8647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAccount = new AccountWithDataSet( 8657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME), 8667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE), 8677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng intent.getStringExtra(SelectAccountActivity.DATA_SET)); 8687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startImport(); 8697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (resultCode != Activity.RESULT_CANCELED) { 8717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.w(LOG_TAG, "Result code was not OK nor CANCELED: " + resultCode); 8727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng finish(); 8747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void startImport() { 8797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Intent intent = getIntent(); 8807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // Handle inbound files 8817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Uri uri = intent.getData(); 8827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (uri != null) { 8837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Starting vCard import using Uri " + uri); 8847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng importVCard(uri); 8857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 8867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Start vCard without Uri. The user will select vCard manually."); 8877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng doScanExternalStorageAndImportVCard(); 8887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 8917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 8927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng protected Dialog onCreateDialog(int resId, Bundle bundle) { 8937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng switch (resId) { 8947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.string.import_from_sdcard: { 8957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mAccountSelectionListener == null) { 8967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng throw new NullPointerException( 8977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng "mAccountSelectionListener must not be null."); 8987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 8997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return AccountSelectionUtil.getSelectAccountDialog(this, resId, 9007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mAccountSelectionListener, mCancelListener); 9017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_searching_vcard: { 9037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mProgressDialogForScanVCard == null) { 9047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String message = getString(R.string.searching_vcard_message); 9057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForScanVCard = 9067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng ProgressDialog.show(this, "", message, true, false); 9077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForScanVCard.setOnCancelListener(mVCardScanThread); 9087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardScanThread.start(); 9097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mProgressDialogForScanVCard; 9117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_sdcard_not_found: { 9137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng AlertDialog.Builder builder = new AlertDialog.Builder(this) 9147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setIconAttribute(android.R.attr.alertDialogIcon) 9157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setMessage(R.string.no_sdcard_message) 9167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 9177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, mCancelListener); 9187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 9197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_vcard_not_found: { 9217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String message = getString(R.string.import_failure_no_vcard_file); 9227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng AlertDialog.Builder builder = new AlertDialog.Builder(this) 9237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setMessage(message) 9247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 9257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, mCancelListener); 9267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 9277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_select_import_type: { 9297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return getSelectImportTypeDialog(); 9307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_select_multiple_vcard: { 9327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return getVCardFileSelectDialog(true); 9337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_select_one_vcard: { 9357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return getVCardFileSelectDialog(false); 9367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_cache_vcard: { 9387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mProgressDialogForCachingVCard == null) { 9397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String title = getString(R.string.caching_vcard_title); 9407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final String message = getString(R.string.caching_vcard_message); 9417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard = new ProgressDialog(this); 9427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard.setTitle(title); 9437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard.setMessage(message); 9447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard.setProgressStyle(ProgressDialog.STYLE_SPINNER); 9457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mProgressDialogForCachingVCard.setOnCancelListener(mVCardCacheThread); 9467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startVCardService(); 9477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return mProgressDialogForCachingVCard; 9497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_io_exception: { 9517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String message = (getString(R.string.scanning_sdcard_failed_message, 9527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.fail_reason_io_error))); 9537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng AlertDialog.Builder builder = new AlertDialog.Builder(this) 9547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setIconAttribute(android.R.attr.alertDialogIcon) 9557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setMessage(message) 9567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 9577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, mCancelListener); 9587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 9597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng case R.id.dialog_error_with_message: { 9617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng String message = mErrorMessage; 9627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (TextUtils.isEmpty(message)) { 9637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.e(LOG_TAG, "Error message is null while it must not."); 9647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng message = getString(R.string.fail_reason_unknown); 9657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final AlertDialog.Builder builder = new AlertDialog.Builder(this) 9677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setTitle(getString(R.string.reading_vcard_failed_title)) 9687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setIconAttribute(android.R.attr.alertDialogIcon) 9697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setMessage(message) 9707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setOnCancelListener(mCancelListener) 9717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng .setPositiveButton(android.R.string.ok, mCancelListener); 9727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return builder.create(); 9737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 9767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng return super.onCreateDialog(resId, bundle); 9777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 9797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ void startVCardService() { 9807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mConnection = new ImportRequestConnection(); 9817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 9827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Bind to VCardService."); 9837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // We don't want the service finishes itself just after this connection. 9847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Intent intent = new Intent(this, VCardService.class); 9857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng startService(intent); 9867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng bindService(new Intent(this, VCardService.class), 9877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mConnection, Context.BIND_AUTO_CREATE); 9887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 9907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 9917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng protected void onRestoreInstanceState(Bundle savedInstanceState) { 9927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng super.onRestoreInstanceState(savedInstanceState); 9937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (mProgressDialogForCachingVCard != null) { 9947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Log.i(LOG_TAG, "Cache thread is still running. Show progress dialog again."); 9957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_cache_vcard); 9967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 9987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 9997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /** 10007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Scans vCard in external storage (typically SDCard) and tries to import it. 10017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * - When there's no SDCard available, an error dialog is shown. 10027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * - When multiple vCard files are available, asks a user to select one. 10037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */ 10047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng private void doScanExternalStorageAndImportVCard() { 10057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng // TODO: should use getExternalStorageState(). 10067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final File file = Environment.getExternalStorageDirectory(); 10077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng if (!file.exists() || !file.isDirectory() || !file.canRead()) { 10087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_sdcard_not_found); 10097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } else { 10107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mVCardScanThread = new VCardScanThread(file); 10117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng showDialog(R.id.dialog_searching_vcard); 10127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 10137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 10147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng 10157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng /* package */ void showFailureNotification(int reasonId) { 10167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final NotificationManager notificationManager = 10177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); 10187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng final Notification notification = 10197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng NotificationImportExportListener.constructImportFailureNotification( 10207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng ImportVCardActivity.this, 10217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(reasonId)); 10227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng notificationManager.notify(NotificationImportExportListener.FAILURE_NOTIFICATION_TAG, 10237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng FAILURE_NOTIFICATION_ID, notification); 10247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng mHandler.post(new Runnable() { 10257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng @Override 10267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng public void run() { 10277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng Toast.makeText(ImportVCardActivity.this, 10287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng getString(R.string.vcard_import_failed), Toast.LENGTH_LONG).show(); 10297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 10307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng }); 10317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng } 10327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng} 1033