blob: bd29fc8f40810f45eb5c1d5b66cf10651e9664ea [file] [log] [blame]
Chiao Cheng7903d242012-12-03 17:15:58 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.contacts.common.vcard;
17
Brian Attwell9dff7722014-10-27 12:29:44 -070018import android.app.Activity;
Chiao Cheng7903d242012-12-03 17:15:58 -080019import android.app.AlertDialog;
20import android.app.Dialog;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.ServiceConnection;
Walter Jang6aa0ab92015-07-09 10:19:35 -070026import android.database.Cursor;
Chiao Cheng7903d242012-12-03 17:15:58 -080027import android.net.Uri;
28import android.os.Bundle;
Chiao Cheng7903d242012-12-03 17:15:58 -080029import android.os.IBinder;
Walter Jang6aa0ab92015-07-09 10:19:35 -070030import android.provider.OpenableColumns;
Brian Attwelled95f6c2014-10-17 14:32:35 -070031import android.text.BidiFormatter;
32import android.text.TextDirectionHeuristics;
Chiao Cheng7903d242012-12-03 17:15:58 -080033import android.util.Log;
34
35import com.android.contacts.common.R;
Brian Attwellc1b73282015-06-23 23:26:27 -070036import com.android.contacts.common.activity.RequestImportVCardPermissionsActivity;
Chiao Cheng7903d242012-12-03 17:15:58 -080037
Chiao Cheng7903d242012-12-03 17:15:58 -080038/**
39 * Shows a dialog confirming the export and asks actual vCard export to {@link VCardService}
40 *
41 * This Activity first connects to VCardService and ask an available file name and shows it to
42 * a user. After the user's confirmation, it send export request with the file name, assuming the
43 * file name is not reserved yet.
44 */
Brian Attwell9dff7722014-10-27 12:29:44 -070045public class ExportVCardActivity extends Activity implements ServiceConnection,
Chiao Cheng7903d242012-12-03 17:15:58 -080046 DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
47 private static final String LOG_TAG = "VCardExport";
48 private static final boolean DEBUG = VCardService.DEBUG;
Walter Jang42765f62015-07-01 11:26:07 -070049 private static final int REQUEST_CREATE_DOCUMENT = 100;
Chiao Cheng7903d242012-12-03 17:15:58 -080050
51 /**
52 * True when this Activity is connected to {@link VCardService}.
53 *
54 * Should be touched inside synchronized block.
55 */
56 private boolean mConnected;
57
58 /**
59 * True when users need to do something and this Activity should not disconnect from
60 * VCardService. False when all necessary procedures are done (including sending export request)
61 * or there's some error occured.
62 */
63 private volatile boolean mProcessOngoing = true;
64
65 private VCardService mService;
Brian Attwelled95f6c2014-10-17 14:32:35 -070066 private static final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
Chiao Cheng7903d242012-12-03 17:15:58 -080067
Chiao Cheng7903d242012-12-03 17:15:58 -080068 // String for storing error reason temporarily.
69 private String mErrorReason;
70
Chiao Cheng7903d242012-12-03 17:15:58 -080071 @Override
72 protected void onCreate(Bundle bundle) {
73 super.onCreate(bundle);
74
Walter Jang6b87ef12016-11-04 14:03:39 -070075 if (RequestImportVCardPermissionsActivity.startPermissionActivity(this,
76 /* isCallerSelf */ false)) {
Brian Attwellc1b73282015-06-23 23:26:27 -070077 return;
78 }
79
Walter Jang42765f62015-07-01 11:26:07 -070080 connectVCardService();
81 }
Chiao Cheng7903d242012-12-03 17:15:58 -080082
Walter Jang42765f62015-07-01 11:26:07 -070083 private void connectVCardService() {
Chiao Cheng7903d242012-12-03 17:15:58 -080084 final String callingActivity = getIntent().getExtras()
85 .getString(VCardCommonArguments.ARG_CALLING_ACTIVITY);
86 Intent intent = new Intent(this, VCardService.class);
87 intent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity);
88
89 if (startService(intent) == null) {
90 Log.e(LOG_TAG, "Failed to start vCard service");
91 mErrorReason = getString(R.string.fail_reason_unknown);
92 showDialog(R.id.dialog_fail_to_export_with_reason);
93 return;
94 }
95
96 if (!bindService(intent, this, Context.BIND_AUTO_CREATE)) {
97 Log.e(LOG_TAG, "Failed to connect to vCard service.");
98 mErrorReason = getString(R.string.fail_reason_unknown);
99 showDialog(R.id.dialog_fail_to_export_with_reason);
100 }
101 // Continued to onServiceConnected()
102 }
103
104 @Override
Walter Jang42765f62015-07-01 11:26:07 -0700105 public void onActivityResult(int requestCode, int resultCode, Intent data) {
106 if (requestCode == REQUEST_CREATE_DOCUMENT) {
107 if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
108 final Uri mTargetFileName = data.getData();
109 if (DEBUG) Log.d(LOG_TAG, "exporting to " + mTargetFileName);
110 final ExportRequest request = new ExportRequest(mTargetFileName);
111 // The connection object will call finish().
112 mService.handleExportRequest(request, new NotificationImportExportListener(
113 ExportVCardActivity.this));
114 } else if (DEBUG) {
115 Log.d(LOG_TAG, "create document cancelled or no data returned");
116 }
117 unbindAndFinish();
118 }
119 }
120
121 @Override
Chiao Cheng7903d242012-12-03 17:15:58 -0800122 public synchronized void onServiceConnected(ComponentName name, IBinder binder) {
123 if (DEBUG) Log.d(LOG_TAG, "connected to service, requesting a destination file name");
124 mConnected = true;
125 mService = ((VCardService.MyBinder) binder).getService();
Walter Jang42765f62015-07-01 11:26:07 -0700126
127 // Have the user choose where vcards will be exported to
128 final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
129 intent.addCategory(Intent.CATEGORY_OPENABLE);
Walter Jang95cddf52015-08-11 09:18:35 -0700130 intent.setType(VCardService.X_VCARD_MIME_TYPE);
Walter Jang42765f62015-07-01 11:26:07 -0700131 intent.putExtra(Intent.EXTRA_TITLE, mBidiFormatter.unicodeWrap(
132 getString(R.string.exporting_vcard_filename), TextDirectionHeuristics.LTR));
133 startActivityForResult(intent, REQUEST_CREATE_DOCUMENT);
Chiao Cheng7903d242012-12-03 17:15:58 -0800134 }
135
136 // Use synchronized since we don't want to call unbindAndFinish() just after this call.
137 @Override
138 public synchronized void onServiceDisconnected(ComponentName name) {
139 if (DEBUG) Log.d(LOG_TAG, "onServiceDisconnected()");
140 mService = null;
141 mConnected = false;
142 if (mProcessOngoing) {
143 // Unexpected disconnect event.
144 Log.w(LOG_TAG, "Disconnected from service during the process ongoing.");
145 mErrorReason = getString(R.string.fail_reason_unknown);
146 showDialog(R.id.dialog_fail_to_export_with_reason);
147 }
148 }
149
150 @Override
151 protected Dialog onCreateDialog(int id, Bundle bundle) {
152 switch (id) {
Chiao Cheng7903d242012-12-03 17:15:58 -0800153 case R.string.fail_reason_too_many_vcard: {
154 mProcessOngoing = false;
155 return new AlertDialog.Builder(this)
156 .setTitle(R.string.exporting_contact_failed_title)
157 .setMessage(getString(R.string.exporting_contact_failed_message,
158 getString(R.string.fail_reason_too_many_vcard)))
159 .setPositiveButton(android.R.string.ok, this)
160 .create();
161 }
162 case R.id.dialog_fail_to_export_with_reason: {
163 mProcessOngoing = false;
164 return new AlertDialog.Builder(this)
165 .setTitle(R.string.exporting_contact_failed_title)
166 .setMessage(getString(R.string.exporting_contact_failed_message,
167 mErrorReason != null ? mErrorReason :
168 getString(R.string.fail_reason_unknown)))
169 .setPositiveButton(android.R.string.ok, this)
170 .setOnCancelListener(this)
171 .create();
172 }
Chiao Cheng7903d242012-12-03 17:15:58 -0800173 }
174 return super.onCreateDialog(id, bundle);
175 }
176
177 @Override
178 protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
179 if (id == R.id.dialog_fail_to_export_with_reason) {
180 ((AlertDialog)dialog).setMessage(mErrorReason);
Chiao Cheng7903d242012-12-03 17:15:58 -0800181 } else {
182 super.onPrepareDialog(id, dialog, args);
183 }
184 }
185
186 @Override
Chiao Cheng7903d242012-12-03 17:15:58 -0800187 public void onClick(DialogInterface dialog, int which) {
188 if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onClick() is called");
189 unbindAndFinish();
190 }
191
192 @Override
193 public void onCancel(DialogInterface dialog) {
194 if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onCancel() is called");
195 mProcessOngoing = false;
196 unbindAndFinish();
197 }
198
199 @Override
200 public void unbindService(ServiceConnection conn) {
201 mProcessOngoing = false;
202 super.unbindService(conn);
203 }
204
Walter Jang6aa0ab92015-07-09 10:19:35 -0700205 /**
206 * Returns the display name for the given openable Uri or null if it could not be resolved. */
207 static String getOpenableUriDisplayName(Context context, Uri uri) {
208 if (uri == null) return null;
209 final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
210 try {
211 if (cursor != null && cursor.moveToFirst()) {
212 return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
213 }
214 } finally {
215 if (cursor != null) {
216 cursor.close();
217 }
218 }
219 return null;
220 }
221
Chiao Cheng7903d242012-12-03 17:15:58 -0800222 private synchronized void unbindAndFinish() {
223 if (mConnected) {
224 unbindService(this);
225 mConnected = false;
226 }
227 finish();
228 }
229}