blob: c36cc384ba01b37c28872c518420e02299708c65 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.contacts.vcard;
import com.android.contacts.R;
import com.android.vcard.VCardComposer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
/**
* Shows a dialog confirming the export and asks actual vCard export to {@link VCardService}
*
* This Activity first connects to VCardService and ask an available file name and shows it to
* a user. After the user's confirmation, it send export request with the file name, assuming the
* file name is not reserved yet.
*/
public class ExportVCardActivity extends Activity implements ServiceConnection,
DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
private static final String LOG_TAG = "VCardExport";
private static final boolean DEBUG = VCardService.DEBUG;
/**
* Handler used when some Message has come from {@link VCardService}.
*/
private class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (DEBUG) Log.d(LOG_TAG, "IncomingHandler received message.");
if (msg.arg1 != 0) {
Log.i(LOG_TAG, "Message returned from vCard server contains error code.");
if (msg.obj != null) {
mErrorReason = (String)msg.obj;
}
showDialog(msg.arg1);
return;
}
switch (msg.what) {
case VCardService.MSG_SET_AVAILABLE_EXPORT_DESTINATION:
if (msg.obj == null) {
Log.w(LOG_TAG, "Message returned from vCard server doesn't contain valid path");
mErrorReason = getString(R.string.fail_reason_unknown);
showDialog(R.id.dialog_fail_to_export_with_reason);
} else {
mTargetFileName = (String)msg.obj;
if (TextUtils.isEmpty(mTargetFileName)) {
Log.w(LOG_TAG, "Destination file name coming from vCard service is empty.");
mErrorReason = getString(R.string.fail_reason_unknown);
showDialog(R.id.dialog_fail_to_export_with_reason);
} else {
if (DEBUG) {
Log.d(LOG_TAG,
String.format("Target file name is set (%s). " +
"Show confirmation dialog", mTargetFileName));
}
showDialog(R.id.dialog_export_confirmation);
}
}
break;
default:
Log.w(LOG_TAG, "Unknown message type: " + msg.what);
super.handleMessage(msg);
}
}
}
/**
* True when this Activity is connected to {@link VCardService}.
*
* Should be touched inside synchronized block.
*/
private boolean mConnected;
/**
* True when users need to do something and this Activity should not disconnect from
* VCardService. False when all necessary procedures are done (including sending export request)
* or there's some error occured.
*/
private volatile boolean mProcessOngoing = true;
private VCardService mService;
private final Messenger mIncomingMessenger = new Messenger(new IncomingHandler());
// Used temporarily when asking users to confirm the file name
private String mTargetFileName;
// String for storing error reason temporarily.
private String mErrorReason;
private class ExportConfirmationListener implements DialogInterface.OnClickListener {
private final Uri mDestinationUri;
public ExportConfirmationListener(String path) {
this(Uri.parse("file://" + path));
}
public ExportConfirmationListener(Uri uri) {
mDestinationUri = uri;
}
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (DEBUG) {
Log.d(LOG_TAG,
String.format("Try sending export request (uri: %s)", mDestinationUri));
}
final ExportRequest request = new ExportRequest(mDestinationUri);
// The connection object will call finish().
mService.handleExportRequest(request, new NotificationImportExportListener(
ExportVCardActivity.this));
}
unbindAndFinish();
}
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Check directory is available.
final File targetDirectory = new File(getString(R.string.config_export_dir));
if (!(targetDirectory.exists() &&
targetDirectory.isDirectory() &&
targetDirectory.canRead()) &&
!targetDirectory.mkdirs()) {
showDialog(R.id.dialog_sdcard_not_found);
return;
}
Intent intent = new Intent(this, VCardService.class);
if (startService(intent) == null) {
Log.e(LOG_TAG, "Failed to start vCard service");
mErrorReason = getString(R.string.fail_reason_unknown);
showDialog(R.id.dialog_fail_to_export_with_reason);
return;
}
if (!bindService(intent, this, Context.BIND_AUTO_CREATE)) {
Log.e(LOG_TAG, "Failed to connect to vCard service.");
mErrorReason = getString(R.string.fail_reason_unknown);
showDialog(R.id.dialog_fail_to_export_with_reason);
}
// Continued to onServiceConnected()
}
@Override
public synchronized void onServiceConnected(ComponentName name, IBinder binder) {
if (DEBUG) Log.d(LOG_TAG, "connected to service, requesting a destination file name");
mConnected = true;
mService = ((VCardService.MyBinder) binder).getService();
mService.handleRequestAvailableExportDestination(mIncomingMessenger);
// Wait until MSG_SET_AVAILABLE_EXPORT_DESTINATION message is available.
}
// Use synchronized since we don't want to call unbindAndFinish() just after this call.
@Override
public synchronized void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.d(LOG_TAG, "onServiceDisconnected()");
mService = null;
mConnected = false;
if (mProcessOngoing) {
// Unexpected disconnect event.
Log.w(LOG_TAG, "Disconnected from service during the process ongoing.");
mErrorReason = getString(R.string.fail_reason_unknown);
showDialog(R.id.dialog_fail_to_export_with_reason);
}
}
@Override
protected Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case R.id.dialog_export_confirmation: {
return new AlertDialog.Builder(this)
.setTitle(R.string.confirm_export_title)
.setMessage(getString(R.string.confirm_export_message, mTargetFileName))
.setPositiveButton(android.R.string.ok,
new ExportConfirmationListener(mTargetFileName))
.setNegativeButton(android.R.string.cancel, this)
.setOnCancelListener(this)
.create();
}
case R.string.fail_reason_too_many_vcard: {
mProcessOngoing = false;
return new AlertDialog.Builder(this)
.setTitle(R.string.exporting_contact_failed_title)
.setMessage(getString(R.string.exporting_contact_failed_message,
getString(R.string.fail_reason_too_many_vcard)))
.setPositiveButton(android.R.string.ok, this)
.create();
}
case R.id.dialog_fail_to_export_with_reason: {
mProcessOngoing = false;
return new AlertDialog.Builder(this)
.setTitle(R.string.exporting_contact_failed_title)
.setMessage(getString(R.string.exporting_contact_failed_message,
mErrorReason != null ? mErrorReason :
getString(R.string.fail_reason_unknown)))
.setPositiveButton(android.R.string.ok, this)
.setOnCancelListener(this)
.create();
}
case R.id.dialog_sdcard_not_found: {
mProcessOngoing = false;
return new AlertDialog.Builder(this)
.setTitle(R.string.no_sdcard_title)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setMessage(R.string.no_sdcard_message)
.setPositiveButton(android.R.string.ok, this).create();
}
}
return super.onCreateDialog(id, bundle);
}
@Override
protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
if (id == R.id.dialog_fail_to_export_with_reason) {
((AlertDialog)dialog).setMessage(mErrorReason);
} else if (id == R.id.dialog_export_confirmation) {
((AlertDialog)dialog).setMessage(
getString(R.string.confirm_export_message, mTargetFileName));
} else {
super.onPrepareDialog(id, dialog, args);
}
}
@Override
protected void onStop() {
super.onStop();
if (!isFinishing()) {
unbindAndFinish();
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onClick() is called");
unbindAndFinish();
}
@Override
public void onCancel(DialogInterface dialog) {
if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onCancel() is called");
mProcessOngoing = false;
unbindAndFinish();
}
@Override
public void unbindService(ServiceConnection conn) {
mProcessOngoing = false;
super.unbindService(conn);
}
private synchronized void unbindAndFinish() {
if (mConnected) {
unbindService(this);
mConnected = false;
}
finish();
}
}