1d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng/* 2d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * Copyright (C) 2010 The Android Open Source Project 3d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * 4d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 5d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * you may not use this file except in compliance with the License. 6d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * You may obtain a copy of the License at 7d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * 8d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 9d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * 10d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * Unless required by applicable law or agreed to in writing, software 11d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 12d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * See the License for the specific language governing permissions and 14d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * limitations under the License. 15d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng */ 1669c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.vcard; 17d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 18d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.app.Notification; 19d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.app.NotificationManager; 20d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.content.ContentResolver; 21d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.content.Context; 22d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.content.Intent; 23d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.content.res.Resources; 24d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.net.Uri; 25142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wangimport android.os.Handler; 26142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wangimport android.os.Message; 27d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.provider.ContactsContract.Contacts; 28d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.provider.ContactsContract.RawContactsEntity; 29d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.text.TextUtils; 30d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport android.util.Log; 31142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wangimport android.widget.Toast; 32d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 333f6a2444e0134b7380cdb2e13abf4bf1163336d0Arthur Wangimport com.android.contacts.R; 343a0b483ff715959b88d7ef20877a7c89d211fde2Walter Jangimport com.android.contactsbind.FeedbackHelper; 35d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport com.android.vcard.VCardComposer; 36d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport com.android.vcard.VCardConfig; 37d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 38d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.BufferedWriter; 39d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.FileNotFoundException; 40d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.IOException; 41d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.OutputStream; 42d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.OutputStreamWriter; 43d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengimport java.io.Writer; 44d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 45d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng/** 46d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * Class for processing one export request from a user. Dropped after exporting requested Uri(s). 47d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng * {@link VCardService} will create another object when there is another export request. 48d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng */ 49d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Chengpublic class ExportProcessor extends ProcessorBase { 50d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private static final String LOG_TAG = "VCardExport"; 51d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private static final boolean DEBUG = VCardService.DEBUG; 52d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 53d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final VCardService mService; 54d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final ContentResolver mResolver; 55d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final NotificationManager mNotificationManager; 56d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final ExportRequest mExportRequest; 57d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final int mJobId; 58d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private final String mCallingActivity; 59d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 60d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private volatile boolean mCanceled; 61d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private volatile boolean mDone; 62d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 63142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang private final int SHOW_READY_TOAST = 1; 64142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang private final Handler handler = new Handler() { 65142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang public void handleMessage(Message msg) { 66142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang if (msg.arg1 == SHOW_READY_TOAST) { 67142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang // This message is long, so we set the duration to LENGTH_LONG. 68142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang Toast.makeText(mService, 69142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang R.string.exporting_vcard_finished_toast, Toast.LENGTH_LONG).show(); 70142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } 71142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang 72142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } 73142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang }; 74142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang 75d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId, 76d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng String callingActivity) { 77d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService = service; 78d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mResolver = service.getContentResolver(); 79d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mNotificationManager = 80d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng (NotificationManager)mService.getSystemService(Context.NOTIFICATION_SERVICE); 81d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mExportRequest = exportRequest; 82d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mJobId = jobId; 83d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mCallingActivity = callingActivity; 84d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 85d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 86d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng @Override 87d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public final int getType() { 88d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return VCardService.TYPE_EXPORT; 89d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 90d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 91d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng @Override 92d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public void run() { 93d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // ExecutorService ignores RuntimeException, so we need to show it here. 94d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng try { 95d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng runInternal(); 96d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 97d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (isCancelled()) { 98d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doCancelNotification(); 99d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 1003a0b483ff715959b88d7ef20877a7c89d211fde2Walter Jang } catch (OutOfMemoryError|RuntimeException e) { 1013a0b483ff715959b88d7ef20877a7c89d211fde2Walter Jang FeedbackHelper.sendFeedback(mService, LOG_TAG, "Failed to process vcard export", e); 102d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng throw e; 103d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } finally { 104d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng synchronized (this) { 105d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mDone = true; 106d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 107d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 108d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 109d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 110d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private void runInternal() { 111d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (DEBUG) Log.d(LOG_TAG, String.format("vCard export (id: %d) has started.", mJobId)); 112d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final ExportRequest request = mExportRequest; 113d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng VCardComposer composer = null; 114d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Writer writer = null; 115d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng boolean successful = false; 116d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng try { 117d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (isCancelled()) { 118d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.i(LOG_TAG, "Export request is cancelled before handling the request"); 119d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 120d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 121d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Uri uri = request.destUri; 122d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final OutputStream outputStream; 123d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng try { 124d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng outputStream = mResolver.openOutputStream(uri); 125d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } catch (FileNotFoundException e) { 126d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.w(LOG_TAG, "FileNotFoundException thrown", e); 127d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // Need concise title. 128d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 129d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String errorReason = 130d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.fail_reason_could_not_open_file, 131d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng uri, e.getMessage()); 132d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doFinishNotification(errorReason, null); 133d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 134d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 135d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 136d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String exportType = request.exportType; 137d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final int vcardType; 138d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (TextUtils.isEmpty(exportType)) { 139d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng vcardType = VCardConfig.getVCardTypeFromString( 140d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.config_export_vcard_type)); 141d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } else { 142d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng vcardType = VCardConfig.getVCardTypeFromString(exportType); 143d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 144d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 145d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng composer = new VCardComposer(mService, vcardType, true); 146d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 147d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // for test 148d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC | 149d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES); 150d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // composer = new VCardComposer(ExportVCardActivity.this, vcardType, true); 151d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 152d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng writer = new BufferedWriter(new OutputStreamWriter(outputStream)); 153d4793dcdd624e3b6026a56b6e9ab76b8f7a51f69Yorke Lee final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI; 154d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // TODO: should provide better selection. 155d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID}, 156d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng null, null, 157d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng null, contentUriForRawContactsEntity)) { 158d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String errorReason = composer.getErrorReason(); 159d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason); 160d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String translatedErrorReason = 161d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng translateComposerError(errorReason); 162d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String title = 163d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.fail_reason_could_not_initialize_exporter, 164d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng translatedErrorReason); 165d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doFinishNotification(title, null); 166d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 167d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 168d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 169d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final int total = composer.getCount(); 170d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (total == 0) { 171d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String title = 172d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.fail_reason_no_exportable_contact); 173d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doFinishNotification(title, null); 174d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 175d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 176d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 177d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng int current = 1; // 1-origin 178d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng while (!composer.isAfterLast()) { 179d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (isCancelled()) { 180d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.i(LOG_TAG, "Export request is cancelled during composing vCard"); 181d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 182d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 183d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng try { 184d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng writer.write(composer.createOneEntry()); 185d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } catch (IOException e) { 186d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String errorReason = composer.getErrorReason(); 187d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.e(LOG_TAG, "Failed to read a contact: " + errorReason); 188d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String translatedErrorReason = 189d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng translateComposerError(errorReason); 190d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String title = 191d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.fail_reason_error_occurred_during_export, 192d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng translatedErrorReason); 193d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doFinishNotification(title, null); 194d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return; 195d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 196d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 197d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // vCard export is quite fast (compared to import), and frequent notifications 198d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng // bother notification bar too much. 199d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (current % 100 == 1) { 200d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng doProgressNotification(uri, total, current); 201d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 202d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng current++; 203d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 204d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.i(LOG_TAG, "Successfully finished exporting vCard " + request.destUri); 205d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 206d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (DEBUG) { 207d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.d(LOG_TAG, "Ask MediaScanner to scan the file: " + request.destUri.getPath()); 208d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 209d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.updateMediaScanner(request.destUri.getPath()); 210d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 211d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng successful = true; 2127a243016264ef766f36d8800eb31235fc8f510ebWalter Jang final String filename = ExportVCardActivity.getOpenableUriDisplayName(mService, uri); 213142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang // If it is a local file (i.e. not a file from Drive), we need to allow user to share 214142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang // the file by pressing the notification; otherwise, it would be a file in Drive, we 215142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang // don't need to enable this action in notification since the file is already uploaded. 216142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang if (isLocalFile(uri)) { 217142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang final Message msg = handler.obtainMessage(); 218142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang msg.arg1 = SHOW_READY_TOAST; 219142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang handler.sendMessage(msg); 220142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang doFinishNotificationWithShareAction( 221142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang mService.getString(R.string.exporting_vcard_finished_title_fallback), 222142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang mService.getString(R.string.touch_to_share_contacts), uri); 223142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } else { 224142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang final String title = filename == null 225142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang ? mService.getString(R.string.exporting_vcard_finished_title_fallback) 226142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang : mService.getString(R.string.exporting_vcard_finished_title, filename); 227142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang doFinishNotification(title, null); 228142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } 229d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } finally { 230d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (composer != null) { 231d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng composer.terminate(); 232d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 233d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (writer != null) { 234d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng try { 235d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng writer.close(); 236d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } catch (IOException e) { 237d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng Log.w(LOG_TAG, "IOException is thrown during close(). Ignored. " + e); 238d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 239d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 240d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.handleFinishExportNotification(mJobId, successful); 241d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 242d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 243d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 244142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang private boolean isLocalFile(Uri uri) { 245142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang final String authority = uri.getAuthority(); 246142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang return mService.getString(R.string.contacts_file_provider_authority).equals(authority); 247142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } 248142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang 249d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private String translateComposerError(String errorMessage) { 250d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Resources resources = mService.getResources(); 251d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) { 252d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return resources.getString(R.string.composer_failed_to_get_database_infomation); 253d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } else if (VCardComposer.FAILURE_REASON_NO_ENTRY.equals(errorMessage)) { 254d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return resources.getString(R.string.composer_has_no_exportable_contact); 255d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } else if (VCardComposer.FAILURE_REASON_NOT_INITIALIZED.equals(errorMessage)) { 256d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return resources.getString(R.string.composer_not_initialized); 257d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } else { 258d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return errorMessage; 259d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 260d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 261d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 262d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private void doProgressNotification(Uri uri, int totalCount, int currentCount) { 263d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String displayName = uri.getLastPathSegment(); 264d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String description = 265d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.exporting_contact_list_message, displayName); 266d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String tickerText = 267d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mService.getString(R.string.exporting_contact_list_title); 268d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Notification notification = 269d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng NotificationImportExportListener.constructProgressNotification(mService, 270d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng VCardService.TYPE_EXPORT, description, tickerText, mJobId, displayName, 271d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng totalCount, currentCount); 272f26ccc7c4e94815ef9e49a2851b4420a7360a412Wenyi Wang mService.startForeground(mJobId, notification); 273d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 274d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 275d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private void doCancelNotification() { 276d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (DEBUG) Log.d(LOG_TAG, "send cancel notification"); 277d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final String description = mService.getString(R.string.exporting_vcard_canceled_title, 278d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mExportRequest.destUri.getLastPathSegment()); 279d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Notification notification = 280d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng NotificationImportExportListener.constructCancelNotification(mService, description); 281d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 282d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mJobId, notification); 283d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 284d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 285d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng private void doFinishNotification(final String title, final String description) { 286d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description); 287d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Intent intent = new Intent(); 288d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng intent.setClassName(mService, mCallingActivity); 289d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng final Notification notification = 290d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng NotificationImportExportListener.constructFinishNotification(mService, title, 291d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng description, intent); 292d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 293d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mJobId, notification); 294d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 295d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 296142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang /** 297142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang * Pass intent with ACTION_SEND to notification so that user can press the notification to 298142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang * share contacts. 299142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang */ 300142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang private void doFinishNotificationWithShareAction(final String title, final String 301142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang description, Uri uri) { 302142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description); 303142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang final Intent intent = new Intent(Intent.ACTION_SEND); 304142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang intent.setType(Contacts.CONTENT_VCARD_TYPE); 305142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang intent.putExtra(Intent.EXTRA_STREAM, uri); 306b81f6ebdc12f39cda46546de400f1044f3f5dea3Wenyi Wang // Securely grant access using temporary access permissions 307b81f6ebdc12f39cda46546de400f1044f3f5dea3Wenyi Wang intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 308b81f6ebdc12f39cda46546de400f1044f3f5dea3Wenyi Wang // Build notification 309142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang final Notification notification = 310142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang NotificationImportExportListener.constructFinishNotificationWithFlags( 311142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang mService, title, description, intent, Intent.FLAG_ACTIVITY_NEW_TASK); 312142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 313142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang mJobId, notification); 314142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang } 315142a344c5c71c28a616b64b21d36809637d3c6f9Wenyi Wang 316d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng @Override 317d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public synchronized boolean cancel(boolean mayInterruptIfRunning) { 318d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (DEBUG) Log.d(LOG_TAG, "received cancel request"); 319d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng if (mDone || mCanceled) { 320d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return false; 321d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 322d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng mCanceled = true; 323d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return true; 324d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 325d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 326d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng @Override 327d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public synchronized boolean isCancelled() { 328d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return mCanceled; 329d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 330d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 331d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng @Override 332d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public synchronized boolean isDone() { 333d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return mDone; 334d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 335d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng 336d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng public ExportRequest getRequest() { 337d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng return mExportRequest; 338d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng } 339d80c4348dd6db1046fdade375a8d8c616d93e7acChiao Cheng} 340