17903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng/*
27903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Copyright (C) 2010 The Android Open Source Project
37903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng *
47903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
57903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * you may not use this file except in compliance with the License.
67903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * You may obtain a copy of the License at
77903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng *
87903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
97903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng *
107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Unless required by applicable law or agreed to in writing, software
117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * See the License for the specific language governing permissions and
147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * limitations under the License.
157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */
167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengpackage com.android.contacts.common.vcard;
177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.Notification;
197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.app.NotificationManager;
207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.ContentResolver;
217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.Context;
227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.Intent;
237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.content.res.Resources;
247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.net.Uri;
2581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wangimport android.os.Handler;
2681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wangimport android.os.Message;
277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.provider.ContactsContract.Contacts;
287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.provider.ContactsContract.RawContactsEntity;
297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.text.TextUtils;
307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport android.util.Log;
3181c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wangimport android.widget.Toast;
327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.contacts.common.R;
347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardComposer;
357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport com.android.vcard.VCardConfig;
367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.BufferedWriter;
387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.FileNotFoundException;
397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.IOException;
407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.OutputStream;
417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.OutputStreamWriter;
427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengimport java.io.Writer;
437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng/**
457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * Class for processing one export request from a user. Dropped after exporting requested Uri(s).
467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng * {@link VCardService} will create another object when there is another export request.
477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng */
487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Chengpublic class ExportProcessor extends ProcessorBase {
497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private static final String LOG_TAG = "VCardExport";
507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private static final boolean DEBUG = VCardService.DEBUG;
517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final VCardService mService;
537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final ContentResolver mResolver;
547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final NotificationManager mNotificationManager;
557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final ExportRequest mExportRequest;
567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final int mJobId;
577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private final String mCallingActivity;
587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private volatile boolean mCanceled;
607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private volatile boolean mDone;
617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
6281c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    private final int SHOW_READY_TOAST = 1;
6381c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    private final Handler handler = new Handler() {
6481c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        public void handleMessage(Message msg) {
6581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            if (msg.arg1 == SHOW_READY_TOAST) {
6681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                // This message is long, so we set the duration to LENGTH_LONG.
6781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                Toast.makeText(mService,
6881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        R.string.exporting_vcard_finished_toast, Toast.LENGTH_LONG).show();
6981c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            }
7081c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang
7181c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        }
7281c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    };
7381c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang
747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId,
757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            String callingActivity) {
767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mService = service;
777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mResolver = service.getContentResolver();
787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mNotificationManager =
797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                (NotificationManager)mService.getSystemService(Context.NOTIFICATION_SERVICE);
807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mExportRequest = exportRequest;
817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mJobId = jobId;
827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mCallingActivity = callingActivity;
837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    @Override
867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public final int getType() {
877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        return VCardService.TYPE_EXPORT;
887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    @Override
917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public void run() {
927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        // ExecutorService ignores RuntimeException, so we need to show it here.
937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        try {
947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            runInternal();
957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (isCancelled()) {
977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                doCancelNotification();
987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } catch (OutOfMemoryError e) {
1007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
1017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            throw e;
1027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } catch (RuntimeException e) {
1037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            Log.e(LOG_TAG, "RuntimeException thrown during export", e);
1047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            throw e;
1057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } finally {
1067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            synchronized (this) {
1077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mDone = true;
1087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        }
1107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
1117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private void runInternal() {
1137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (DEBUG) Log.d(LOG_TAG, String.format("vCard export (id: %d) has started.", mJobId));
1147903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final ExportRequest request = mExportRequest;
1157903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        VCardComposer composer = null;
1167903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        Writer writer = null;
1177903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        boolean successful = false;
1187903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        try {
1197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (isCancelled()) {
1207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                Log.i(LOG_TAG, "Export request is cancelled before handling the request");
1217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                return;
1227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            final Uri uri = request.destUri;
1247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            final OutputStream outputStream;
1257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            try {
1267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                outputStream = mResolver.openOutputStream(uri);
1277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            } catch (FileNotFoundException e) {
1287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                Log.w(LOG_TAG, "FileNotFoundException thrown", e);
1297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                // Need concise title.
1307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                final String errorReason =
1327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    mService.getString(R.string.fail_reason_could_not_open_file,
1337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                            uri, e.getMessage());
1347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                doFinishNotification(errorReason, null);
1357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                return;
1367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            final String exportType = request.exportType;
1397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            final int vcardType;
1407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (TextUtils.isEmpty(exportType)) {
1417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                vcardType = VCardConfig.getVCardTypeFromString(
1427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        mService.getString(R.string.config_export_vcard_type));
1437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            } else {
1447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                vcardType = VCardConfig.getVCardTypeFromString(exportType);
1457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1467903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1477903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            composer = new VCardComposer(mService, vcardType, true);
1487903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1497903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            // for test
1507903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            // int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC |
1517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            //     VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
1527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            // composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);
1537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            writer = new BufferedWriter(new OutputStreamWriter(outputStream));
1559c14089f5a08017413de04b29d2b096b22f74e82Yorke Lee            final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI;
1567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            // TODO: should provide better selection.
1577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID},
1587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    null, null,
1597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    null, contentUriForRawContactsEntity)) {
1607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                final String errorReason = composer.getErrorReason();
1617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
1627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                final String translatedErrorReason =
1637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        translateComposerError(errorReason);
1647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                final String title =
1657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        mService.getString(R.string.fail_reason_could_not_initialize_exporter,
1667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                                translatedErrorReason);
1677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                doFinishNotification(title, null);
1687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                return;
1697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            final int total = composer.getCount();
1727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (total == 0) {
1737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                final String title =
1747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        mService.getString(R.string.fail_reason_no_exportable_contact);
1757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                doFinishNotification(title, null);
1767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                return;
1777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
1787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            int current = 1;  // 1-origin
1807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            while (!composer.isAfterLast()) {
1817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                if (isCancelled()) {
1827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    Log.i(LOG_TAG, "Export request is cancelled during composing vCard");
1837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    return;
1847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                }
1857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                try {
1867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    writer.write(composer.createOneEntry());
1877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                } catch (IOException e) {
1887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    final String errorReason = composer.getErrorReason();
1897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
1907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    final String translatedErrorReason =
1917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                            translateComposerError(errorReason);
1927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    final String title =
1937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                            mService.getString(R.string.fail_reason_error_occurred_during_export,
1947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                                    translatedErrorReason);
1957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    doFinishNotification(title, null);
1967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    return;
1977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                }
1987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
1997903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                // vCard export is quite fast (compared to import), and frequent notifications
2007903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                // bother notification bar too much.
2017903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                if (current % 100 == 1) {
2027903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    doProgressNotification(uri, total, current);
2037903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                }
2047903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                current++;
2057903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
2067903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            Log.i(LOG_TAG, "Successfully finished exporting vCard " + request.destUri);
2077903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
2087903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (DEBUG) {
2097903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                Log.d(LOG_TAG, "Ask MediaScanner to scan the file: " + request.destUri.getPath());
2107903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
2117903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            mService.updateMediaScanner(request.destUri.getPath());
2127903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
2137903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            successful = true;
2146aa0ab91746534fe5b30a1456687485d1b38b85aWalter Jang            final String filename = ExportVCardActivity.getOpenableUriDisplayName(mService, uri);
21581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            // If it is a local file (i.e. not a file from Drive), we need to allow user to share
21681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            // the file by pressing the notification; otherwise, it would be a file in Drive, we
21781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            // don't need to enable this action in notification since the file is already uploaded.
21881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            if (isLocalFile(uri)) {
21981c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                final Message msg = handler.obtainMessage();
22081c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                msg.arg1 = SHOW_READY_TOAST;
22181c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                handler.sendMessage(msg);
22281c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                doFinishNotificationWithShareAction(
22381c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        mService.getString(R.string.exporting_vcard_finished_title_fallback),
22481c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        mService.getString(R.string.touch_to_share_contacts), uri);
22581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            } else {
22681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                final String title = filename == null
22781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        ? mService.getString(R.string.exporting_vcard_finished_title_fallback)
22881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        : mService.getString(R.string.exporting_vcard_finished_title, filename);
22981c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                doFinishNotification(title, null);
23081c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            }
2317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } finally {
2327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (composer != null) {
2337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                composer.terminate();
2347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
2357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            if (writer != null) {
2367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                try {
2377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    writer.close();
2387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                } catch (IOException e) {
2397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                    Log.w(LOG_TAG, "IOException is thrown during close(). Ignored. " + e);
2407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                }
2417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            }
2427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            mService.handleFinishExportNotification(mJobId, successful);
2437903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        }
2447903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
2457903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
24681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    private boolean isLocalFile(Uri uri) {
24781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        final String authority = uri.getAuthority();
24881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        return mService.getString(R.string.contacts_file_provider_authority).equals(authority);
24981c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    }
25081c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang
2517903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private String translateComposerError(String errorMessage) {
2527903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final Resources resources = mService.getResources();
2537903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) {
2547903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            return resources.getString(R.string.composer_failed_to_get_database_infomation);
2557903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } else if (VCardComposer.FAILURE_REASON_NO_ENTRY.equals(errorMessage)) {
2567903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            return resources.getString(R.string.composer_has_no_exportable_contact);
2577903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } else if (VCardComposer.FAILURE_REASON_NOT_INITIALIZED.equals(errorMessage)) {
2587903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            return resources.getString(R.string.composer_not_initialized);
2597903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        } else {
2607903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            return errorMessage;
2617903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        }
2627903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
2637903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
2647903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private void doProgressNotification(Uri uri, int totalCount, int currentCount) {
2657903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final String displayName = uri.getLastPathSegment();
2667903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final String description =
2677903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mService.getString(R.string.exporting_contact_list_message, displayName);
2687903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final String tickerText =
2697903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mService.getString(R.string.exporting_contact_list_title);
2707903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final Notification notification =
2717903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                NotificationImportExportListener.constructProgressNotification(mService,
2727903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        VCardService.TYPE_EXPORT, description, tickerText, mJobId, displayName,
2737903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        totalCount, currentCount);
2747903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
2757903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mJobId, notification);
2767903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
2777903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
2787903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private void doCancelNotification() {
2797903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (DEBUG) Log.d(LOG_TAG, "send cancel notification");
2807903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final String description = mService.getString(R.string.exporting_vcard_canceled_title,
2817903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mExportRequest.destUri.getLastPathSegment());
2827903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final Notification notification =
2837903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                NotificationImportExportListener.constructCancelNotification(mService, description);
2847903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
2857903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mJobId, notification);
2867903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
2877903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
2887903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    private void doFinishNotification(final String title, final String description) {
2897903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
2907903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final Intent intent = new Intent();
2917903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        intent.setClassName(mService, mCallingActivity);
2927903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        final Notification notification =
2937903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                NotificationImportExportListener.constructFinishNotification(mService, title,
2947903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                        description, intent);
2957903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
2967903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng                mJobId, notification);
2977903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
2987903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
29981c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    /**
30081c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang     * Pass intent with ACTION_SEND to notification so that user can press the notification to
30181c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang     * share contacts.
30281c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang     */
30381c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    private void doFinishNotificationWithShareAction(final String title, final String
30481c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang            description, Uri uri) {
30581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
30681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        final Intent intent = new Intent(Intent.ACTION_SEND);
30781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        intent.setType(Contacts.CONTENT_VCARD_TYPE);
30881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        intent.putExtra(Intent.EXTRA_STREAM, uri);
3092149e72ed4d55b1d9271872960b74ace5f8a3e90Wenyi Wang        // Securely grant access using temporary access permissions
3102149e72ed4d55b1d9271872960b74ace5f8a3e90Wenyi Wang        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
3112149e72ed4d55b1d9271872960b74ace5f8a3e90Wenyi Wang        // Build notification
31281c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        final Notification notification =
31381c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                NotificationImportExportListener.constructFinishNotificationWithFlags(
31481c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                        mService, title, description, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
31581c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang        mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
31681c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang                mJobId, notification);
31781c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang    }
31881c9c1da36cb58d7c583642a5f9449f113c8aeddWenyi Wang
3197903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    @Override
3207903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public synchronized boolean cancel(boolean mayInterruptIfRunning) {
3217903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (DEBUG) Log.d(LOG_TAG, "received cancel request");
3227903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        if (mDone || mCanceled) {
3237903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng            return false;
3247903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        }
3257903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        mCanceled = true;
3267903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        return true;
3277903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
3287903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
3297903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    @Override
3307903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public synchronized boolean isCancelled() {
3317903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        return mCanceled;
3327903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
3337903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
3347903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    @Override
3357903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public synchronized boolean isDone() {
3367903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        return mDone;
3377903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
3387903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng
3397903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    public ExportRequest getRequest() {
3407903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng        return mExportRequest;
3417903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng    }
3427903d2473e1120e32fa5380a7d7532d0a21e2180Chiao Cheng}
343