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