diff --git a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
index 36a0d336e..4fc08ee11 100644
--- a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
+++ b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
@@ -18,6 +18,7 @@ package com.android.emailcommon.service;
import android.content.Context;
import android.content.Intent;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -30,6 +31,7 @@ import com.android.emailcommon.provider.Policy;
import com.android.mail.utils.LogUtils;
import java.io.IOException;
+import java.util.concurrent.Executor;
/**
* The EmailServiceProxy class provides a simple interface for the UI to call into the various
@@ -258,6 +260,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
@Override
public void deleteExternalAccountPIMData(final String emailAddress) throws RemoteException {
setTask(new ProxyTask() {
+ @Override
+ public Executor runInExecutor() {
+ return AsyncTask.THREAD_POOL_EXECUTOR;
+ }
+
@Override
public void run() throws RemoteException {
mService.deleteExternalAccountPIMData(emailAddress);
diff --git a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
index 3669345c1..8adffc43e 100644
--- a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
+++ b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
@@ -31,6 +31,8 @@ import android.os.RemoteException;
import com.android.emailcommon.provider.EmailContent;
import com.android.mail.utils.LogUtils;
+import java.util.concurrent.Executor;
+
/**
* ServiceProxy is a superclass for proxy objects which make a single call to a service. It handles
* connecting to the service, running a task supplied by the subclass when the connection is ready,
@@ -133,8 +135,8 @@ public abstract class ServiceProxy {
"RuntimeException when trying to unbind from service");
}
}
- mTaskCompleted = true;
synchronized(mConnection) {
+ mTaskCompleted = true;
if (DEBUG_PROXY) {
LogUtils.v(mTag, "Task " + mName + " completed; disconnecting");
}
@@ -142,7 +144,7 @@ public abstract class ServiceProxy {
}
return null;
}
- }.execute();
+ }.executeOnExecutor(mTask.runInExecutor());
}
@Override
@@ -154,8 +156,11 @@ public abstract class ServiceProxy {
}
}
- protected interface ProxyTask {
- public void run() throws RemoteException;
+ protected abstract class ProxyTask {
+ public Executor runInExecutor() {
+ return AsyncTask.SERIAL_EXECUTOR;
+ };
+ public abstract void run() throws RemoteException;
}
public ServiceProxy setTimeout(int secs) {
@@ -178,6 +183,9 @@ public abstract class ServiceProxy {
if (DEBUG_PROXY) {
LogUtils.v(mTag, "Bind requested for task " + mName);
}
+ synchronized (mConnection) {
+ mTaskCompleted = false;
+ }
return mContext.bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE);
}
@@ -203,7 +211,9 @@ public abstract class ServiceProxy {
if (DEBUG_PROXY) {
LogUtils.v(mTag, "Waiting for task " + mName + " to complete...");
}
- mConnection.wait(mTimeout * 1000L);
+ if (!mTaskCompleted) {
+ mConnection.wait(mTimeout * 1000L);
+ }
} catch (InterruptedException e) {
// Can be ignored safely
}
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
new file mode 100644
index 000000000..0e3594f64
--- /dev/null
+++ b/res/values/cm_strings.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+ Delete account
+ This will delete all the settings and emails of the
+ account %s. This operation cannot be undone.\n\nContinue?
+ Deleting account\u2026
+ Couldn\'t delete the account
+
diff --git a/src/com/android/email/activity/setup/AccountSettingsFragment.java b/src/com/android/email/activity/setup/AccountSettingsFragment.java
index 30c3d9cb3..49bd8535d 100644
--- a/src/com/android/email/activity/setup/AccountSettingsFragment.java
+++ b/src/com/android/email/activity/setup/AccountSettingsFragment.java
@@ -16,11 +16,15 @@
package com.android.email.activity.setup;
+import android.accounts.AccountManager;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.LoaderManager;
+import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
@@ -28,7 +32,11 @@ import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.Message;
import android.os.Vibrator;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
@@ -43,8 +51,12 @@ import android.provider.ContactsContract;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.Window;
+import android.widget.Toast;
import com.android.email.R;
import com.android.email.SecurityPolicy;
@@ -63,6 +75,7 @@ import com.android.mail.providers.Folder;
import com.android.mail.providers.UIProvider;
import com.android.mail.ui.MailAsyncTaskLoader;
import com.android.mail.ui.settings.MailAccountPrefsFragment;
+import com.android.mail.ui.settings.PublicPreferenceActivity;
import com.android.mail.ui.settings.SettingsUtils;
import com.android.mail.utils.ContentProviderTask.UpdateTask;
import com.android.mail.utils.LogUtils;
@@ -118,6 +131,9 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
// Request code to start different activities.
private static final int RINGTONE_REQUEST_CODE = 0;
+ // Message codes
+ private static final int MSG_DELETE_ACCOUNT = 0;
+
private EditTextPreference mAccountDescription;
private EditTextPreference mAccountName;
private EditTextPreference mAccountSignature;
@@ -128,6 +144,7 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
private Preference mInboxRingtone;
private Context mContext;
+ private Handler mHandler;
private Account mAccount;
private com.android.mail.providers.Account mUiAccount;
@@ -136,6 +153,18 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
private Ringtone mRingtone;
+ private MenuItem mDeleteAccountItem;
+
+ private final Callback mHandlerCallback = new Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (msg.what == MSG_DELETE_ACCOUNT) {
+ deleteAccount();
+ }
+ return false;
+ }
+ };
+
/**
* This may be null if the account exists but the inbox has not yet been created in the database
* (waiting for initial sync)
@@ -176,6 +205,7 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mHandler = new Handler(mHandlerCallback);
setHasOptionsMenu(true);
@@ -412,9 +442,39 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
+
+ // Delete account item
+ mDeleteAccountItem = menu.add(Menu.NONE, Menu.NONE, 0, R.string.delete_account);
+ mDeleteAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+
inflater.inflate(R.menu.settings_fragment_menu, menu);
}
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.equals(mDeleteAccountItem)) {
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(mContext);
+ alertBuilder.setTitle(R.string.delete_account);
+ String msg = getString(R.string.delete_account_confirmation_msg, mAccountEmail);
+ alertBuilder.setMessage(msg);
+ alertBuilder.setCancelable(true);
+ final DialogInterface.OnClickListener cb = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ mHandler.dispatchMessage(Message.obtain(mHandler, MSG_DELETE_ACCOUNT));
+ }
+ };
+ alertBuilder.setPositiveButton(android.R.string.ok, cb);
+ alertBuilder.setNegativeButton(android.R.string.cancel, null);
+ alertBuilder.create().show();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+
+
/**
* Async task loader to load account in order to view/edit it
*/
@@ -987,4 +1047,63 @@ public class AccountSettingsFragment extends MailAccountPrefsFragment
AccountServerSettingsActivity.getIntentForOutgoing(getActivity(), account);
getActivity().startActivity(intent);
}
+
+ private void deleteAccount() {
+ AsyncTask task = new AsyncTask() {
+ private ProgressDialog mDialog;
+
+ @Override
+ protected void onPreExecute() {
+ // Display an alert dialog to advise the user that the operation is in progress
+ mDialog = new ProgressDialog(mContext);
+ mDialog.setMessage(mContext.getString(R.string.deleting_account_msg));
+ mDialog.setCancelable(false);
+ mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ mDialog.show();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (!result) {
+ Toast.makeText(mContext, R.string.delete_account_failed,
+ Toast.LENGTH_SHORT).show();
+ }
+ mDialog.dismiss();
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ // Retrieve the necessary information
+ AccountManager accountManager = (AccountManager)mContext.getSystemService(
+ Context.ACCOUNT_SERVICE);
+ android.accounts.Account account = mUiAccount.getAccountManagerAccount();
+
+ // Remove the email account and its notifications
+ ContentResolver resolver = mContext.getContentResolver();
+ int ret = resolver.delete(mUiAccount.uri, null, null);
+ if (ret <= 0) {
+ LogUtils.w(LogUtils.TAG, "Failed to delete account %s", mAccountEmail);
+ return Boolean.FALSE;
+ }
+ NotificationUtils.clearAccountNotifications(mContext, account);
+
+ // And now we remove the system account that holds the email service
+ accountManager.removeAccount(account, getActivity(), null, null);
+
+ // We deleted the account, so we need to clear the activity stack, so just show
+ // the settings fragment and clear the activity stack
+ Intent intent = new Intent(getActivity(), PublicPreferenceActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ getActivity().startActivity(intent);
+ } catch (Exception ex) {
+ LogUtils.w(LogUtils.TAG, ex, "Failed to delete account %s", mAccountEmail);
+ return Boolean.FALSE;
+ }
+ return Boolean.TRUE;
+ }
+ };
+ task.execute();
+ }
}