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