Moving vcard UI to ContactsCommon.
Moving all class in vcard directory in preparation to move
ImportExportDialogFragment.
Bug: 6993891
Change-Id: I5a321892f86f788e874cd6ca0d29f3136645b495
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eff52d8..11eefce 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -416,7 +416,7 @@
</activity>
<!-- vCard related -->
- <activity android:name=".vcard.ImportVCardActivity"
+ <activity android:name=".common.vcard.ImportVCardActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/BackgroundOnlyTheme">
<intent-filter>
@@ -428,7 +428,7 @@
</intent-filter>
</activity>
- <activity android:name=".vcard.NfcImportVCardActivity"
+ <activity android:name=".common.vcard.NfcImportVCardActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/BackgroundOnlyTheme">
<intent-filter>
@@ -439,17 +439,17 @@
</intent-filter>
</activity>
- <activity android:name=".vcard.CancelActivity"
+ <activity android:name=".common.vcard.CancelActivity"
android:theme="@style/BackgroundOnlyTheme" />
- <activity android:name=".vcard.SelectAccountActivity"
+ <activity android:name=".common.vcard.SelectAccountActivity"
android:theme="@style/BackgroundOnlyTheme" />
- <activity android:name=".vcard.ExportVCardActivity"
+ <activity android:name=".common.vcard.ExportVCardActivity"
android:theme="@style/BackgroundOnlyTheme" />
<service
- android:name=".vcard.VCardService"
+ android:name=".common.vcard.VCardService"
android:exported="false" />
<!-- Pinned header list demo -->
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index 03fb0dc..a7bde88 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -40,35 +40,6 @@
<!-- Flag indicating whether to show images in browse list -->
<bool name="config_browse_list_show_images">true</bool>
- <!-- The type of vcard for improt. If the vcard importer cannot guess the exact type
- of a vCard type, the improter uses this type. -->
- <string name="config_import_vcard_type" translatable="false">default</string>
-
- <!-- The type of VCard for export. If you want to let the app emit vCard which is
- specific to some vendor (like DoCoMo), specify this type (e.g. "docomo") -->
- <string name="config_export_vcard_type" translatable="false">default</string>
-
- <!-- Prefix of exported VCard file -->
- <string name="config_export_file_prefix" translatable="false"></string>
-
- <!-- Suffix of exported VCard file. Attached before an extension -->
- <string name="config_export_file_suffix" translatable="false"></string>
-
- <!-- Extension for exported VCard files -->
- <string name="config_export_file_extension" translatable="false">vcf</string>
-
- <!-- Minimum number of exported VCard file index -->
- <integer name="config_export_file_min_index">1</integer>
-
- <!-- Maximum number of exported VCard file index -->
- <integer name="config_export_file_max_index">99999</integer>
-
- <!-- The list (separated by ',') of extensions should be checked in addition to
- config_export_extension. e.g. If "aaa" is added to here and 00001.vcf and 00002.aaa
- exist in a target directory, 00003.vcf becomes a next file name candidate.
- Without this configuration, 00002.vcf becomes the candidate.-->
- <string name="config_export_extensions_to_consider" translatable="false"></string>
-
<!-- If true, phonetic name is included in the contact editor by default -->
<bool name="config_editor_include_phonetic_name">false</bool>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 2de327a..b5a230f 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -19,30 +19,10 @@
<item type="id" name="header_phones"/>
<item type="id" name="dialog_sync_add"/>
- <!-- For vcard.ImportVCardActivity -->
- <item type="id" name="dialog_searching_vcard"/>
- <item type="id" name="dialog_sdcard_not_found"/>
- <item type="id" name="dialog_vcard_not_found"/>
- <item type="id" name="dialog_select_import_type"/>
- <item type="id" name="dialog_select_one_vcard"/>
- <item type="id" name="dialog_select_multiple_vcard"/>
- <item type="id" name="dialog_cache_vcard"/>
- <item type="id" name="dialog_io_exception"/>
- <item type="id" name="dialog_error_with_message"/>
-
- <!-- For vcard.CancelActivity -->
- <item type="id" name="dialog_cancel_confirmation"/>
- <item type="id" name="dialog_cancel_failed"/>
-
<!-- For ContactDeletionInteraction -->
<item type="id" name="dialog_delete_contact_confirmation"/>
<item type="id" name="dialog_delete_contact_loader_id" />
- <!-- For ExportVCardActivity -->
- <item type="id" name="dialog_export_confirmation"/>
- <item type="id" name="dialog_exporting_vcard"/>
- <item type="id" name="dialog_fail_to_export_with_reason"/>
-
<!-- For PhoneNumberInteraction -->
<item type="id" name="dialog_phone_number_call_disambiguation"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aadd05c..ada7255 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -541,17 +541,6 @@
-->
<string name="description_plus_button">plus</string>
- <!-- Dialog message shown when (USB) storage does not exist [CHAR LIMIT=30] -->
- <string name="no_sdcard_message" product="nosdcard">No storage was found.</string>
- <!-- Dialog message shown when SDcard does not exist. [CHAR LIMIT=30] -->
- <string name="no_sdcard_message" product="default">No SD card was found.</string>
-
- <!-- Action string for selecting SIM for importing contacts -->
- <string name="import_from_sim">Import from SIM card</string>
-
- <!-- Action string for selecting (USB) storage for importing contacts [CHAR LIMIT=25] -->
- <string name="import_from_sdcard" product="default">Import from storage</string>
-
<!-- Action that exports all contacts to (USB) storage [CHAR LIMIT=25] -->
<string name="export_to_sdcard" product="default">Export to storage</string>
@@ -602,18 +591,6 @@
This may be shown when the vCard is corrupted [CHAR LIMIT=40] -->
<string name="fail_reason_not_supported">The format isn\'t supported.</string>
- <!-- Message used when vCard import has failed. [CHAR LIMIT=40] -->
- <string name="vcard_import_failed">Couldn\'t import vCard.</string>
-
- <!-- The failure message shown when the system could not find any vCard file.
- (with extension ".vcf" in (USB) storage.)
- [CHAR LIMIT=128] -->
- <string name="import_failure_no_vcard_file" product="nosdcard">No vCard file found in storage.</string>
- <!-- The failure message shown when the system could not find any vCard file.
- (with extension ".vcf" in SDCard.)
- [CHAR LIMIT=128] -->
- <string name="import_failure_no_vcard_file" product="default">No vCard file found on the SD card.</string>
-
<!-- Fail reason shown when vCard importer failed to look over meta information stored in vCard file(s). -->
<string name="fail_reason_failed_to_collect_vcard_meta_info">Couldn\'t collect meta information of given vCard file(s).</string>
@@ -621,9 +598,6 @@
files import. It includes the case where all files were failed to be imported. -->
<string name="fail_reason_failed_to_read_files">One or more files couldn\'t be imported (%s).</string>
- <!-- The failed reason which should not be shown but it may in some buggy condition. [CHAR LIMIT=40] -->
- <string name="fail_reason_unknown">Unknown error.</string>
-
<!-- Dialog title shown when a user is asked to select vCard file. [CHAR LIMIT=25] -->
<string name="select_vcard_title">Choose vCard file</string>
@@ -631,81 +605,9 @@
data storage. [CHAR LIMIT=40] -->
<string name="caching_vcard_title">Caching</string>
- <!-- The message shown when vCard importer is caching files to be imported into local temporary
- data storage. [CHAR LIMIT=NONE] -->
- <string name="caching_vcard_message">Caching vCard(s) to local temporary storage. The actual import will start soon.</string>
-
- <!-- The message shown while importing vCard(s).
- First argument is current index of contacts to be imported.
- Second argument is the total number of contacts.
- Third argument is the name of a contact which is being read.
- [CHAR LIMIT=20] -->
- <string name="progress_notifier_message">Importing <xliff:g id="current_number">%s</xliff:g>/<xliff:g id="total_number">%s</xliff:g>: <xliff:g id="name" example="Joe Due">%s</xliff:g></string>
-
- <!-- Description shown when importing vCard data.
- The argument is the name of a contact which is being read.
- [CHAR LIMIT=20] -->
- <string name="importing_vcard_description">Importing <xliff:g id="name" example="Joe Due">%s</xliff:g></string>
-
- <!-- Dialog title shown when reading vCard data failed [CHAR LIMIT=40] -->
- <string name="reading_vcard_failed_title">Couldn\'t read vCard data</string>
-
- <!-- The title shown when reading vCard is canceled (probably by a user)
- [CHAR LIMIT=40] -->
- <string name="reading_vcard_canceled_title">Reading vCard data canceled</string>
-
- <!-- The title shown when reading vCard finished
- The argument is file name the user imported.
- [CHAR LIMIT=40] -->
- <string name="importing_vcard_finished_title">Finished importing vCard <xliff:g id="filename" example="import.vcf">%s</xliff:g></string>
-
- <!-- The title shown when importing vCard is canceled (probably by a user)
- The argument is file name the user canceled importing.
- [CHAR LIMIT=40] -->
- <string name="importing_vcard_canceled_title">Importing <xliff:g id="filename" example="import.vcf">%s</xliff:g> canceled</string>
-
- <!-- The message shown when vCard import request is accepted. The system may start that work soon, or do it later
- when there are already other import/export requests.
- The argument is file name the user imported.
- [CHAR LIMIT=40] -->
- <string name="vcard_import_will_start_message"><xliff:g id="filename" example="import.vcf">%s</xliff:g> will be imported shortly.</string>
- <!-- The message shown when vCard import request is accepted. The system may start that work soon, or do it later when there are already other import/export requests.
- "The file" is what a user selected for importing.
- [CHAR LIMIT=40] -->
- <string name="vcard_import_will_start_message_with_default_name">The file will be imported shortly.</string>
- <!-- The message shown when a given vCard import request is rejected by the system. [CHAR LIMIT=NONE] -->
- <string name="vcard_import_request_rejected_message">vCard import request was rejected. Try again later.</string>
- <!-- The message shown when vCard export request is accepted. The system may start that work soon, or do it later
- when there are already other import/export requests.
- The argument is file name the user exported.
- [CHAR LIMIT=40] -->
- <string name="vcard_export_will_start_message"><xliff:g id="filename" example="import.vcf">%s</xliff:g> will be exported shortly.</string>
- <!-- The message shown when a given vCard export request is rejected by the system. [CHAR LIMIT=NONE] -->
- <string name="vcard_export_request_rejected_message">vCard export request was rejected. Try again later.</string>
- <!-- Used when file name is unknown in vCard processing. It typically happens
- when the file is given outside the Contacts app. [CHAR LIMIT=30] -->
- <string name="vcard_unknown_filename">contact</string>
-
- <!-- The percentage, used for expressing the progress of vCard import/export. -->
- <string name="percentage"><xliff:g id="percentage" example="50">%s</xliff:g><xliff:g id="percentsign" example="%">%%</xliff:g></string>
-
<!-- Dialog title shown when a user confirms whether he/she export Contact data. [CHAR LIMIT=32] -->
<string name="confirm_export_title">Export contacts?</string>
- <!-- Dialog message shown when a user confirms whether he/she export Contact data [CHAR LIMIT=NONE] -->
- <string name="confirm_export_message">Your contact list will be exported to file: <xliff:g id="vcard_filename">%s</xliff:g>.</string>
-
- <!-- Dialog title shown when exporting Contact data failed. [CHAR LIMIT=20] -->
- <string name="exporting_contact_failed_title">Couldn\'t export</string>
-
- <!-- Dialog message shown when exporting Contact data failed. [CHAR LIMIT=NONE] -->
- <string name="exporting_contact_failed_message">The contact data wasn\'t exported.\nReason: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
-
- <!-- The failed reason shown when there's no contact which is allowed to be exported.
- Note that user may have contacts data but all of them are probably not allowed to be
- exported because of security/permission reasons. [CHAR LIMIT=NONE] -->
- <string name="fail_reason_no_exportable_contact">There is no exportable contact.</string>
-
<!-- The failed reason shown when vCard exporter could not create a file for the vCard since
there are too many files relevant to vCard. [CHAR LIMIT=NONE] -->
<string name="fail_reason_too_many_vcard" product="nosdcard">Too many vCard files are in the storage.</string>
@@ -718,66 +620,9 @@
mention it here. [CHAR LIMIT=NONE] -->
<string name="fail_reason_too_long_filename">Required filename is too long (\"<xliff:g id="filename">%s</xliff:g>\").</string>
- <!-- The title shown when exporting vCard is successfuly finished [CHAR LIMIT=40] -->
- <string name="exporting_vcard_finished_title">Finished exporting <xliff:g id="filename" example="export.vcf">%s</xliff:g>.</string>
-
- <!-- The title shown when exporting vCard is canceled (probably by a user)
- The argument is file name the user canceled importing.
- [CHAR LIMIT=40] -->
- <string name="exporting_vcard_canceled_title">Exporting <xliff:g id="filename" example="export.vcf">%s</xliff:g> canceled.</string>
-
- <!-- Dialog title shown when the application is exporting contact data outside. [CHAR LIMIT=NONE] -->
- <string name="exporting_contact_list_title">Exporting contact data</string>
-
- <!-- Message shown when the application is exporting contact data outside -->
- <string name="exporting_contact_list_message">Your contact data is being exported to: <xliff:g id="file_name">%s</xliff:g>.</string>
-
- <!-- The failed reason shown when contacts exporter fails to be initialized.
- Some exact reason must follow this. [CHAR LIMIT=NONE]-->
- <string name="fail_reason_could_not_initialize_exporter">Couldn\'t start the exporter: \"<xliff:g id="exact_reason">%s</xliff:g>\".</string>
-
- <!-- The failed reason shown when some error happend during contacts export.
- Some exact reason must follow this. [CHAR LIMIT=NONE] -->
- <string name="fail_reason_error_occurred_during_export">An error occurred during export: \"<xliff:g id="exact_reason">%s</xliff:g>\".</string>
-
- <!-- The error reason the vCard composer "may" emit when database is corrupted or
- something is going wrong. Usually users should not see this text. [CHAR LIMIT=NONE] -->
- <string name="composer_failed_to_get_database_infomation">Couldn\'t get database information.</string>
-
- <!-- This error message shown when the user actually have no contact
- (e.g. just after data-wiping), or, data providers of the contact list prohibits their
- contacts from being exported to outside world via vcard exporter, etc. [CHAR LIMIT=NONE] -->
- <string name="composer_has_no_exportable_contact" product="tablet">There are no exportable contacts. If you do have contacts on your tablet, some data providers may not allow the contacts to be exported from the tablet.</string>
- <!-- This error message shown when the user actually have no contact
- (e.g. just after data-wiping), or, data providers of the contact list prohibits their
- contacts from being exported to outside world via vcard exporter, etc. [CHAR LIMIT=NONE] -->
- <string name="composer_has_no_exportable_contact" product="default">There are no exportable contacts. If you do have contacts on your phone, some data providers may not allow the contacts to be exported from the phone.</string>
-
- <!-- The error reason the vCard composer may emit when vCard composer is not initialized
- even when needed.
- Users should not usually see this error message. [CHAR LIMIT=NONE] -->
- <string name="composer_not_initialized">The vCard composer didn\'t start properly.</string>
-
- <!-- The failed reason shown when vCard importer/exporter could not open the file
- specified by a user. The file name should be in the message. [CHAR LIMIT=NONE] -->
- <string name="fail_reason_could_not_open_file">Couldn\'t open \"<xliff:g id="file_name">%s</xliff:g>\": <xliff:g id="exact_reason">%s</xliff:g>.</string>
-
<!-- Message in progress bar while exporting contact list to a file "(current number) of (total number) contacts" The order of "current number" and "total number" cannot be changed (like "total: (total number), current: (current number)")-->
<string name="exporting_contact_list_progress"><xliff:g id="current_number">%s</xliff:g> of <xliff:g id="total_number">%s</xliff:g> contacts</string>
- <!-- Message shown in a Dialog confirming a user's cancel request toward existing vCard import.
- The argument is file name for the vCard import the user wants to cancel.
- [CHAR LIMIT=128] -->
- <string name="cancel_import_confirmation_message">Cancel import of <xliff:g id="filename" example="import.vcf">%s</xliff:g>?</string>
-
- <!-- Message shown in a Dialog confirming a user's cancel request toward existing vCard export.
- The argument is file name for the vCard export the user wants to cancel.
- [CHAR LIMIT=128] -->
- <string name="cancel_export_confirmation_message">Cancel export of <xliff:g id="filename" example="export.vcf">%s</xliff:g>?</string>
-
- <!-- Title shown in a Dialog telling users cancel vCard import/export operation is failed. [CHAR LIMIT=40] -->
- <string name="cancel_vcard_import_or_export_failed">Couldn\'t cancel vCard import/export</string>
-
<!-- The string used to describe Contacts as a searchable item within system search settings. -->
<string name="search_settings_description">Names of your contacts</string>
@@ -819,8 +664,6 @@
<!-- Toast indicating that sharing a contact has failed. [CHAR LIMIT=NONE] -->
<string name="share_error">This contact can\'t be shared.</string>
- <string name="dialog_new_contact_account">Create contact under account</string>
-
<!-- Title for the disambiguation dialog that requests the user choose an account for the new group to be created under [CHAR LIMIT=NONE] -->
<string name="dialog_new_group_account">Create group under account</string>
@@ -1116,9 +959,6 @@
<!-- Hint text in the group name box in the edit group view. [CHAR LIMIT=20]-->
<string name="group_name_hint">Group\'s name</string>
- <!-- The "file name" displayed for vCards received directly via NFC [CHAR LIMIT=16] -->
- <string name="nfc_vcard_file_name">Contact received over NFC</string>
-
<!-- Menu item used to show only outgoing in the call log. [CHAR LIMIT=30] -->
<string name="menu_show_outgoing_only">Show outgoing only</string>
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index 99b3463..b360271 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -41,10 +41,10 @@
import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.util.AccountSelectionUtil;
+import com.android.contacts.common.util.AccountSelectionUtil;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
-import com.android.contacts.vcard.ExportVCardActivity;
-import com.android.contacts.vcard.VCardCommonArguments;
+import com.android.contacts.common.vcard.ExportVCardActivity;
+import com.android.contacts.common.vcard.VCardCommonArguments;
import java.util.List;
diff --git a/src/com/android/contacts/util/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
deleted file mode 100644
index 1d456b3..0000000
--- a/src/com/android/contacts/util/AccountSelectionUtil.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.util;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.TextView;
-
-import com.android.contacts.R;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-
-import java.util.List;
-
-/**
- * Utility class for selectiong an Account for importing contact(s)
- */
-public class AccountSelectionUtil {
- // TODO: maybe useful for EditContactActivity.java...
- private static final String LOG_TAG = "AccountSelectionUtil";
-
- public static boolean mVCardShare = false;
-
- public static Uri mPath;
-
- public static class AccountSelectedListener
- implements DialogInterface.OnClickListener {
-
- final private Context mContext;
- final private int mResId;
-
- final protected List<AccountWithDataSet> mAccountList;
-
- public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
- int resId) {
- if (accountList == null || accountList.size() == 0) {
- Log.e(LOG_TAG, "The size of Account list is 0.");
- }
- mContext = context;
- mAccountList = accountList;
- mResId = resId;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- doImport(mContext, mResId, mAccountList.get(which));
- }
- }
-
- public static Dialog getSelectAccountDialog(Context context, int resId) {
- return getSelectAccountDialog(context, resId, null, null);
- }
-
- public static Dialog getSelectAccountDialog(Context context, int resId,
- DialogInterface.OnClickListener onClickListener) {
- return getSelectAccountDialog(context, resId, onClickListener, null);
- }
-
- /**
- * When OnClickListener or OnCancelListener is null, uses a default listener.
- * The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
- */
- public static Dialog getSelectAccountDialog(Context context, int resId,
- DialogInterface.OnClickListener onClickListener,
- DialogInterface.OnCancelListener onCancelListener) {
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
- final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
-
- Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
-
- // Assume accountList.size() > 1
-
- // Wrap our context to inflate list items using correct theme
- final Context dialogContext = new ContextThemeWrapper(
- context, android.R.style.Theme_Light);
- final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- final ArrayAdapter<AccountWithDataSet> accountAdapter =
- new ArrayAdapter<AccountWithDataSet>(context, android.R.layout.simple_list_item_2,
- writableAccountList) {
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = dialogInflater.inflate(
- android.R.layout.simple_list_item_2,
- parent, false);
- }
-
- // TODO: show icon along with title
- final TextView text1 =
- (TextView)convertView.findViewById(android.R.id.text1);
- final TextView text2 =
- (TextView)convertView.findViewById(android.R.id.text2);
-
- final AccountWithDataSet account = this.getItem(position);
- final AccountType accountType = accountTypes.getAccountType(
- account.type, account.dataSet);
- final Context context = getContext();
-
- text1.setText(account.name);
- text2.setText(accountType.getDisplayLabel(context));
-
- return convertView;
- }
- };
-
- if (onClickListener == null) {
- AccountSelectedListener accountSelectedListener =
- new AccountSelectedListener(context, writableAccountList, resId);
- onClickListener = accountSelectedListener;
- }
- if (onCancelListener == null) {
- onCancelListener = new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- dialog.dismiss();
- }
- };
- }
- return new AlertDialog.Builder(context)
- .setTitle(R.string.dialog_new_contact_account)
- .setSingleChoiceItems(accountAdapter, 0, onClickListener)
- .setOnCancelListener(onCancelListener)
- .create();
- }
-
- public static void doImport(Context context, int resId, AccountWithDataSet account) {
- switch (resId) {
- case R.string.import_from_sim: {
- doImportFromSim(context, account);
- break;
- }
- case R.string.import_from_sdcard: {
- doImportFromSdCard(context, account);
- break;
- }
- }
- }
-
- public static void doImportFromSim(Context context, AccountWithDataSet account) {
- Intent importIntent = new Intent(Intent.ACTION_VIEW);
- importIntent.setType("vnd.android.cursor.item/sim-contact");
- if (account != null) {
- importIntent.putExtra("account_name", account.name);
- importIntent.putExtra("account_type", account.type);
- importIntent.putExtra("data_set", account.dataSet);
- }
- importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
- context.startActivity(importIntent);
- }
-
- public static void doImportFromSdCard(Context context, AccountWithDataSet account) {
- Intent importIntent = new Intent(context,
- com.android.contacts.vcard.ImportVCardActivity.class);
- if (account != null) {
- importIntent.putExtra("account_name", account.name);
- importIntent.putExtra("account_type", account.type);
- importIntent.putExtra("data_set", account.dataSet);
- }
-
- if (mVCardShare) {
- importIntent.setAction(Intent.ACTION_VIEW);
- importIntent.setData(mPath);
- }
- mVCardShare = false;
- mPath = null;
- context.startActivity(importIntent);
- }
-}
diff --git a/src/com/android/contacts/vcard/CancelActivity.java b/src/com/android/contacts/vcard/CancelActivity.java
deleted file mode 100644
index ff8512b..0000000
--- a/src/com/android/contacts/vcard/CancelActivity.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-
-import com.android.contacts.R;
-
-/**
- * The Activity for canceling vCard import/export.
- */
-public class CancelActivity extends Activity implements ServiceConnection {
- private final String LOG_TAG = "VCardCancel";
-
- /* package */ final static String JOB_ID = "job_id";
- /* package */ final static String DISPLAY_NAME = "display_name";
-
- /**
- * Type of the process to be canceled. Only used for choosing appropriate title/message.
- * Must be {@link VCardService#TYPE_IMPORT} or {@link VCardService#TYPE_EXPORT}.
- */
- /* package */ final static String TYPE = "type";
-
- private class RequestCancelListener implements DialogInterface.OnClickListener {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- bindService(new Intent(CancelActivity.this,
- VCardService.class), CancelActivity.this, Context.BIND_AUTO_CREATE);
- }
- }
-
- private class CancelListener
- implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- @Override
- public void onCancel(DialogInterface dialog) {
- finish();
- }
- }
-
- private final CancelListener mCancelListener = new CancelListener();
- private int mJobId;
- private String mDisplayName;
- private int mType;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final Uri uri = getIntent().getData();
- mJobId = Integer.parseInt(uri.getQueryParameter(JOB_ID));
- mDisplayName = uri.getQueryParameter(DISPLAY_NAME);
- mType = Integer.parseInt(uri.getQueryParameter(TYPE));
- showDialog(R.id.dialog_cancel_confirmation);
- }
-
- @Override
- protected Dialog onCreateDialog(int id, Bundle bundle) {
- switch (id) {
- case R.id.dialog_cancel_confirmation: {
- final String message;
- if (mType == VCardService.TYPE_IMPORT) {
- message = getString(R.string.cancel_import_confirmation_message, mDisplayName);
- } else {
- message = getString(R.string.cancel_export_confirmation_message, mDisplayName);
- }
- final AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, new RequestCancelListener())
- .setOnCancelListener(mCancelListener)
- .setNegativeButton(android.R.string.cancel, mCancelListener);
- return builder.create();
- }
- case R.id.dialog_cancel_failed:
- final AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.cancel_vcard_import_or_export_failed)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(getString(R.string.fail_reason_unknown))
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- return builder.create();
- default:
- Log.w(LOG_TAG, "Unknown dialog id: " + id);
- break;
- }
- return super.onCreateDialog(id, bundle);
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- VCardService service = ((VCardService.MyBinder) binder).getService();
-
- try {
- final CancelRequest request = new CancelRequest(mJobId, mDisplayName);
- service.handleCancelRequest(request, null);
- } finally {
- unbindService(this);
- }
-
- finish();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // do nothing
- }
-}
diff --git a/src/com/android/contacts/vcard/CancelRequest.java b/src/com/android/contacts/vcard/CancelRequest.java
deleted file mode 100644
index 85893ba..0000000
--- a/src/com/android/contacts/vcard/CancelRequest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-/**
- * Class representing one request for canceling vCard import/export.
- */
-public class CancelRequest {
- public final int jobId;
- /**
- * Name used for showing users some useful info. Typically a file name.
- * Must not be used to do some actual operations.
- */
- public final String displayName;
- public CancelRequest(int jobId, String displayName) {
- this.jobId = jobId;
- this.displayName = displayName;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/vcard/ExportProcessor.java b/src/com/android/contacts/vcard/ExportProcessor.java
deleted file mode 100644
index 6063629..0000000
--- a/src/com/android/contacts/vcard/ExportProcessor.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContactsEntity;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.contacts.R;
-import com.android.vcard.VCardComposer;
-import com.android.vcard.VCardConfig;
-
-import java.io.BufferedWriter;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-/**
- * Class for processing one export request from a user. Dropped after exporting requested Uri(s).
- * {@link VCardService} will create another object when there is another export request.
- */
-public class ExportProcessor extends ProcessorBase {
- private static final String LOG_TAG = "VCardExport";
- private static final boolean DEBUG = VCardService.DEBUG;
-
- private final VCardService mService;
- private final ContentResolver mResolver;
- private final NotificationManager mNotificationManager;
- private final ExportRequest mExportRequest;
- private final int mJobId;
- private final String mCallingActivity;
-
-
- private volatile boolean mCanceled;
- private volatile boolean mDone;
-
- public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId,
- String callingActivity) {
- mService = service;
- mResolver = service.getContentResolver();
- mNotificationManager =
- (NotificationManager)mService.getSystemService(Context.NOTIFICATION_SERVICE);
- mExportRequest = exportRequest;
- mJobId = jobId;
- mCallingActivity = callingActivity;
- }
-
- @Override
- public final int getType() {
- return VCardService.TYPE_EXPORT;
- }
-
- @Override
- public void run() {
- // ExecutorService ignores RuntimeException, so we need to show it here.
- try {
- runInternal();
-
- if (isCancelled()) {
- doCancelNotification();
- }
- } catch (OutOfMemoryError e) {
- Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
- throw e;
- } catch (RuntimeException e) {
- Log.e(LOG_TAG, "RuntimeException thrown during export", e);
- throw e;
- } finally {
- synchronized (this) {
- mDone = true;
- }
- }
- }
-
- private void runInternal() {
- if (DEBUG) Log.d(LOG_TAG, String.format("vCard export (id: %d) has started.", mJobId));
- final ExportRequest request = mExportRequest;
- VCardComposer composer = null;
- Writer writer = null;
- boolean successful = false;
- try {
- if (isCancelled()) {
- Log.i(LOG_TAG, "Export request is cancelled before handling the request");
- return;
- }
- final Uri uri = request.destUri;
- final OutputStream outputStream;
- try {
- outputStream = mResolver.openOutputStream(uri);
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "FileNotFoundException thrown", e);
- // Need concise title.
-
- final String errorReason =
- mService.getString(R.string.fail_reason_could_not_open_file,
- uri, e.getMessage());
- doFinishNotification(errorReason, null);
- return;
- }
-
- final String exportType = request.exportType;
- final int vcardType;
- if (TextUtils.isEmpty(exportType)) {
- vcardType = VCardConfig.getVCardTypeFromString(
- mService.getString(R.string.config_export_vcard_type));
- } else {
- vcardType = VCardConfig.getVCardTypeFromString(exportType);
- }
-
- composer = new VCardComposer(mService, vcardType, true);
-
- // for test
- // int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC |
- // VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
- // composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);
-
- writer = new BufferedWriter(new OutputStreamWriter(outputStream));
- final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI.buildUpon()
- .appendQueryParameter(RawContactsEntity.FOR_EXPORT_ONLY, "1")
- .build();
- // TODO: should provide better selection.
- if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID},
- null, null,
- null, contentUriForRawContactsEntity)) {
- final String errorReason = composer.getErrorReason();
- Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
- final String translatedErrorReason =
- translateComposerError(errorReason);
- final String title =
- mService.getString(R.string.fail_reason_could_not_initialize_exporter,
- translatedErrorReason);
- doFinishNotification(title, null);
- return;
- }
-
- final int total = composer.getCount();
- if (total == 0) {
- final String title =
- mService.getString(R.string.fail_reason_no_exportable_contact);
- doFinishNotification(title, null);
- return;
- }
-
- int current = 1; // 1-origin
- while (!composer.isAfterLast()) {
- if (isCancelled()) {
- Log.i(LOG_TAG, "Export request is cancelled during composing vCard");
- return;
- }
- try {
- writer.write(composer.createOneEntry());
- } catch (IOException e) {
- final String errorReason = composer.getErrorReason();
- Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
- final String translatedErrorReason =
- translateComposerError(errorReason);
- final String title =
- mService.getString(R.string.fail_reason_error_occurred_during_export,
- translatedErrorReason);
- doFinishNotification(title, null);
- return;
- }
-
- // vCard export is quite fast (compared to import), and frequent notifications
- // bother notification bar too much.
- if (current % 100 == 1) {
- doProgressNotification(uri, total, current);
- }
- current++;
- }
- Log.i(LOG_TAG, "Successfully finished exporting vCard " + request.destUri);
-
- if (DEBUG) {
- Log.d(LOG_TAG, "Ask MediaScanner to scan the file: " + request.destUri.getPath());
- }
- mService.updateMediaScanner(request.destUri.getPath());
-
- successful = true;
- final String filename = uri.getLastPathSegment();
- final String title = mService.getString(R.string.exporting_vcard_finished_title,
- filename);
- doFinishNotification(title, null);
- } finally {
- if (composer != null) {
- composer.terminate();
- }
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- Log.w(LOG_TAG, "IOException is thrown during close(). Ignored. " + e);
- }
- }
- mService.handleFinishExportNotification(mJobId, successful);
- }
- }
-
- private String translateComposerError(String errorMessage) {
- final Resources resources = mService.getResources();
- if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) {
- return resources.getString(R.string.composer_failed_to_get_database_infomation);
- } else if (VCardComposer.FAILURE_REASON_NO_ENTRY.equals(errorMessage)) {
- return resources.getString(R.string.composer_has_no_exportable_contact);
- } else if (VCardComposer.FAILURE_REASON_NOT_INITIALIZED.equals(errorMessage)) {
- return resources.getString(R.string.composer_not_initialized);
- } else {
- return errorMessage;
- }
- }
-
- private void doProgressNotification(Uri uri, int totalCount, int currentCount) {
- final String displayName = uri.getLastPathSegment();
- final String description =
- mService.getString(R.string.exporting_contact_list_message, displayName);
- final String tickerText =
- mService.getString(R.string.exporting_contact_list_title);
- final Notification notification =
- NotificationImportExportListener.constructProgressNotification(mService,
- VCardService.TYPE_EXPORT, description, tickerText, mJobId, displayName,
- totalCount, currentCount);
- mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
- mJobId, notification);
- }
-
- private void doCancelNotification() {
- if (DEBUG) Log.d(LOG_TAG, "send cancel notification");
- final String description = mService.getString(R.string.exporting_vcard_canceled_title,
- mExportRequest.destUri.getLastPathSegment());
- final Notification notification =
- NotificationImportExportListener.constructCancelNotification(mService, description);
- mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
- mJobId, notification);
- }
-
- private void doFinishNotification(final String title, final String description) {
- if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
- final Intent intent = new Intent();
- intent.setClassName(mService, mCallingActivity);
- final Notification notification =
- NotificationImportExportListener.constructFinishNotification(mService, title,
- description, intent);
- mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
- mJobId, notification);
- }
-
- @Override
- public synchronized boolean cancel(boolean mayInterruptIfRunning) {
- if (DEBUG) Log.d(LOG_TAG, "received cancel request");
- if (mDone || mCanceled) {
- return false;
- }
- mCanceled = true;
- return true;
- }
-
- @Override
- public synchronized boolean isCancelled() {
- return mCanceled;
- }
-
- @Override
- public synchronized boolean isDone() {
- return mDone;
- }
-
- public ExportRequest getRequest() {
- return mExportRequest;
- }
-}
diff --git a/src/com/android/contacts/vcard/ExportRequest.java b/src/com/android/contacts/vcard/ExportRequest.java
deleted file mode 100644
index fae2d07..0000000
--- a/src/com/android/contacts/vcard/ExportRequest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.net.Uri;
-
-public class ExportRequest {
- public final Uri destUri;
- /**
- * Can be null.
- */
- public final String exportType;
-
- public ExportRequest(Uri destUri) {
- this(destUri, null);
- }
-
- public ExportRequest(Uri destUri, String exportType) {
- this.destUri = destUri;
- this.exportType = exportType;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/vcard/ExportVCardActivity.java b/src/com/android/contacts/vcard/ExportVCardActivity.java
deleted file mode 100644
index 29ffc4c..0000000
--- a/src/com/android/contacts/vcard/ExportVCardActivity.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.contacts.R;
-
-import java.io.File;
-
-/**
- * Shows a dialog confirming the export and asks actual vCard export to {@link VCardService}
- *
- * This Activity first connects to VCardService and ask an available file name and shows it to
- * a user. After the user's confirmation, it send export request with the file name, assuming the
- * file name is not reserved yet.
- */
-public class ExportVCardActivity extends Activity implements ServiceConnection,
- DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
- private static final String LOG_TAG = "VCardExport";
- private static final boolean DEBUG = VCardService.DEBUG;
-
- /**
- * Handler used when some Message has come from {@link VCardService}.
- */
- private class IncomingHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- if (DEBUG) Log.d(LOG_TAG, "IncomingHandler received message.");
-
- if (msg.arg1 != 0) {
- Log.i(LOG_TAG, "Message returned from vCard server contains error code.");
- if (msg.obj != null) {
- mErrorReason = (String)msg.obj;
- }
- showDialog(msg.arg1);
- return;
- }
-
- switch (msg.what) {
- case VCardService.MSG_SET_AVAILABLE_EXPORT_DESTINATION:
- if (msg.obj == null) {
- Log.w(LOG_TAG, "Message returned from vCard server doesn't contain valid path");
- mErrorReason = getString(R.string.fail_reason_unknown);
- showDialog(R.id.dialog_fail_to_export_with_reason);
- } else {
- mTargetFileName = (String)msg.obj;
- if (TextUtils.isEmpty(mTargetFileName)) {
- Log.w(LOG_TAG, "Destination file name coming from vCard service is empty.");
- mErrorReason = getString(R.string.fail_reason_unknown);
- showDialog(R.id.dialog_fail_to_export_with_reason);
- } else {
- if (DEBUG) {
- Log.d(LOG_TAG,
- String.format("Target file name is set (%s). " +
- "Show confirmation dialog", mTargetFileName));
- }
- showDialog(R.id.dialog_export_confirmation);
- }
- }
- break;
- default:
- Log.w(LOG_TAG, "Unknown message type: " + msg.what);
- super.handleMessage(msg);
- }
- }
- }
-
- /**
- * True when this Activity is connected to {@link VCardService}.
- *
- * Should be touched inside synchronized block.
- */
- private boolean mConnected;
-
- /**
- * True when users need to do something and this Activity should not disconnect from
- * VCardService. False when all necessary procedures are done (including sending export request)
- * or there's some error occured.
- */
- private volatile boolean mProcessOngoing = true;
-
- private VCardService mService;
- private final Messenger mIncomingMessenger = new Messenger(new IncomingHandler());
-
- // Used temporarily when asking users to confirm the file name
- private String mTargetFileName;
-
- // String for storing error reason temporarily.
- private String mErrorReason;
-
- private class ExportConfirmationListener implements DialogInterface.OnClickListener {
- private final Uri mDestinationUri;
-
- public ExportConfirmationListener(String path) {
- this(Uri.parse("file://" + path));
- }
-
- public ExportConfirmationListener(Uri uri) {
- mDestinationUri = uri;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- if (DEBUG) {
- Log.d(LOG_TAG,
- String.format("Try sending export request (uri: %s)", mDestinationUri));
- }
- final ExportRequest request = new ExportRequest(mDestinationUri);
- // The connection object will call finish().
- mService.handleExportRequest(request, new NotificationImportExportListener(
- ExportVCardActivity.this));
- }
- unbindAndFinish();
- }
- }
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
-
- // Check directory is available.
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- Log.w(LOG_TAG, "External storage is in state " + Environment.getExternalStorageState() +
- ". Cancelling export");
- showDialog(R.id.dialog_sdcard_not_found);
- return;
- }
-
- final File targetDirectory = Environment.getExternalStorageDirectory();
- if (!(targetDirectory.exists() &&
- targetDirectory.isDirectory() &&
- targetDirectory.canRead()) &&
- !targetDirectory.mkdirs()) {
- showDialog(R.id.dialog_sdcard_not_found);
- return;
- }
-
- final String callingActivity = getIntent().getExtras()
- .getString(VCardCommonArguments.ARG_CALLING_ACTIVITY);
- Intent intent = new Intent(this, VCardService.class);
- intent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity);
-
- if (startService(intent) == null) {
- Log.e(LOG_TAG, "Failed to start vCard service");
- mErrorReason = getString(R.string.fail_reason_unknown);
- showDialog(R.id.dialog_fail_to_export_with_reason);
- return;
- }
-
- if (!bindService(intent, this, Context.BIND_AUTO_CREATE)) {
- Log.e(LOG_TAG, "Failed to connect to vCard service.");
- mErrorReason = getString(R.string.fail_reason_unknown);
- showDialog(R.id.dialog_fail_to_export_with_reason);
- }
- // Continued to onServiceConnected()
- }
-
- @Override
- public synchronized void onServiceConnected(ComponentName name, IBinder binder) {
- if (DEBUG) Log.d(LOG_TAG, "connected to service, requesting a destination file name");
- mConnected = true;
- mService = ((VCardService.MyBinder) binder).getService();
- mService.handleRequestAvailableExportDestination(mIncomingMessenger);
- // Wait until MSG_SET_AVAILABLE_EXPORT_DESTINATION message is available.
- }
-
- // Use synchronized since we don't want to call unbindAndFinish() just after this call.
- @Override
- public synchronized void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.d(LOG_TAG, "onServiceDisconnected()");
- mService = null;
- mConnected = false;
- if (mProcessOngoing) {
- // Unexpected disconnect event.
- Log.w(LOG_TAG, "Disconnected from service during the process ongoing.");
- mErrorReason = getString(R.string.fail_reason_unknown);
- showDialog(R.id.dialog_fail_to_export_with_reason);
- }
- }
-
- @Override
- protected Dialog onCreateDialog(int id, Bundle bundle) {
- switch (id) {
- case R.id.dialog_export_confirmation: {
- return new AlertDialog.Builder(this)
- .setTitle(R.string.confirm_export_title)
- .setMessage(getString(R.string.confirm_export_message, mTargetFileName))
- .setPositiveButton(android.R.string.ok,
- new ExportConfirmationListener(mTargetFileName))
- .setNegativeButton(android.R.string.cancel, this)
- .setOnCancelListener(this)
- .create();
- }
- case R.string.fail_reason_too_many_vcard: {
- mProcessOngoing = false;
- return new AlertDialog.Builder(this)
- .setTitle(R.string.exporting_contact_failed_title)
- .setMessage(getString(R.string.exporting_contact_failed_message,
- getString(R.string.fail_reason_too_many_vcard)))
- .setPositiveButton(android.R.string.ok, this)
- .create();
- }
- case R.id.dialog_fail_to_export_with_reason: {
- mProcessOngoing = false;
- return new AlertDialog.Builder(this)
- .setTitle(R.string.exporting_contact_failed_title)
- .setMessage(getString(R.string.exporting_contact_failed_message,
- mErrorReason != null ? mErrorReason :
- getString(R.string.fail_reason_unknown)))
- .setPositiveButton(android.R.string.ok, this)
- .setOnCancelListener(this)
- .create();
- }
- case R.id.dialog_sdcard_not_found: {
- mProcessOngoing = false;
- return new AlertDialog.Builder(this)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(R.string.no_sdcard_message)
- .setPositiveButton(android.R.string.ok, this).create();
- }
- }
- return super.onCreateDialog(id, bundle);
- }
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
- if (id == R.id.dialog_fail_to_export_with_reason) {
- ((AlertDialog)dialog).setMessage(mErrorReason);
- } else if (id == R.id.dialog_export_confirmation) {
- ((AlertDialog)dialog).setMessage(
- getString(R.string.confirm_export_message, mTargetFileName));
- } else {
- super.onPrepareDialog(id, dialog, args);
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- if (!isFinishing()) {
- unbindAndFinish();
- }
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onClick() is called");
- unbindAndFinish();
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onCancel() is called");
- mProcessOngoing = false;
- unbindAndFinish();
- }
-
- @Override
- public void unbindService(ServiceConnection conn) {
- mProcessOngoing = false;
- super.unbindService(conn);
- }
-
- private synchronized void unbindAndFinish() {
- if (mConnected) {
- unbindService(this);
- mConnected = false;
- }
- finish();
- }
-}
diff --git a/src/com/android/contacts/vcard/ImportProcessor.java b/src/com/android/contacts/vcard/ImportProcessor.java
deleted file mode 100644
index a2e8a48..0000000
--- a/src/com/android/contacts/vcard/ImportProcessor.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.accounts.Account;
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.util.Log;
-
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryCommitter;
-import com.android.vcard.VCardEntryConstructor;
-import com.android.vcard.VCardEntryHandler;
-import com.android.vcard.VCardInterpreter;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardNestedException;
-import com.android.vcard.exception.VCardNotSupportedException;
-import com.android.vcard.exception.VCardVersionException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class for processing one import request from a user. Dropped after importing requested Uri(s).
- * {@link VCardService} will create another object when there is another import request.
- */
-public class ImportProcessor extends ProcessorBase implements VCardEntryHandler {
- private static final String LOG_TAG = "VCardImport";
- private static final boolean DEBUG = VCardService.DEBUG;
-
- private final VCardService mService;
- private final ContentResolver mResolver;
- private final ImportRequest mImportRequest;
- private final int mJobId;
- private final VCardImportExportListener mListener;
-
- // TODO: remove and show appropriate message instead.
- private final List<Uri> mFailedUris = new ArrayList<Uri>();
-
- private VCardParser mVCardParser;
-
- private volatile boolean mCanceled;
- private volatile boolean mDone;
-
- private int mCurrentCount = 0;
- private int mTotalCount = 0;
-
- public ImportProcessor(final VCardService service, final VCardImportExportListener listener,
- final ImportRequest request, final int jobId) {
- mService = service;
- mResolver = mService.getContentResolver();
- mListener = listener;
-
- mImportRequest = request;
- mJobId = jobId;
- }
-
- @Override
- public void onStart() {
- // do nothing
- }
-
- @Override
- public void onEnd() {
- // do nothing
- }
-
- @Override
- public void onEntryCreated(VCardEntry entry) {
- mCurrentCount++;
- if (mListener != null) {
- mListener.onImportParsed(mImportRequest, mJobId, entry, mCurrentCount, mTotalCount);
- }
- }
-
- @Override
- public final int getType() {
- return VCardService.TYPE_IMPORT;
- }
-
- @Override
- public void run() {
- // ExecutorService ignores RuntimeException, so we need to show it here.
- try {
- runInternal();
-
- if (isCancelled() && mListener != null) {
- mListener.onImportCanceled(mImportRequest, mJobId);
- }
- } catch (OutOfMemoryError e) {
- Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
- throw e;
- } catch (RuntimeException e) {
- Log.e(LOG_TAG, "RuntimeException thrown during import", e);
- throw e;
- } finally {
- synchronized (this) {
- mDone = true;
- }
- }
- }
-
- private void runInternal() {
- Log.i(LOG_TAG, String.format("vCard import (id: %d) has started.", mJobId));
- final ImportRequest request = mImportRequest;
- if (isCancelled()) {
- Log.i(LOG_TAG, "Canceled before actually handling parameter (" + request.uri + ")");
- return;
- }
- final int[] possibleVCardVersions;
- if (request.vcardVersion == ImportVCardActivity.VCARD_VERSION_AUTO_DETECT) {
- /**
- * Note: this code assumes that a given Uri is able to be opened more than once,
- * which may not be true in certain conditions.
- */
- possibleVCardVersions = new int[] {
- ImportVCardActivity.VCARD_VERSION_V21,
- ImportVCardActivity.VCARD_VERSION_V30
- };
- } else {
- possibleVCardVersions = new int[] {
- request.vcardVersion
- };
- }
-
- final Uri uri = request.uri;
- final Account account = request.account;
- final int estimatedVCardType = request.estimatedVCardType;
- final String estimatedCharset = request.estimatedCharset;
- final int entryCount = request.entryCount;
- mTotalCount += entryCount;
-
- final VCardEntryConstructor constructor =
- new VCardEntryConstructor(estimatedVCardType, account, estimatedCharset);
- final VCardEntryCommitter committer = new VCardEntryCommitter(mResolver);
- constructor.addEntryHandler(committer);
- constructor.addEntryHandler(this);
-
- InputStream is = null;
- boolean successful = false;
- try {
- if (uri != null) {
- Log.i(LOG_TAG, "start importing one vCard (Uri: " + uri + ")");
- is = mResolver.openInputStream(uri);
- } else if (request.data != null){
- Log.i(LOG_TAG, "start importing one vCard (byte[])");
- is = new ByteArrayInputStream(request.data);
- }
-
- if (is != null) {
- successful = readOneVCard(is, estimatedVCardType, estimatedCharset, constructor,
- possibleVCardVersions);
- }
- } catch (IOException e) {
- successful = false;
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- mService.handleFinishImportNotification(mJobId, successful);
-
- if (successful) {
- // TODO: successful becomes true even when cancelled. Should return more appropriate
- // value
- if (isCancelled()) {
- Log.i(LOG_TAG, "vCard import has been canceled (uri: " + uri + ")");
- // Cancel notification will be done outside this method.
- } else {
- Log.i(LOG_TAG, "Successfully finished importing one vCard file: " + uri);
- List<Uri> uris = committer.getCreatedUris();
- if (mListener != null) {
- if (uris != null && uris.size() > 0) {
- // TODO: construct intent showing a list of imported contact list.
- mListener.onImportFinished(mImportRequest, mJobId, uris.get(0));
- } else {
- // Not critical, but suspicious.
- Log.w(LOG_TAG,
- "Created Uris is null or 0 length " +
- "though the creation itself is successful.");
- mListener.onImportFinished(mImportRequest, mJobId, null);
- }
- }
- }
- } else {
- Log.w(LOG_TAG, "Failed to read one vCard file: " + uri);
- mFailedUris.add(uri);
- }
- }
-
- private boolean readOneVCard(InputStream is, int vcardType, String charset,
- final VCardInterpreter interpreter,
- final int[] possibleVCardVersions) {
- boolean successful = false;
- final int length = possibleVCardVersions.length;
- for (int i = 0; i < length; i++) {
- final int vcardVersion = possibleVCardVersions[i];
- try {
- if (i > 0 && (interpreter instanceof VCardEntryConstructor)) {
- // Let the object clean up internal temporary objects,
- ((VCardEntryConstructor) interpreter).clear();
- }
-
- // We need synchronized block here,
- // since we need to handle mCanceled and mVCardParser at once.
- // In the worst case, a user may call cancel() just before creating
- // mVCardParser.
- synchronized (this) {
- mVCardParser = (vcardVersion == ImportVCardActivity.VCARD_VERSION_V30 ?
- new VCardParser_V30(vcardType) :
- new VCardParser_V21(vcardType));
- if (isCancelled()) {
- Log.i(LOG_TAG, "ImportProcessor already recieves cancel request, so " +
- "send cancel request to vCard parser too.");
- mVCardParser.cancel();
- }
- }
- mVCardParser.parse(is, interpreter);
-
- successful = true;
- break;
- } catch (IOException e) {
- Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());
- } catch (VCardNestedException e) {
- // This exception should not be thrown here. We should instead handle it
- // in the preprocessing session in ImportVCardActivity, as we don't try
- // to detect the type of given vCard here.
- //
- // TODO: Handle this case appropriately, which should mean we have to have
- // code trying to auto-detect the type of given vCard twice (both in
- // ImportVCardActivity and ImportVCardService).
- Log.e(LOG_TAG, "Nested Exception is found.");
- } catch (VCardNotSupportedException e) {
- Log.e(LOG_TAG, e.toString());
- } catch (VCardVersionException e) {
- if (i == length - 1) {
- Log.e(LOG_TAG, "Appropriate version for this vCard is not found.");
- } else {
- // We'll try the other (v30) version.
- }
- } catch (VCardException e) {
- Log.e(LOG_TAG, e.toString());
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
- return successful;
- }
-
- @Override
- public synchronized boolean cancel(boolean mayInterruptIfRunning) {
- if (DEBUG) Log.d(LOG_TAG, "ImportProcessor received cancel request");
- if (mDone || mCanceled) {
- return false;
- }
- mCanceled = true;
- synchronized (this) {
- if (mVCardParser != null) {
- mVCardParser.cancel();
- }
- }
- return true;
- }
-
- @Override
- public synchronized boolean isCancelled() {
- return mCanceled;
- }
-
-
- @Override
- public synchronized boolean isDone() {
- return mDone;
- }
-}
diff --git a/src/com/android/contacts/vcard/ImportRequest.java b/src/com/android/contacts/vcard/ImportRequest.java
deleted file mode 100644
index 68b5424..0000000
--- a/src/com/android/contacts/vcard/ImportRequest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.accounts.Account;
-import android.net.Uri;
-
-import com.android.vcard.VCardSourceDetector;
-
-/**
- * Class representing one request for importing vCard (given as a Uri).
- *
- * Mainly used when {@link ImportVCardActivity} requests {@link VCardService}
- * to import some specific Uri.
- *
- * Note: This object's accepting only One Uri does NOT mean that
- * there's only one vCard entry inside the instance, as one Uri often has multiple
- * vCard entries inside it.
- */
-public class ImportRequest {
- /**
- * Can be null (typically when there's no Account available in the system).
- */
- public final Account account;
-
- /**
- * Uri to be imported. May have different content than originally given from users, so
- * when displaying user-friendly information (e.g. "importing xxx.vcf"), use
- * {@link #displayName} instead.
- *
- * If this is null {@link #data} contains the byte stream of the vcard.
- */
- public final Uri uri;
-
- /**
- * Holds the byte stream of the vcard, if {@link #uri} is null.
- */
- public final byte[] data;
-
- /**
- * String to be displayed to the user to indicate the source of the VCARD.
- */
- public final String displayName;
-
- /**
- * Can be {@link VCardSourceDetector#PARSE_TYPE_UNKNOWN}.
- */
- public final int estimatedVCardType;
-
- /**
- * Can be null, meaning no preferable charset is available.
- */
- public final String estimatedCharset;
-
- /**
- * Assumes that one Uri contains only one version, while there's a (tiny) possibility
- * we may have two types in one vCard.
- *
- * e.g.
- * BEGIN:VCARD
- * VERSION:2.1
- * ...
- * END:VCARD
- * BEGIN:VCARD
- * VERSION:3.0
- * ...
- * END:VCARD
- *
- * We've never seen this kind of a file, but we may have to cope with it in the future.
- */
- public final int vcardVersion;
-
- /**
- * The count of vCard entries in {@link #uri}. A receiver of this object can use it
- * when showing the progress of import. Thus a receiver must be able to torelate this
- * variable being invalid because of vCard's limitation.
- *
- * vCard does not let us know this count without looking over a whole file content,
- * which means we have to open and scan over {@link #uri} to know this value, while
- * it may not be opened more than once (Uri does not require it to be opened multiple times
- * and may become invalid after its close() request).
- */
- public final int entryCount;
-
- public ImportRequest(Account account,
- byte[] data, Uri uri, String displayName, int estimatedType, String estimatedCharset,
- int vcardVersion, int entryCount) {
- this.account = account;
- this.data = data;
- this.uri = uri;
- this.displayName = displayName;
- this.estimatedVCardType = estimatedType;
- this.estimatedCharset = estimatedCharset;
- this.vcardVersion = vcardVersion;
- this.entryCount = entryCount;
- }
-}
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
deleted file mode 100644
index d6cad88..0000000
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.vcard;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.ProgressDialog;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.res.Configuration;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.PowerManager;
-import android.provider.OpenableColumns;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.style.RelativeSizeSpan;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.contacts.ContactsActivity;
-import com.android.contacts.R;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.util.AccountSelectionUtil;
-import com.android.vcard.VCardEntryCounter;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.VCardSourceDetector;
-import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardNestedException;
-import com.android.vcard.exception.VCardVersionException;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-/**
- * The class letting users to import vCard. This includes the UI part for letting them select
- * an Account and posssibly a file if there's no Uri is given from its caller Activity.
- *
- * Note that this Activity assumes that the instance is a "one-shot Activity", which will be
- * finished (with the method {@link Activity#finish()}) after the import and never reuse
- * any Dialog in the instance. So this code is careless about the management around managed
- * dialogs stuffs (like how onCreateDialog() is used).
- */
-public class ImportVCardActivity extends ContactsActivity {
- private static final String LOG_TAG = "VCardImport";
-
- private static final int SELECT_ACCOUNT = 0;
-
- /* package */ static final String VCARD_URI_ARRAY = "vcard_uri";
- /* package */ static final String ESTIMATED_VCARD_TYPE_ARRAY = "estimated_vcard_type";
- /* package */ static final String ESTIMATED_CHARSET_ARRAY = "estimated_charset";
- /* package */ static final String VCARD_VERSION_ARRAY = "vcard_version";
- /* package */ static final String ENTRY_COUNT_ARRAY = "entry_count";
-
- /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0;
- /* package */ final static int VCARD_VERSION_V21 = 1;
- /* package */ final static int VCARD_VERSION_V30 = 2;
-
- private static final String SECURE_DIRECTORY_NAME = ".android_secure";
-
- /**
- * Notification id used when error happened before sending an import request to VCardServer.
- */
- private static final int FAILURE_NOTIFICATION_ID = 1;
-
- final static String CACHED_URIS = "cached_uris";
-
- private AccountSelectionUtil.AccountSelectedListener mAccountSelectionListener;
-
- private AccountWithDataSet mAccount;
-
- private ProgressDialog mProgressDialogForScanVCard;
- private ProgressDialog mProgressDialogForCachingVCard;
-
- private List<VCardFile> mAllVCardFileList;
- private VCardScanThread mVCardScanThread;
-
- private VCardCacheThread mVCardCacheThread;
- private ImportRequestConnection mConnection;
- /* package */ VCardImportExportListener mListener;
-
- private String mErrorMessage;
-
- private Handler mHandler = new Handler();
-
- private static class VCardFile {
- private final String mName;
- private final String mCanonicalPath;
- private final long mLastModified;
-
- public VCardFile(String name, String canonicalPath, long lastModified) {
- mName = name;
- mCanonicalPath = canonicalPath;
- mLastModified = lastModified;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getCanonicalPath() {
- return mCanonicalPath;
- }
-
- public long getLastModified() {
- return mLastModified;
- }
- }
-
- // Runs on the UI thread.
- private class DialogDisplayer implements Runnable {
- private final int mResId;
- public DialogDisplayer(int resId) {
- mResId = resId;
- }
- public DialogDisplayer(String errorMessage) {
- mResId = R.id.dialog_error_with_message;
- mErrorMessage = errorMessage;
- }
- @Override
- public void run() {
- if (!isFinishing()) {
- showDialog(mResId);
- }
- }
- }
-
- private class CancelListener
- implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- @Override
- public void onCancel(DialogInterface dialog) {
- finish();
- }
- }
-
- private CancelListener mCancelListener = new CancelListener();
-
- private class ImportRequestConnection implements ServiceConnection {
- private VCardService mService;
-
- public void sendImportRequest(final List<ImportRequest> requests) {
- Log.i(LOG_TAG, "Send an import request");
- mService.handleImportRequest(requests, mListener);
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- mService = ((VCardService.MyBinder) binder).getService();
- Log.i(LOG_TAG,
- String.format("Connected to VCardService. Kick a vCard cache thread (uri: %s)",
- Arrays.toString(mVCardCacheThread.getSourceUris())));
- mVCardCacheThread.start();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.i(LOG_TAG, "Disconnected from VCardService");
- }
- }
-
- /**
- * Caches given vCard files into a local directory, and sends actual import request to
- * {@link VCardService}.
- *
- * We need to cache given files into local storage. One of reasons is that some data (as Uri)
- * may have special permissions. Callers may allow only this Activity to access that content,
- * not what this Activity launched (like {@link VCardService}).
- */
- private class VCardCacheThread extends Thread
- implements DialogInterface.OnCancelListener {
- private boolean mCanceled;
- private PowerManager.WakeLock mWakeLock;
- private VCardParser mVCardParser;
- private final Uri[] mSourceUris; // Given from a caller.
- private final byte[] mSource;
- private final String mDisplayName;
-
- public VCardCacheThread(final Uri[] sourceUris) {
- mSourceUris = sourceUris;
- mSource = null;
- final Context context = ImportVCardActivity.this;
- final PowerManager powerManager =
- (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(
- PowerManager.SCREEN_DIM_WAKE_LOCK |
- PowerManager.ON_AFTER_RELEASE, LOG_TAG);
- mDisplayName = null;
- }
-
- @Override
- public void finalize() {
- if (mWakeLock != null && mWakeLock.isHeld()) {
- Log.w(LOG_TAG, "WakeLock is being held.");
- mWakeLock.release();
- }
- }
-
- @Override
- public void run() {
- Log.i(LOG_TAG, "vCard cache thread starts running.");
- if (mConnection == null) {
- throw new NullPointerException("vCard cache thread must be launched "
- + "after a service connection is established");
- }
-
- mWakeLock.acquire();
- try {
- if (mCanceled == true) {
- Log.i(LOG_TAG, "vCard cache operation is canceled.");
- return;
- }
-
- final Context context = ImportVCardActivity.this;
- // Uris given from caller applications may not be opened twice: consider when
- // it is not from local storage (e.g. "file:///...") but from some special
- // provider (e.g. "content://...").
- // Thus we have to once copy the content of Uri into local storage, and read
- // it after it.
- //
- // We may be able to read content of each vCard file during copying them
- // to local storage, but currently vCard code does not allow us to do so.
- int cache_index = 0;
- ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>();
- if (mSource != null) {
- try {
- requests.add(constructImportRequest(mSource, null, mDisplayName));
- } catch (VCardException e) {
- Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
- showFailureNotification(R.string.fail_reason_not_supported);
- return;
- }
- } else {
- final ContentResolver resolver =
- ImportVCardActivity.this.getContentResolver();
- for (Uri sourceUri : mSourceUris) {
- String filename = null;
- // Note: caches are removed by VCardService.
- while (true) {
- filename = VCardService.CACHE_FILE_PREFIX + cache_index + ".vcf";
- final File file = context.getFileStreamPath(filename);
- if (!file.exists()) {
- break;
- } else {
- if (cache_index == Integer.MAX_VALUE) {
- throw new RuntimeException("Exceeded cache limit");
- }
- cache_index++;
- }
- }
- final Uri localDataUri = copyTo(sourceUri, filename);
- if (mCanceled) {
- Log.i(LOG_TAG, "vCard cache operation is canceled.");
- break;
- }
- if (localDataUri == null) {
- Log.w(LOG_TAG, "destUri is null");
- break;
- }
-
- String displayName = null;
- Cursor cursor = null;
- // Try to get a display name from the given Uri. If it fails, we just
- // pick up the last part of the Uri.
- try {
- cursor = resolver.query(sourceUri,
- new String[] { OpenableColumns.DISPLAY_NAME },
- null, null, null);
- if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
- if (cursor.getCount() > 1) {
- Log.w(LOG_TAG, "Unexpected multiple rows: "
- + cursor.getCount());
- }
- int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
- if (index >= 0) {
- displayName = cursor.getString(index);
- }
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- if (TextUtils.isEmpty(displayName)){
- displayName = sourceUri.getLastPathSegment();
- }
-
- final ImportRequest request;
- try {
- request = constructImportRequest(null, localDataUri, displayName);
- } catch (VCardException e) {
- Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
- showFailureNotification(R.string.fail_reason_not_supported);
- return;
- } catch (IOException e) {
- Log.e(LOG_TAG, "Unexpected IOException", e);
- showFailureNotification(R.string.fail_reason_io_error);
- return;
- }
- if (mCanceled) {
- Log.i(LOG_TAG, "vCard cache operation is canceled.");
- return;
- }
- requests.add(request);
- }
- }
- if (!requests.isEmpty()) {
- mConnection.sendImportRequest(requests);
- } else {
- Log.w(LOG_TAG, "Empty import requests. Ignore it.");
- }
- } catch (OutOfMemoryError e) {
- Log.e(LOG_TAG, "OutOfMemoryError occured during caching vCard");
- System.gc();
- runOnUiThread(new DialogDisplayer(
- getString(R.string.fail_reason_low_memory_during_import)));
- } catch (IOException e) {
- Log.e(LOG_TAG, "IOException during caching vCard", e);
- runOnUiThread(new DialogDisplayer(
- getString(R.string.fail_reason_io_error)));
- } finally {
- Log.i(LOG_TAG, "Finished caching vCard.");
- mWakeLock.release();
- unbindService(mConnection);
- mProgressDialogForCachingVCard.dismiss();
- mProgressDialogForCachingVCard = null;
- finish();
- }
- }
-
- /**
- * Copy the content of sourceUri to the destination.
- */
- private Uri copyTo(final Uri sourceUri, String filename) throws IOException {
- Log.i(LOG_TAG, String.format("Copy a Uri to app local storage (%s -> %s)",
- sourceUri, filename));
- final Context context = ImportVCardActivity.this;
- final ContentResolver resolver = context.getContentResolver();
- ReadableByteChannel inputChannel = null;
- WritableByteChannel outputChannel = null;
- Uri destUri = null;
- try {
- inputChannel = Channels.newChannel(resolver.openInputStream(sourceUri));
- destUri = Uri.parse(context.getFileStreamPath(filename).toURI().toString());
- outputChannel = context.openFileOutput(filename, Context.MODE_PRIVATE).getChannel();
- final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
- while (inputChannel.read(buffer) != -1) {
- if (mCanceled) {
- Log.d(LOG_TAG, "Canceled during caching " + sourceUri);
- return null;
- }
- buffer.flip();
- outputChannel.write(buffer);
- buffer.compact();
- }
- buffer.flip();
- while (buffer.hasRemaining()) {
- outputChannel.write(buffer);
- }
- } finally {
- if (inputChannel != null) {
- try {
- inputChannel.close();
- } catch (IOException e) {
- Log.w(LOG_TAG, "Failed to close inputChannel.");
- }
- }
- if (outputChannel != null) {
- try {
- outputChannel.close();
- } catch(IOException e) {
- Log.w(LOG_TAG, "Failed to close outputChannel");
- }
- }
- }
- return destUri;
- }
-
- /**
- * Reads localDataUri (possibly multiple times) and constructs {@link ImportRequest} from
- * its content.
- *
- * @arg localDataUri Uri actually used for the import. Should be stored in
- * app local storage, as we cannot guarantee other types of Uris can be read
- * multiple times. This variable populates {@link ImportRequest#uri}.
- * @arg displayName Used for displaying information to the user. This variable populates
- * {@link ImportRequest#displayName}.
- */
- private ImportRequest constructImportRequest(final byte[] data,
- final Uri localDataUri, final String displayName)
- throws IOException, VCardException {
- final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();
- VCardEntryCounter counter = null;
- VCardSourceDetector detector = null;
- int vcardVersion = VCARD_VERSION_V21;
- try {
- boolean shouldUseV30 = false;
- InputStream is;
- if (data != null) {
- is = new ByteArrayInputStream(data);
- } else {
- is = resolver.openInputStream(localDataUri);
- }
- mVCardParser = new VCardParser_V21();
- try {
- counter = new VCardEntryCounter();
- detector = new VCardSourceDetector();
- mVCardParser.addInterpreter(counter);
- mVCardParser.addInterpreter(detector);
- mVCardParser.parse(is);
- } catch (VCardVersionException e1) {
- try {
- is.close();
- } catch (IOException e) {
- }
-
- shouldUseV30 = true;
- if (data != null) {
- is = new ByteArrayInputStream(data);
- } else {
- is = resolver.openInputStream(localDataUri);
- }
- mVCardParser = new VCardParser_V30();
- try {
- counter = new VCardEntryCounter();
- detector = new VCardSourceDetector();
- mVCardParser.addInterpreter(counter);
- mVCardParser.addInterpreter(detector);
- mVCardParser.parse(is);
- } catch (VCardVersionException e2) {
- throw new VCardException("vCard with unspported version.");
- }
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
-
- vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;
- } catch (VCardNestedException e) {
- Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");
- // Go through without throwing the Exception, as we may be able to detect the
- // version before it
- }
- return new ImportRequest(mAccount,
- data, localDataUri, displayName,
- detector.getEstimatedType(),
- detector.getEstimatedCharset(),
- vcardVersion, counter.getCount());
- }
-
- public Uri[] getSourceUris() {
- return mSourceUris;
- }
-
- public void cancel() {
- mCanceled = true;
- if (mVCardParser != null) {
- mVCardParser.cancel();
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- Log.i(LOG_TAG, "Cancel request has come. Abort caching vCard.");
- cancel();
- }
- }
-
- private class ImportTypeSelectedListener implements
- DialogInterface.OnClickListener {
- public static final int IMPORT_ONE = 0;
- public static final int IMPORT_MULTIPLE = 1;
- public static final int IMPORT_ALL = 2;
- public static final int IMPORT_TYPE_SIZE = 3;
-
- private int mCurrentIndex;
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- switch (mCurrentIndex) {
- case IMPORT_ALL:
- importVCardFromSDCard(mAllVCardFileList);
- break;
- case IMPORT_MULTIPLE:
- showDialog(R.id.dialog_select_multiple_vcard);
- break;
- default:
- showDialog(R.id.dialog_select_one_vcard);
- break;
- }
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- finish();
- } else {
- mCurrentIndex = which;
- }
- }
- }
-
- private class VCardSelectedListener implements
- DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener {
- private int mCurrentIndex;
- private Set<Integer> mSelectedIndexSet;
-
- public VCardSelectedListener(boolean multipleSelect) {
- mCurrentIndex = 0;
- if (multipleSelect) {
- mSelectedIndexSet = new HashSet<Integer>();
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mSelectedIndexSet != null) {
- List<VCardFile> selectedVCardFileList = new ArrayList<VCardFile>();
- final int size = mAllVCardFileList.size();
- // We'd like to sort the files by its index, so we do not use Set iterator.
- for (int i = 0; i < size; i++) {
- if (mSelectedIndexSet.contains(i)) {
- selectedVCardFileList.add(mAllVCardFileList.get(i));
- }
- }
- importVCardFromSDCard(selectedVCardFileList);
- } else {
- importVCardFromSDCard(mAllVCardFileList.get(mCurrentIndex));
- }
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- finish();
- } else {
- // Some file is selected.
- mCurrentIndex = which;
- if (mSelectedIndexSet != null) {
- if (mSelectedIndexSet.contains(which)) {
- mSelectedIndexSet.remove(which);
- } else {
- mSelectedIndexSet.add(which);
- }
- }
- }
- }
-
- public void onClick(DialogInterface dialog, int which, boolean isChecked) {
- if (mSelectedIndexSet == null || (mSelectedIndexSet.contains(which) == isChecked)) {
- Log.e(LOG_TAG, String.format("Inconsist state in index %d (%s)", which,
- mAllVCardFileList.get(which).getCanonicalPath()));
- } else {
- onClick(dialog, which);
- }
- }
- }
-
- /**
- * Thread scanning VCard from SDCard. After scanning, the dialog which lets a user select
- * a vCard file is shown. After the choice, VCardReadThread starts running.
- */
- private class VCardScanThread extends Thread implements OnCancelListener, OnClickListener {
- private boolean mCanceled;
- private boolean mGotIOException;
- private File mRootDirectory;
-
- // To avoid recursive link.
- private Set<String> mCheckedPaths;
- private PowerManager.WakeLock mWakeLock;
-
- private class CanceledException extends Exception {
- }
-
- public VCardScanThread(File sdcardDirectory) {
- mCanceled = false;
- mGotIOException = false;
- mRootDirectory = sdcardDirectory;
- mCheckedPaths = new HashSet<String>();
- PowerManager powerManager = (PowerManager)ImportVCardActivity.this.getSystemService(
- Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(
- PowerManager.SCREEN_DIM_WAKE_LOCK |
- PowerManager.ON_AFTER_RELEASE, LOG_TAG);
- }
-
- @Override
- public void run() {
- mAllVCardFileList = new Vector<VCardFile>();
- try {
- mWakeLock.acquire();
- getVCardFileRecursively(mRootDirectory);
- } catch (CanceledException e) {
- mCanceled = true;
- } catch (IOException e) {
- mGotIOException = true;
- } finally {
- mWakeLock.release();
- }
-
- if (mCanceled) {
- mAllVCardFileList = null;
- }
-
- mProgressDialogForScanVCard.dismiss();
- mProgressDialogForScanVCard = null;
-
- if (mGotIOException) {
- runOnUiThread(new DialogDisplayer(R.id.dialog_io_exception));
- } else if (mCanceled) {
- finish();
- } else {
- int size = mAllVCardFileList.size();
- final Context context = ImportVCardActivity.this;
- if (size == 0) {
- runOnUiThread(new DialogDisplayer(R.id.dialog_vcard_not_found));
- } else {
- startVCardSelectAndImport();
- }
- }
- }
-
- private void getVCardFileRecursively(File directory)
- throws CanceledException, IOException {
- if (mCanceled) {
- throw new CanceledException();
- }
-
- // e.g. secured directory may return null toward listFiles().
- final File[] files = directory.listFiles();
- if (files == null) {
- final String currentDirectoryPath = directory.getCanonicalPath();
- final String secureDirectoryPath =
- mRootDirectory.getCanonicalPath().concat(SECURE_DIRECTORY_NAME);
- if (!TextUtils.equals(currentDirectoryPath, secureDirectoryPath)) {
- Log.w(LOG_TAG, "listFiles() returned null (directory: " + directory + ")");
- }
- return;
- }
- for (File file : directory.listFiles()) {
- if (mCanceled) {
- throw new CanceledException();
- }
- String canonicalPath = file.getCanonicalPath();
- if (mCheckedPaths.contains(canonicalPath)) {
- continue;
- }
-
- mCheckedPaths.add(canonicalPath);
-
- if (file.isDirectory()) {
- getVCardFileRecursively(file);
- } else if (canonicalPath.toLowerCase().endsWith(".vcf") &&
- file.canRead()){
- String fileName = file.getName();
- VCardFile vcardFile = new VCardFile(
- fileName, canonicalPath, file.lastModified());
- mAllVCardFileList.add(vcardFile);
- }
- }
- }
-
- public void onCancel(DialogInterface dialog) {
- mCanceled = true;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_NEGATIVE) {
- mCanceled = true;
- }
- }
- }
-
- private void startVCardSelectAndImport() {
- int size = mAllVCardFileList.size();
- if (getResources().getBoolean(R.bool.config_import_all_vcard_from_sdcard_automatically) ||
- size == 1) {
- importVCardFromSDCard(mAllVCardFileList);
- } else if (getResources().getBoolean(R.bool.config_allow_users_select_all_vcard_import)) {
- runOnUiThread(new DialogDisplayer(R.id.dialog_select_import_type));
- } else {
- runOnUiThread(new DialogDisplayer(R.id.dialog_select_one_vcard));
- }
- }
-
- private void importVCardFromSDCard(final List<VCardFile> selectedVCardFileList) {
- final int size = selectedVCardFileList.size();
- String[] uriStrings = new String[size];
- int i = 0;
- for (VCardFile vcardFile : selectedVCardFileList) {
- uriStrings[i] = "file://" + vcardFile.getCanonicalPath();
- i++;
- }
- importVCard(uriStrings);
- }
-
- private void importVCardFromSDCard(final VCardFile vcardFile) {
- importVCard(new Uri[] {Uri.parse("file://" + vcardFile.getCanonicalPath())});
- }
-
- private void importVCard(final Uri uri) {
- importVCard(new Uri[] {uri});
- }
-
- private void importVCard(final String[] uriStrings) {
- final int length = uriStrings.length;
- final Uri[] uris = new Uri[length];
- for (int i = 0; i < length; i++) {
- uris[i] = Uri.parse(uriStrings[i]);
- }
- importVCard(uris);
- }
-
- private void importVCard(final Uri[] uris) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (!isFinishing()) {
- mVCardCacheThread = new VCardCacheThread(uris);
- mListener = new NotificationImportExportListener(ImportVCardActivity.this);
- showDialog(R.id.dialog_cache_vcard);
- }
- }
- });
- }
-
- private Dialog getSelectImportTypeDialog() {
- final DialogInterface.OnClickListener listener = new ImportTypeSelectedListener();
- final AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.select_vcard_title)
- .setPositiveButton(android.R.string.ok, listener)
- .setOnCancelListener(mCancelListener)
- .setNegativeButton(android.R.string.cancel, mCancelListener);
-
- final String[] items = new String[ImportTypeSelectedListener.IMPORT_TYPE_SIZE];
- items[ImportTypeSelectedListener.IMPORT_ONE] =
- getString(R.string.import_one_vcard_string);
- items[ImportTypeSelectedListener.IMPORT_MULTIPLE] =
- getString(R.string.import_multiple_vcard_string);
- items[ImportTypeSelectedListener.IMPORT_ALL] =
- getString(R.string.import_all_vcard_string);
- builder.setSingleChoiceItems(items, ImportTypeSelectedListener.IMPORT_ONE, listener);
- return builder.create();
- }
-
- private Dialog getVCardFileSelectDialog(boolean multipleSelect) {
- final int size = mAllVCardFileList.size();
- final VCardSelectedListener listener = new VCardSelectedListener(multipleSelect);
- final AlertDialog.Builder builder =
- new AlertDialog.Builder(this)
- .setTitle(R.string.select_vcard_title)
- .setPositiveButton(android.R.string.ok, listener)
- .setOnCancelListener(mCancelListener)
- .setNegativeButton(android.R.string.cancel, mCancelListener);
-
- CharSequence[] items = new CharSequence[size];
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- for (int i = 0; i < size; i++) {
- VCardFile vcardFile = mAllVCardFileList.get(i);
- SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
- stringBuilder.append(vcardFile.getName());
- stringBuilder.append('\n');
- int indexToBeSpanned = stringBuilder.length();
- // Smaller date text looks better, since each file name becomes easier to read.
- // The value set to RelativeSizeSpan is arbitrary. You can change it to any other
- // value (but the value bigger than 1.0f would not make nice appearance :)
- stringBuilder.append(
- "(" + dateFormat.format(new Date(vcardFile.getLastModified())) + ")");
- stringBuilder.setSpan(
- new RelativeSizeSpan(0.7f), indexToBeSpanned, stringBuilder.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- items[i] = stringBuilder;
- }
- if (multipleSelect) {
- builder.setMultiChoiceItems(items, (boolean[])null, listener);
- } else {
- builder.setSingleChoiceItems(items, 0, listener);
- }
- return builder.create();
- }
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
-
- String accountName = null;
- String accountType = null;
- String dataSet = null;
- final Intent intent = getIntent();
- if (intent != null) {
- accountName = intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME);
- accountType = intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE);
- dataSet = intent.getStringExtra(SelectAccountActivity.DATA_SET);
- } else {
- Log.e(LOG_TAG, "intent does not exist");
- }
-
- if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
- mAccount = new AccountWithDataSet(accountName, accountType, dataSet);
- } else {
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
- final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
- if (accountList.size() == 0) {
- mAccount = null;
- } else if (accountList.size() == 1) {
- mAccount = accountList.get(0);
- } else {
- startActivityForResult(new Intent(this, SelectAccountActivity.class),
- SELECT_ACCOUNT);
- return;
- }
- }
-
- startImport();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if (requestCode == SELECT_ACCOUNT) {
- if (resultCode == RESULT_OK) {
- mAccount = new AccountWithDataSet(
- intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
- intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
- intent.getStringExtra(SelectAccountActivity.DATA_SET));
- startImport();
- } else {
- if (resultCode != RESULT_CANCELED) {
- Log.w(LOG_TAG, "Result code was not OK nor CANCELED: " + resultCode);
- }
- finish();
- }
- }
- }
-
- private void startImport() {
- Intent intent = getIntent();
- // Handle inbound files
- Uri uri = intent.getData();
- if (uri != null) {
- Log.i(LOG_TAG, "Starting vCard import using Uri " + uri);
- importVCard(uri);
- } else {
- Log.i(LOG_TAG, "Start vCard without Uri. The user will select vCard manually.");
- doScanExternalStorageAndImportVCard();
- }
- }
-
- @Override
- protected Dialog onCreateDialog(int resId, Bundle bundle) {
- switch (resId) {
- case R.string.import_from_sdcard: {
- if (mAccountSelectionListener == null) {
- throw new NullPointerException(
- "mAccountSelectionListener must not be null.");
- }
- return AccountSelectionUtil.getSelectAccountDialog(this, resId,
- mAccountSelectionListener, mCancelListener);
- }
- case R.id.dialog_searching_vcard: {
- if (mProgressDialogForScanVCard == null) {
- String message = getString(R.string.searching_vcard_message);
- mProgressDialogForScanVCard =
- ProgressDialog.show(this, "", message, true, false);
- mProgressDialogForScanVCard.setOnCancelListener(mVCardScanThread);
- mVCardScanThread.start();
- }
- return mProgressDialogForScanVCard;
- }
- case R.id.dialog_sdcard_not_found: {
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(R.string.no_sdcard_message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- return builder.create();
- }
- case R.id.dialog_vcard_not_found: {
- final String message = getString(R.string.import_failure_no_vcard_file);
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- return builder.create();
- }
- case R.id.dialog_select_import_type: {
- return getSelectImportTypeDialog();
- }
- case R.id.dialog_select_multiple_vcard: {
- return getVCardFileSelectDialog(true);
- }
- case R.id.dialog_select_one_vcard: {
- return getVCardFileSelectDialog(false);
- }
- case R.id.dialog_cache_vcard: {
- if (mProgressDialogForCachingVCard == null) {
- final String title = getString(R.string.caching_vcard_title);
- final String message = getString(R.string.caching_vcard_message);
- mProgressDialogForCachingVCard = new ProgressDialog(this);
- mProgressDialogForCachingVCard.setTitle(title);
- mProgressDialogForCachingVCard.setMessage(message);
- mProgressDialogForCachingVCard.setProgressStyle(ProgressDialog.STYLE_SPINNER);
- mProgressDialogForCachingVCard.setOnCancelListener(mVCardCacheThread);
- startVCardService();
- }
- return mProgressDialogForCachingVCard;
- }
- case R.id.dialog_io_exception: {
- String message = (getString(R.string.scanning_sdcard_failed_message,
- getString(R.string.fail_reason_io_error)));
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- return builder.create();
- }
- case R.id.dialog_error_with_message: {
- String message = mErrorMessage;
- if (TextUtils.isEmpty(message)) {
- Log.e(LOG_TAG, "Error message is null while it must not.");
- message = getString(R.string.fail_reason_unknown);
- }
- final AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(getString(R.string.reading_vcard_failed_title))
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- return builder.create();
- }
- }
-
- return super.onCreateDialog(resId, bundle);
- }
-
- /* package */ void startVCardService() {
- mConnection = new ImportRequestConnection();
-
- Log.i(LOG_TAG, "Bind to VCardService.");
- // We don't want the service finishes itself just after this connection.
- Intent intent = new Intent(this, VCardService.class);
- startService(intent);
- bindService(new Intent(this, VCardService.class),
- mConnection, Context.BIND_AUTO_CREATE);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- if (mProgressDialogForCachingVCard != null) {
- Log.i(LOG_TAG, "Cache thread is still running. Show progress dialog again.");
- showDialog(R.id.dialog_cache_vcard);
- }
- }
-
- /**
- * Scans vCard in external storage (typically SDCard) and tries to import it.
- * - When there's no SDCard available, an error dialog is shown.
- * - When multiple vCard files are available, asks a user to select one.
- */
- private void doScanExternalStorageAndImportVCard() {
- // TODO: should use getExternalStorageState().
- final File file = Environment.getExternalStorageDirectory();
- if (!file.exists() || !file.isDirectory() || !file.canRead()) {
- showDialog(R.id.dialog_sdcard_not_found);
- } else {
- mVCardScanThread = new VCardScanThread(file);
- showDialog(R.id.dialog_searching_vcard);
- }
- }
-
- /* package */ void showFailureNotification(int reasonId) {
- final NotificationManager notificationManager =
- (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
- final Notification notification =
- NotificationImportExportListener.constructImportFailureNotification(
- ImportVCardActivity.this,
- getString(reasonId));
- notificationManager.notify(NotificationImportExportListener.FAILURE_NOTIFICATION_TAG,
- FAILURE_NOTIFICATION_ID, notification);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(ImportVCardActivity.this,
- getString(R.string.vcard_import_failed), Toast.LENGTH_LONG).show();
- }
- });
- }
-}
diff --git a/src/com/android/contacts/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
deleted file mode 100644
index 3c099cb..0000000
--- a/src/com/android/contacts/vcard/NfcImportVCardActivity.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.contacts.vcard;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.Uri;
-import android.nfc.NdefMessage;
-import android.nfc.NdefRecord;
-import android.nfc.NfcAdapter;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-import com.android.contacts.R;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryCounter;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.VCardSourceDetector;
-import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardNestedException;
-import com.android.vcard.exception.VCardVersionException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-public class NfcImportVCardActivity extends Activity implements ServiceConnection,
- VCardImportExportListener {
- private static final String TAG = "NfcImportVCardActivity";
-
- private static final int SELECT_ACCOUNT = 1;
-
- private NdefRecord mRecord;
- private AccountWithDataSet mAccount;
-
- /* package */ class ImportTask extends AsyncTask<VCardService, Void, ImportRequest> {
- @Override
- public ImportRequest doInBackground(VCardService... services) {
- ImportRequest request = createImportRequest();
- if (request == null) {
- return null;
- }
-
- ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>();
- requests.add(request);
- services[0].handleImportRequest(requests, NfcImportVCardActivity.this);
- return request;
- }
-
- @Override
- public void onCancelled() {
- unbindService(NfcImportVCardActivity.this);
- }
-
- @Override
- public void onPostExecute(ImportRequest request) {
- unbindService(NfcImportVCardActivity.this);
- }
- }
-
- /* package */ ImportRequest createImportRequest() {
- VCardParser parser;
- VCardEntryCounter counter = null;
- VCardSourceDetector detector = null;
- int vcardVersion = ImportVCardActivity.VCARD_VERSION_V21;
- try {
- ByteArrayInputStream is = new ByteArrayInputStream(mRecord.getPayload());
- is.mark(0);
- parser = new VCardParser_V21();
- try {
- counter = new VCardEntryCounter();
- detector = new VCardSourceDetector();
- parser.addInterpreter(counter);
- parser.addInterpreter(detector);
- parser.parse(is);
- } catch (VCardVersionException e1) {
- is.reset();
- vcardVersion = ImportVCardActivity.VCARD_VERSION_V30;
- parser = new VCardParser_V30();
- try {
- counter = new VCardEntryCounter();
- detector = new VCardSourceDetector();
- parser.addInterpreter(counter);
- parser.addInterpreter(detector);
- parser.parse(is);
- } catch (VCardVersionException e2) {
- return null;
- }
- } finally {
- try {
- if (is != null) is.close();
- } catch (IOException e) {
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed reading vcard data", e);
- return null;
- } catch (VCardNestedException e) {
- Log.w(TAG, "Nested Exception is found (it may be false-positive).");
- // Go through without throwing the Exception, as we may be able to detect the
- // version before it
- } catch (VCardException e) {
- Log.e(TAG, "Error parsing vcard", e);
- return null;
- }
-
- return new ImportRequest(mAccount, mRecord.getPayload(), null,
- getString(R.string.nfc_vcard_file_name), detector.getEstimatedType(),
- detector.getEstimatedCharset(), vcardVersion, counter.getCount());
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- VCardService service = ((VCardService.MyBinder) binder).getService();
- new ImportTask().execute(service);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // Do nothing
- }
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
-
- Intent intent = getIntent();
- if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
- Log.w(TAG, "Unknowon intent " + intent);
- finish();
- return;
- }
-
- String type = intent.getType();
- if (type == null ||
- (!"text/x-vcard".equals(type) && !"text/vcard".equals(type))) {
- Log.w(TAG, "Not a vcard");
- //setStatus(getString(R.string.fail_reason_not_supported));
- finish();
- return;
- }
- NdefMessage msg = (NdefMessage) intent.getParcelableArrayExtra(
- NfcAdapter.EXTRA_NDEF_MESSAGES)[0];
- mRecord = msg.getRecords()[0];
-
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
- final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
- if (accountList.size() == 0) {
- mAccount = null;
- } else if (accountList.size() == 1) {
- mAccount = accountList.get(0);
- } else {
- startActivityForResult(new Intent(this, SelectAccountActivity.class), SELECT_ACCOUNT);
- return;
- }
-
- startImport();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- if (requestCode == SELECT_ACCOUNT) {
- if (resultCode == RESULT_OK) {
- mAccount = new AccountWithDataSet(
- intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
- intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
- intent.getStringExtra(SelectAccountActivity.DATA_SET));
- startImport();
- } else {
- finish();
- }
- }
- }
-
- private void startImport() {
- // We don't want the service finishes itself just after this connection.
- Intent intent = new Intent(this, VCardService.class);
- startService(intent);
- bindService(intent, this, Context.BIND_AUTO_CREATE);
- }
-
- @Override
- public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
- // do nothing
- }
-
- @Override
- public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
- int totalCount) {
- // do nothing
- }
-
- @Override
- public void onImportFinished(ImportRequest request, int jobId, Uri uri) {
- if (isFinishing()) {
- Log.i(TAG, "Late import -- ignoring");
- return;
- }
-
- if (uri != null) {
- Uri contactUri = RawContacts.getContactLookupUri(getContentResolver(), uri);
- Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
- startActivity(intent);
- finish();
- }
- }
-
- @Override
- public void onImportFailed(ImportRequest request) {
- if (isFinishing()) {
- Log.i(TAG, "Late import failure -- ignoring");
- return;
- }
- // TODO: report failure
- }
-
- @Override
- public void onImportCanceled(ImportRequest request, int jobId) {
- // do nothing
- }
-
- @Override
- public void onExportProcessed(ExportRequest request, int jobId) {
- // do nothing
- }
-
- @Override
- public void onExportFailed(ExportRequest request) {
- // do nothing
- }
-
- @Override
- public void onCancelRequest(CancelRequest request, int type) {
- // do nothing
- }
-
- @Override
- public void onComplete() {
- // do nothing
- }
-}
diff --git a/src/com/android/contacts/vcard/NotificationImportExportListener.java b/src/com/android/contacts/vcard/NotificationImportExportListener.java
deleted file mode 100644
index 855f680..0000000
--- a/src/com/android/contacts/vcard/NotificationImportExportListener.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.contacts.vcard;
-
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.ContactsContract.RawContacts;
-import android.widget.Toast;
-
-import com.android.contacts.R;
-import com.android.vcard.VCardEntry;
-
-public class NotificationImportExportListener implements VCardImportExportListener,
- Handler.Callback {
- /** The tag used by vCard-related notifications. */
- /* package */ static final String DEFAULT_NOTIFICATION_TAG = "VCardServiceProgress";
- /**
- * The tag used by vCard-related failure notifications.
- * <p>
- * Use a different tag from {@link #DEFAULT_NOTIFICATION_TAG} so that failures do not get
- * replaced by other notifications and vice-versa.
- */
- /* package */ static final String FAILURE_NOTIFICATION_TAG = "VCardServiceFailure";
-
- private final NotificationManager mNotificationManager;
- private final Activity mContext;
- private final Handler mHandler;
-
- public NotificationImportExportListener(Activity activity) {
- mContext = activity;
- mNotificationManager = (NotificationManager) activity.getSystemService(
- Context.NOTIFICATION_SERVICE);
- mHandler = new Handler(this);
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- String text = (String) msg.obj;
- Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
- return true;
- }
-
- @Override
- public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
- // Show a notification about the status
- final String displayName;
- final String message;
- if (request.displayName != null) {
- displayName = request.displayName;
- message = mContext.getString(R.string.vcard_import_will_start_message, displayName);
- } else {
- displayName = mContext.getString(R.string.vcard_unknown_filename);
- message = mContext.getString(
- R.string.vcard_import_will_start_message_with_default_name);
- }
-
- // We just want to show notification for the first vCard.
- if (sequence == 0) {
- // TODO: Ideally we should detect the current status of import/export and
- // show "started" when we can import right now and show "will start" when
- // we cannot.
- mHandler.obtainMessage(0, message).sendToTarget();
- }
-
- final Notification notification = constructProgressNotification(mContext,
- VCardService.TYPE_IMPORT, message, message, jobId, displayName, -1, 0);
- mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
- }
-
- @Override
- public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
- int totalCount) {
- if (entry.isIgnorable()) {
- return;
- }
-
- final String totalCountString = String.valueOf(totalCount);
- final String tickerText =
- mContext.getString(R.string.progress_notifier_message,
- String.valueOf(currentCount),
- totalCountString,
- entry.getDisplayName());
- final String description = mContext.getString(R.string.importing_vcard_description,
- entry.getDisplayName());
-
- final Notification notification = constructProgressNotification(
- mContext.getApplicationContext(), VCardService.TYPE_IMPORT, description, tickerText,
- jobId, request.displayName, totalCount, currentCount);
- mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
- }
-
- @Override
- public void onImportFinished(ImportRequest request, int jobId, Uri createdUri) {
- final String description = mContext.getString(R.string.importing_vcard_finished_title,
- request.displayName);
- final Intent intent;
- if (createdUri != null) {
- final long rawContactId = ContentUris.parseId(createdUri);
- final Uri contactUri = RawContacts.getContactLookupUri(
- mContext.getContentResolver(), ContentUris.withAppendedId(
- RawContacts.CONTENT_URI, rawContactId));
- intent = new Intent(Intent.ACTION_VIEW, contactUri);
- } else {
- intent = null;
- }
- final Notification notification =
- NotificationImportExportListener.constructFinishNotification(mContext,
- description, null, intent);
- mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
- jobId, notification);
- }
-
- @Override
- public void onImportFailed(ImportRequest request) {
- // TODO: a little unkind to show Toast in this case, which is shown just a moment.
- // Ideally we should show some persistent something users can notice more easily.
- mHandler.obtainMessage(0,
- mContext.getString(R.string.vcard_import_request_rejected_message)).sendToTarget();
- }
-
- @Override
- public void onImportCanceled(ImportRequest request, int jobId) {
- final String description = mContext.getString(R.string.importing_vcard_canceled_title,
- request.displayName);
- final Notification notification =
- NotificationImportExportListener.constructCancelNotification(mContext, description);
- mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
- jobId, notification);
- }
-
- @Override
- public void onExportProcessed(ExportRequest request, int jobId) {
- final String displayName = request.destUri.getLastPathSegment();
- final String message = mContext.getString(R.string.vcard_export_will_start_message,
- displayName);
-
- mHandler.obtainMessage(0, message).sendToTarget();
- final Notification notification =
- NotificationImportExportListener.constructProgressNotification(mContext,
- VCardService.TYPE_EXPORT, message, message, jobId, displayName, -1, 0);
- mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
- }
-
- @Override
- public void onExportFailed(ExportRequest request) {
- mHandler.obtainMessage(0,
- mContext.getString(R.string.vcard_export_request_rejected_message)).sendToTarget();
- }
-
- @Override
- public void onCancelRequest(CancelRequest request, int type) {
- final String description = type == VCardService.TYPE_IMPORT ?
- mContext.getString(R.string.importing_vcard_canceled_title, request.displayName) :
- mContext.getString(R.string.exporting_vcard_canceled_title, request.displayName);
- final Notification notification = constructCancelNotification(mContext, description);
- mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, request.jobId, notification);
- }
-
- /**
- * Constructs a {@link Notification} showing the current status of import/export.
- * Users can cancel the process with the Notification.
- *
- * @param context
- * @param type import/export
- * @param description Content of the Notification.
- * @param tickerText
- * @param jobId
- * @param displayName Name to be shown to the Notification (e.g. "finished importing XXXX").
- * Typycally a file name.
- * @param totalCount The number of vCard entries to be imported. Used to show progress bar.
- * -1 lets the system show the progress bar with "indeterminate" state.
- * @param currentCount The index of current vCard. Used to show progress bar.
- */
- /* package */ static Notification constructProgressNotification(
- Context context, int type, String description, String tickerText,
- int jobId, String displayName, int totalCount, int currentCount) {
- // Note: We cannot use extra values here (like setIntExtra()), as PendingIntent doesn't
- // preserve them across multiple Notifications. PendingIntent preserves the first extras
- // (when flag is not set), or update them when PendingIntent#getActivity() is called
- // (See PendingIntent#FLAG_UPDATE_CURRENT). In either case, we cannot preserve extras as we
- // expect (for each vCard import/export request).
- //
- // We use query parameter in Uri instead.
- // Scheme and Authority is arbitorary, assuming CancelActivity never refers them.
- final Intent intent = new Intent(context, CancelActivity.class);
- final Uri uri = (new Uri.Builder())
- .scheme("invalidscheme")
- .authority("invalidauthority")
- .appendQueryParameter(CancelActivity.JOB_ID, String.valueOf(jobId))
- .appendQueryParameter(CancelActivity.DISPLAY_NAME, displayName)
- .appendQueryParameter(CancelActivity.TYPE, String.valueOf(type)).build();
- intent.setData(uri);
-
- final Notification.Builder builder = new Notification.Builder(context);
- builder.setOngoing(true)
- .setProgress(totalCount, currentCount, totalCount == - 1)
- .setTicker(tickerText)
- .setContentTitle(description)
- .setSmallIcon(type == VCardService.TYPE_IMPORT
- ? android.R.drawable.stat_sys_download
- : android.R.drawable.stat_sys_upload)
- .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
- if (totalCount > 0) {
- builder.setContentText(context.getString(R.string.percentage,
- String.valueOf(currentCount * 100 / totalCount)));
- }
- return builder.getNotification();
- }
-
- /**
- * Constructs a Notification telling users the process is canceled.
- *
- * @param context
- * @param description Content of the Notification
- */
- /* package */ static Notification constructCancelNotification(
- Context context, String description) {
- return new Notification.Builder(context)
- .setAutoCancel(true)
- .setSmallIcon(android.R.drawable.stat_notify_error)
- .setContentTitle(description)
- .setContentText(description)
- .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0))
- .getNotification();
- }
-
- /**
- * Constructs a Notification telling users the process is finished.
- *
- * @param context
- * @param description Content of the Notification
- * @param intent Intent to be launched when the Notification is clicked. Can be null.
- */
- /* package */ static Notification constructFinishNotification(
- Context context, String title, String description, Intent intent) {
- return new Notification.Builder(context)
- .setAutoCancel(true)
- .setSmallIcon(android.R.drawable.stat_sys_download_done)
- .setContentTitle(title)
- .setContentText(description)
- .setContentIntent(PendingIntent.getActivity(context, 0,
- (intent != null ? intent : new Intent()), 0))
- .getNotification();
- }
-
- /**
- * Constructs a Notification telling the vCard import has failed.
- *
- * @param context
- * @param reason The reason why the import has failed. Shown in description field.
- */
- /* package */ static Notification constructImportFailureNotification(
- Context context, String reason) {
- return new Notification.Builder(context)
- .setAutoCancel(true)
- .setSmallIcon(android.R.drawable.stat_notify_error)
- .setContentTitle(context.getString(R.string.vcard_import_failed))
- .setContentText(reason)
- .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0))
- .getNotification();
- }
-
- @Override
- public void onComplete() {
- mContext.finish();
- }
-}
diff --git a/src/com/android/contacts/vcard/ProcessorBase.java b/src/com/android/contacts/vcard/ProcessorBase.java
deleted file mode 100644
index 073bcbb..0000000
--- a/src/com/android/contacts/vcard/ProcessorBase.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.RunnableFuture;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A base processor class. One instance processes vCard one import/export request (imports a given
- * vCard or exports a vCard). Expected to be used with {@link ExecutorService}.
- *
- * This instance starts itself with {@link #run()} method, and can be cancelled with
- * {@link #cancel(boolean)}. Users can check the processor's status using {@link #isCancelled()}
- * and {@link #isDone()} asynchronously.
- *
- * {@link #get()} and {@link #get(long, TimeUnit)}, which are form {@link Future}, aren't
- * supported and {@link UnsupportedOperationException} will be just thrown when they are called.
- */
-public abstract class ProcessorBase implements RunnableFuture<Object> {
-
- /**
- * @return the type of the processor. Must be {@link VCardService#TYPE_IMPORT} or
- * {@link VCardService#TYPE_EXPORT}.
- */
- public abstract int getType();
-
- @Override
- public abstract void run();
-
- /**
- * Cancels this operation.
- *
- * @param mayInterruptIfRunning ignored. When this method is called, the instance
- * stops processing and finish itself even if the thread is running.
- *
- * @see Future#cancel(boolean)
- */
- @Override
- public abstract boolean cancel(boolean mayInterruptIfRunning);
- @Override
- public abstract boolean isCancelled();
- @Override
- public abstract boolean isDone();
-
- /**
- * Just throws {@link UnsupportedOperationException}.
- */
- @Override
- public final Object get() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Just throws {@link UnsupportedOperationException}.
- */
- @Override
- public final Object get(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException();
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/vcard/SelectAccountActivity.java b/src/com/android/contacts/vcard/SelectAccountActivity.java
deleted file mode 100644
index f74cc8c..0000000
--- a/src/com/android/contacts/vcard/SelectAccountActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.contacts.ContactsActivity;
-import com.android.contacts.R;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.util.AccountSelectionUtil;
-
-import java.util.List;
-
-public class SelectAccountActivity extends ContactsActivity {
- private static final String LOG_TAG = "SelectAccountActivity";
-
- public static final String ACCOUNT_NAME = "account_name";
- public static final String ACCOUNT_TYPE = "account_type";
- public static final String DATA_SET = "data_set";
-
- private class CancelListener
- implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- public void onCancel(DialogInterface dialog) {
- finish();
- }
- }
-
- private AccountSelectionUtil.AccountSelectedListener mAccountSelectionListener;
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
-
- // There's three possibilities:
- // - more than one accounts -> ask the user
- // - just one account -> use the account without asking the user
- // - no account -> use phone-local storage without asking the user
- final int resId = R.string.import_from_sdcard;
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
- final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
- if (accountList.size() == 0) {
- Log.w(LOG_TAG, "Account does not exist");
- finish();
- return;
- } else if (accountList.size() == 1) {
- final AccountWithDataSet account = accountList.get(0);
- final Intent intent = new Intent();
- intent.putExtra(ACCOUNT_NAME, account.name);
- intent.putExtra(ACCOUNT_TYPE, account.type);
- intent.putExtra(DATA_SET, account.dataSet);
- setResult(RESULT_OK, intent);
- finish();
- return;
- }
-
- Log.i(LOG_TAG, "The number of available accounts: " + accountList.size());
-
- // Multiple accounts. Let users to select one.
- mAccountSelectionListener =
- new AccountSelectionUtil.AccountSelectedListener(
- this, accountList, resId) {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- final AccountWithDataSet account = mAccountList.get(which);
- final Intent intent = new Intent();
- intent.putExtra(ACCOUNT_NAME, account.name);
- intent.putExtra(ACCOUNT_TYPE, account.type);
- intent.putExtra(DATA_SET, account.dataSet);
- setResult(RESULT_OK, intent);
- finish();
- }
- };
- showDialog(resId);
- return;
- }
-
- @Override
- protected Dialog onCreateDialog(int resId, Bundle bundle) {
- switch (resId) {
- case R.string.import_from_sdcard: {
- if (mAccountSelectionListener == null) {
- throw new NullPointerException(
- "mAccountSelectionListener must not be null.");
- }
- return AccountSelectionUtil.getSelectAccountDialog(this, resId,
- mAccountSelectionListener,
- new CancelListener());
- }
- }
- return super.onCreateDialog(resId, bundle);
- }
-}
diff --git a/src/com/android/contacts/vcard/VCardCommonArguments.java b/src/com/android/contacts/vcard/VCardCommonArguments.java
deleted file mode 100644
index 06b49a2..0000000
--- a/src/com/android/contacts/vcard/VCardCommonArguments.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.vcard;
-
-/**
- * Argument constants used by many activities and services.
- */
-public class VCardCommonArguments {
-
- // Argument used to pass calling activities to the target activity or service.
- // The value should be a string class name (e.g. com.android.contacts.vcard.VCardCommonArgs)
- public static final String ARG_CALLING_ACTIVITY = "CALLING_ACTIVITY";
-}
diff --git a/src/com/android/contacts/vcard/VCardImportExportListener.java b/src/com/android/contacts/vcard/VCardImportExportListener.java
deleted file mode 100644
index 82d7c21..0000000
--- a/src/com/android/contacts/vcard/VCardImportExportListener.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.contacts.vcard;
-
-import android.net.Uri;
-
-import com.android.vcard.VCardEntry;
-
-interface VCardImportExportListener {
- void onImportProcessed(ImportRequest request, int jobId, int sequence);
- void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
- int totalCount);
- void onImportFinished(ImportRequest request, int jobId, Uri uri);
- void onImportFailed(ImportRequest request);
- void onImportCanceled(ImportRequest request, int jobId);
-
- void onExportProcessed(ExportRequest request, int jobId);
- void onExportFailed(ExportRequest request);
-
- void onCancelRequest(CancelRequest request, int type);
- void onComplete();
-}
diff --git a/src/com/android/contacts/vcard/VCardService.java b/src/com/android/contacts/vcard/VCardService.java
deleted file mode 100644
index 056f89a..0000000
--- a/src/com/android/contacts/vcard/VCardService.java
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts.vcard;
-
-import android.app.Service;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.media.MediaScannerConnection;
-import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.contacts.R;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- * The class responsible for handling vCard import/export requests.
- *
- * This Service creates one ImportRequest/ExportRequest object (as Runnable) per request and push
- * it to {@link ExecutorService} with single thread executor. The executor handles each request
- * one by one, and notifies users when needed.
- */
-// TODO: Using IntentService looks simpler than using Service + ServiceConnection though this
-// works fine enough. Investigate the feasibility.
-public class VCardService extends Service {
- private final static String LOG_TAG = "VCardService";
-
- /* package */ final static boolean DEBUG = false;
-
- /* package */ static final int MSG_IMPORT_REQUEST = 1;
- /* package */ static final int MSG_EXPORT_REQUEST = 2;
- /* package */ static final int MSG_CANCEL_REQUEST = 3;
- /* package */ static final int MSG_REQUEST_AVAILABLE_EXPORT_DESTINATION = 4;
- /* package */ static final int MSG_SET_AVAILABLE_EXPORT_DESTINATION = 5;
-
- /**
- * Specifies the type of operation. Used when constructing a notification, canceling
- * some operation, etc.
- */
- /* package */ static final int TYPE_IMPORT = 1;
- /* package */ static final int TYPE_EXPORT = 2;
-
- /* package */ static final String CACHE_FILE_PREFIX = "import_tmp_";
-
-
- private class CustomMediaScannerConnectionClient implements MediaScannerConnectionClient {
- final MediaScannerConnection mConnection;
- final String mPath;
-
- public CustomMediaScannerConnectionClient(String path) {
- mConnection = new MediaScannerConnection(VCardService.this, this);
- mPath = path;
- }
-
- public void start() {
- mConnection.connect();
- }
-
- @Override
- public void onMediaScannerConnected() {
- if (DEBUG) { Log.d(LOG_TAG, "Connected to MediaScanner. Start scanning."); }
- mConnection.scanFile(mPath, null);
- }
-
- @Override
- public void onScanCompleted(String path, Uri uri) {
- if (DEBUG) { Log.d(LOG_TAG, "scan completed: " + path); }
- mConnection.disconnect();
- removeConnectionClient(this);
- }
- }
-
- // Should be single thread, as we don't want to simultaneously handle import and export
- // requests.
- private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
-
- private int mCurrentJobId;
-
- // Stores all unfinished import/export jobs which will be executed by mExecutorService.
- // Key is jobId.
- private final SparseArray<ProcessorBase> mRunningJobMap = new SparseArray<ProcessorBase>();
- // Stores ScannerConnectionClient objects until they finish scanning requested files.
- // Uses List class for simplicity. It's not costly as we won't have multiple objects in
- // almost all cases.
- private final List<CustomMediaScannerConnectionClient> mRemainingScannerConnections =
- new ArrayList<CustomMediaScannerConnectionClient>();
-
- /* ** vCard exporter params ** */
- // If true, VCardExporter is able to emits files longer than 8.3 format.
- private static final boolean ALLOW_LONG_FILE_NAME = false;
-
- private File mTargetDirectory;
- private String mFileNamePrefix;
- private String mFileNameSuffix;
- private int mFileIndexMinimum;
- private int mFileIndexMaximum;
- private String mFileNameExtension;
- private Set<String> mExtensionsToConsider;
- private String mErrorReason;
- private MyBinder mBinder;
-
- private String mCallingActivity;
-
- // File names currently reserved by some export job.
- private final Set<String> mReservedDestination = new HashSet<String>();
- /* ** end of vCard exporter params ** */
-
- public class MyBinder extends Binder {
- public VCardService getService() {
- return VCardService.this;
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mBinder = new MyBinder();
- if (DEBUG) Log.d(LOG_TAG, "vCard Service is being created.");
- initExporterParams();
- }
-
- private void initExporterParams() {
- mTargetDirectory = Environment.getExternalStorageDirectory();
- mFileNamePrefix = getString(R.string.config_export_file_prefix);
- mFileNameSuffix = getString(R.string.config_export_file_suffix);
- mFileNameExtension = getString(R.string.config_export_file_extension);
-
- mExtensionsToConsider = new HashSet<String>();
- mExtensionsToConsider.add(mFileNameExtension);
-
- final String additionalExtensions =
- getString(R.string.config_export_extensions_to_consider);
- if (!TextUtils.isEmpty(additionalExtensions)) {
- for (String extension : additionalExtensions.split(",")) {
- String trimed = extension.trim();
- if (trimed.length() > 0) {
- mExtensionsToConsider.add(trimed);
- }
- }
- }
-
- final Resources resources = getResources();
- mFileIndexMinimum = resources.getInteger(R.integer.config_export_file_min_index);
- mFileIndexMaximum = resources.getInteger(R.integer.config_export_file_max_index);
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int id) {
- mCallingActivity = intent.getExtras().getString(
- VCardCommonArguments.ARG_CALLING_ACTIVITY);
- return START_STICKY;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public void onDestroy() {
- if (DEBUG) Log.d(LOG_TAG, "VCardService is being destroyed.");
- cancelAllRequestsAndShutdown();
- clearCache();
- super.onDestroy();
- }
-
- public synchronized void handleImportRequest(List<ImportRequest> requests,
- VCardImportExportListener listener) {
- if (DEBUG) {
- final ArrayList<String> uris = new ArrayList<String>();
- final ArrayList<String> displayNames = new ArrayList<String>();
- for (ImportRequest request : requests) {
- uris.add(request.uri.toString());
- displayNames.add(request.displayName);
- }
- Log.d(LOG_TAG,
- String.format("received multiple import request (uri: %s, displayName: %s)",
- uris.toString(), displayNames.toString()));
- }
- final int size = requests.size();
- for (int i = 0; i < size; i++) {
- ImportRequest request = requests.get(i);
-
- if (tryExecute(new ImportProcessor(this, listener, request, mCurrentJobId))) {
- if (listener != null) {
- listener.onImportProcessed(request, mCurrentJobId, i);
- }
- mCurrentJobId++;
- } else {
- if (listener != null) {
- listener.onImportFailed(request);
- }
- // A rejection means executor doesn't run any more. Exit.
- break;
- }
- }
- }
-
- public synchronized void handleExportRequest(ExportRequest request,
- VCardImportExportListener listener) {
- if (tryExecute(new ExportProcessor(this, request, mCurrentJobId, mCallingActivity))) {
- final String path = request.destUri.getEncodedPath();
- if (DEBUG) Log.d(LOG_TAG, "Reserve the path " + path);
- if (!mReservedDestination.add(path)) {
- Log.w(LOG_TAG,
- String.format("The path %s is already reserved. Reject export request",
- path));
- if (listener != null) {
- listener.onExportFailed(request);
- }
- return;
- }
-
- if (listener != null) {
- listener.onExportProcessed(request, mCurrentJobId);
- }
- mCurrentJobId++;
- } else {
- if (listener != null) {
- listener.onExportFailed(request);
- }
- }
- }
-
- /**
- * Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
- * @return true when successful.
- */
- private synchronized boolean tryExecute(ProcessorBase processor) {
- try {
- if (DEBUG) {
- Log.d(LOG_TAG, "Executor service status: shutdown: " + mExecutorService.isShutdown()
- + ", terminated: " + mExecutorService.isTerminated());
- }
- mExecutorService.execute(processor);
- mRunningJobMap.put(mCurrentJobId, processor);
- return true;
- } catch (RejectedExecutionException e) {
- Log.w(LOG_TAG, "Failed to excetute a job.", e);
- return false;
- }
- }
-
- public synchronized void handleCancelRequest(CancelRequest request,
- VCardImportExportListener listener) {
- final int jobId = request.jobId;
- if (DEBUG) Log.d(LOG_TAG, String.format("Received cancel request. (id: %d)", jobId));
-
- final ProcessorBase processor = mRunningJobMap.get(jobId);
- mRunningJobMap.remove(jobId);
-
- if (processor != null) {
- processor.cancel(true);
- final int type = processor.getType();
- if (listener != null) {
- listener.onCancelRequest(request, type);
- }
- if (type == TYPE_EXPORT) {
- final String path =
- ((ExportProcessor)processor).getRequest().destUri.getEncodedPath();
- Log.i(LOG_TAG,
- String.format("Cancel reservation for the path %s if appropriate", path));
- if (!mReservedDestination.remove(path)) {
- Log.w(LOG_TAG, "Not reserved.");
- }
- }
- } else {
- Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
- }
- stopServiceIfAppropriate();
- }
-
- public synchronized void handleRequestAvailableExportDestination(final Messenger messenger) {
- if (DEBUG) Log.d(LOG_TAG, "Received available export destination request.");
- final String path = getAppropriateDestination(mTargetDirectory);
- final Message message;
- if (path != null) {
- message = Message.obtain(null,
- VCardService.MSG_SET_AVAILABLE_EXPORT_DESTINATION, 0, 0, path);
- } else {
- message = Message.obtain(null,
- VCardService.MSG_SET_AVAILABLE_EXPORT_DESTINATION,
- R.id.dialog_fail_to_export_with_reason, 0, mErrorReason);
- }
- try {
- messenger.send(message);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Failed to send reply for available export destination request.", e);
- }
- }
-
- /**
- * Checks job list and call {@link #stopSelf()} when there's no job and no scanner connection
- * is remaining.
- * A new job (import/export) cannot be submitted any more after this call.
- */
- private synchronized void stopServiceIfAppropriate() {
- if (mRunningJobMap.size() > 0) {
- final int size = mRunningJobMap.size();
-
- // Check if there are processors which aren't finished yet. If we still have ones to
- // process, we cannot stop the service yet. Also clean up already finished processors
- // here.
-
- // Job-ids to be removed. At first all elements in the array are invalid and will
- // be filled with real job-ids from the array's top. When we find a not-yet-finished
- // processor, then we start removing those finished jobs. In that case latter half of
- // this array will be invalid.
- final int[] toBeRemoved = new int[size];
- for (int i = 0; i < size; i++) {
- final int jobId = mRunningJobMap.keyAt(i);
- final ProcessorBase processor = mRunningJobMap.valueAt(i);
- if (!processor.isDone()) {
- Log.i(LOG_TAG, String.format("Found unfinished job (id: %d)", jobId));
-
- // Remove processors which are already "done", all of which should be before
- // processors which aren't done yet.
- for (int j = 0; j < i; j++) {
- mRunningJobMap.remove(toBeRemoved[j]);
- }
- return;
- }
-
- // Remember the finished processor.
- toBeRemoved[i] = jobId;
- }
-
- // We're sure we can remove all. Instead of removing one by one, just call clear().
- mRunningJobMap.clear();
- }
-
- if (!mRemainingScannerConnections.isEmpty()) {
- Log.i(LOG_TAG, "MediaScanner update is in progress.");
- return;
- }
-
- Log.i(LOG_TAG, "No unfinished job. Stop this service.");
- mExecutorService.shutdown();
- stopSelf();
- }
-
- /* package */ synchronized void updateMediaScanner(String path) {
- if (DEBUG) {
- Log.d(LOG_TAG, "MediaScanner is being updated: " + path);
- }
-
- if (mExecutorService.isShutdown()) {
- Log.w(LOG_TAG, "MediaScanner update is requested after executor's being shut down. " +
- "Ignoring the update request");
- return;
- }
- final CustomMediaScannerConnectionClient client =
- new CustomMediaScannerConnectionClient(path);
- mRemainingScannerConnections.add(client);
- client.start();
- }
-
- private synchronized void removeConnectionClient(
- CustomMediaScannerConnectionClient client) {
- if (DEBUG) {
- Log.d(LOG_TAG, "Removing custom MediaScannerConnectionClient.");
- }
- mRemainingScannerConnections.remove(client);
- stopServiceIfAppropriate();
- }
-
- /* package */ synchronized void handleFinishImportNotification(
- int jobId, boolean successful) {
- if (DEBUG) {
- Log.d(LOG_TAG, String.format("Received vCard import finish notification (id: %d). "
- + "Result: %b", jobId, (successful ? "success" : "failure")));
- }
- mRunningJobMap.remove(jobId);
- stopServiceIfAppropriate();
- }
-
- /* package */ synchronized void handleFinishExportNotification(
- int jobId, boolean successful) {
- if (DEBUG) {
- Log.d(LOG_TAG, String.format("Received vCard export finish notification (id: %d). "
- + "Result: %b", jobId, (successful ? "success" : "failure")));
- }
- final ProcessorBase job = mRunningJobMap.get(jobId);
- mRunningJobMap.remove(jobId);
- if (job == null) {
- Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
- } else if (!(job instanceof ExportProcessor)) {
- Log.w(LOG_TAG,
- String.format("Removed job (id: %s) isn't ExportProcessor", jobId));
- } else {
- final String path = ((ExportProcessor)job).getRequest().destUri.getEncodedPath();
- if (DEBUG) Log.d(LOG_TAG, "Remove reserved path " + path);
- mReservedDestination.remove(path);
- }
-
- stopServiceIfAppropriate();
- }
-
- /**
- * Cancels all the import/export requests and calls {@link ExecutorService#shutdown()}, which
- * means this Service becomes no longer ready for import/export requests.
- *
- * Mainly called from onDestroy().
- */
- private synchronized void cancelAllRequestsAndShutdown() {
- for (int i = 0; i < mRunningJobMap.size(); i++) {
- mRunningJobMap.valueAt(i).cancel(true);
- }
- mRunningJobMap.clear();
- mExecutorService.shutdown();
- }
-
- /**
- * Removes import caches stored locally.
- */
- private void clearCache() {
- for (final String fileName : fileList()) {
- if (fileName.startsWith(CACHE_FILE_PREFIX)) {
- // We don't want to keep all the caches so we remove cache files old enough.
- Log.i(LOG_TAG, "Remove a temporary file: " + fileName);
- deleteFile(fileName);
- }
- }
- }
-
- /**
- * Returns an appropriate file name for vCard export. Returns null when impossible.
- *
- * @return destination path for a vCard file to be exported. null on error and mErrorReason
- * is correctly set.
- */
- private String getAppropriateDestination(final File destDirectory) {
- /*
- * Here, file names have 5 parts: directory, prefix, index, suffix, and extension.
- * e.g. "/mnt/sdcard/prfx00001sfx.vcf" -> "/mnt/sdcard", "prfx", "00001", "sfx", and ".vcf"
- * (In default, prefix and suffix is empty, so usually the destination would be
- * /mnt/sdcard/00001.vcf.)
- *
- * This method increments "index" part from 1 to maximum, and checks whether any file name
- * following naming rule is available. If there's no file named /mnt/sdcard/00001.vcf, the
- * name will be returned to a caller. If there are 00001.vcf 00002.vcf, 00003.vcf is
- * returned.
- *
- * There may not be any appropriate file name. If there are 99999 vCard files in the
- * storage, for example, there's no appropriate name, so this method returns
- * null.
- */
-
- // Count the number of digits of mFileIndexMaximum
- // e.g. When mFileIndexMaximum is 99999, fileIndexDigit becomes 5, as we will count the
- int fileIndexDigit = 0;
- {
- // Calling Math.Log10() is costly.
- int tmp;
- for (fileIndexDigit = 0, tmp = mFileIndexMaximum; tmp > 0;
- fileIndexDigit++, tmp /= 10) {
- }
- }
-
- // %s05d%s (e.g. "p00001s")
- final String bodyFormat = "%s%0" + fileIndexDigit + "d%s";
-
- if (!ALLOW_LONG_FILE_NAME) {
- final String possibleBody =
- String.format(bodyFormat, mFileNamePrefix, 1, mFileNameSuffix);
- if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
- Log.e(LOG_TAG, "This code does not allow any long file name.");
- mErrorReason = getString(R.string.fail_reason_too_long_filename,
- String.format("%s.%s", possibleBody, mFileNameExtension));
- Log.w(LOG_TAG, "File name becomes too long.");
- return null;
- }
- }
-
- for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
- boolean numberIsAvailable = true;
- final String body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
- // Make sure that none of the extensions of mExtensionsToConsider matches. If this
- // number is free, we'll go ahead with mFileNameExtension (which is included in
- // mExtensionsToConsider)
- for (String possibleExtension : mExtensionsToConsider) {
- final File file = new File(destDirectory, body + "." + possibleExtension);
- final String path = file.getAbsolutePath();
- synchronized (this) {
- // Is this being exported right now? Skip this number
- if (mReservedDestination.contains(path)) {
- if (DEBUG) {
- Log.d(LOG_TAG, String.format("%s is already being exported.", path));
- }
- numberIsAvailable = false;
- break;
- }
- }
- if (file.exists()) {
- numberIsAvailable = false;
- break;
- }
- }
- if (numberIsAvailable) {
- return new File(destDirectory, body + "." + mFileNameExtension).getAbsolutePath();
- }
- }
-
- Log.w(LOG_TAG, "Reached vCard number limit. Maybe there are too many vCard in the storage");
- mErrorReason = getString(R.string.fail_reason_too_many_vcard);
- return null;
- }
-}