replicant-packages_apps_Email/src/com/android/email/activity/MoveMessageToDialog.java

300 lines
11 KiB
Java

/*
* Copyright (C) 2010 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.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.utility.Utility;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
/**
* "Move (messages) to" dialog.
*
* TODO The check logic in MessageCheckerCallback is not efficient. It shouldn't restore full
* Message objects. But we don't bother at this point as the UI is still temporary.
*/
public class MoveMessageToDialog extends DialogFragment implements DialogInterface.OnClickListener {
private static final String BUNDLE_MESSAGE_IDS = "message_ids";
private static final int LOADER_ID_MOVE_TO_DIALOG_MAILBOX_LOADER = 1;
private static final int LOADER_ID_MOVE_TO_DIALOG_MESSAGE_CHECKER = 2;
/** Message IDs passed to {@link #newInstance} */
private long[] mMessageIds;
private MailboxMoveToAdapter mAdapter;
/** ID of the account that contains all of the messages to move */
private long mAccountId;
/** ID of the mailbox that contains all of the messages to move */
private long mMailboxId;
private boolean mDestroyed;
/**
* Callback that target fragments, or the owner activity should implement.
*/
public interface Callback {
public void onMoveToMailboxSelected(long newMailboxId, long[] messageIds);
}
/**
* Create and return a new instance.
*
* @param messageIds IDs of the messages to be moved.
* @param callbackFragment Fragment that gets a callback. The fragment must implement
* {@link Callback}.
*/
public static <T extends Fragment & Callback> MoveMessageToDialog newInstance(long[] messageIds,
T callbackFragment) {
if (messageIds.length == 0) {
throw new IllegalArgumentException();
}
if (callbackFragment == null) {
throw new IllegalArgumentException(); // fail fast
}
MoveMessageToDialog dialog = new MoveMessageToDialog();
Bundle args = new Bundle();
args.putLongArray(BUNDLE_MESSAGE_IDS, messageIds);
dialog.setArguments(args);
dialog.setTargetFragment(callbackFragment, 0);
return dialog;
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "" + this + " onCreate target=" + getTargetFragment());
}
super.onCreate(savedInstanceState);
mMessageIds = getArguments().getLongArray(BUNDLE_MESSAGE_IDS);
setStyle(STYLE_NORMAL, android.R.style.Theme_Holo_Light);
}
@Override
public void onDestroy() {
mDestroyed = true;
super.onDestroy();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
// Build adapter & dialog
// Make sure to pass Builder's context to the adapter, so that it'll get the correct theme.
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setTitle(activity.getResources().getString(R.string.move_to_folder_dialog_title));
mAdapter = new MailboxMoveToAdapter(builder.getContext());
builder.setSingleChoiceItems(mAdapter, -1, this);
getLoaderManager().initLoader(
LOADER_ID_MOVE_TO_DIALOG_MESSAGE_CHECKER,
null, new MessageCheckerCallback());
return builder.show();
}
@Override
public void onClick(DialogInterface dialog, int position) {
final long mailboxId = mAdapter.getItemId(position);
((Callback) getTargetFragment()).onMoveToMailboxSelected(mailboxId, mMessageIds);
dismiss();
}
/**
* Delay-call {@link #dismissAllowingStateLoss()} using a {@link Handler}. Calling
* {@link #dismissAllowingStateLoss()} from {@link LoaderManager.LoaderCallbacks#onLoadFinished}
* is not allowed, so we use it instead.
*/
private void dismissAsync() {
new Handler().post(new Runnable() {
@Override
public void run() {
if (!mDestroyed) {
dismissAllowingStateLoss();
}
}
});
}
/**
* Loader callback for {@link MessageChecker}
*/
private class MessageCheckerCallback implements LoaderManager.LoaderCallbacks<IdContainer> {
@Override
public Loader<IdContainer> onCreateLoader(int id, Bundle args) {
return new MessageChecker(getActivity(), mMessageIds);
}
@Override
public void onLoadFinished(Loader<IdContainer> loader, IdContainer idSet) {
if (mDestroyed) {
return;
}
// accountId shouldn't be null, but I'm paranoia.
if (idSet == null || idSet.mAccountId == Account.NO_ACCOUNT
|| idSet.mMailboxId == Mailbox.NO_MAILBOX) {
// Some of the messages can't be moved. Close the dialog.
dismissAsync();
return;
}
mAccountId = idSet.mAccountId;
mMailboxId = idSet.mMailboxId;
getLoaderManager().initLoader(
LOADER_ID_MOVE_TO_DIALOG_MAILBOX_LOADER,
null, new MailboxesLoaderCallbacks());
}
@Override
public void onLoaderReset(Loader<IdContainer> loader) {
}
}
/**
* Loader callback for destination mailbox list.
*/
private class MailboxesLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return MailboxMoveToAdapter.createLoader(getActivity().getApplicationContext(),
mAccountId, mMailboxId);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (mDestroyed) {
return;
}
mAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
/**
* A loader that checks if the messages can be moved. If messages can be moved, it returns
* the account and mailbox IDs where the messages are currently located. If any the messages
* cannot be moved (such as the messages belong to different accounts), the IDs returned
* will be {@link Account#NO_ACCOUNT} and {@link Mailbox#NO_MAILBOX}.
*/
private static class MessageChecker extends AsyncTaskLoader<IdContainer> {
private final Activity mActivity;
private final long[] mMessageIds;
public MessageChecker(Activity activity, long[] messageIds) {
super(activity);
mActivity = activity;
mMessageIds = messageIds;
}
@Override
public IdContainer loadInBackground() {
final Context c = getContext();
long accountId = Account.NO_ACCOUNT;
long mailboxId = Mailbox.NO_MAILBOX;
for (long messageId : mMessageIds) {
// TODO This shouln't restore a full Message object.
final Message message = Message.restoreMessageWithId(c, messageId);
if (message == null) {
continue; // Skip removed messages.
}
// First, check account.
if (accountId == Account.NO_ACCOUNT) {
// First, check if the account supports move
accountId = message.mAccountKey;
if (!Account.supportsMoveMessages(c, accountId)) {
Utility.showToast(
mActivity, R.string.cannot_move_protocol_not_supported_toast);
accountId = Account.NO_ACCOUNT;
break;
}
mailboxId = message.mMailboxKey;
// Second, check if the mailbox supports move
if (!Mailbox.canMoveFrom(c, mailboxId)) {
Utility.showToast(mActivity, R.string.cannot_move_special_mailboxes_toast);
accountId = Account.NO_ACCOUNT;
mailboxId = Mailbox.NO_MAILBOX;
break;
}
} else {
// Subsequent messages; all messages must to belong to the same mailbox
if (message.mAccountKey != accountId || message.mMailboxKey != mailboxId) {
Utility.showToast(mActivity, R.string.cannot_move_multiple_accounts_toast);
accountId = Account.NO_ACCOUNT;
mailboxId = Mailbox.NO_MAILBOX;
break;
}
}
}
return new IdContainer(accountId, mailboxId);
}
@Override
protected void onStartLoading() {
cancelLoad();
forceLoad();
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onReset() {
stopLoading();
}
}
/** Container for multiple types of IDs */
private static class IdContainer {
private final long mAccountId;
private final long mMailboxId;
private IdContainer(long accountId, long mailboxId) {
mAccountId = accountId;
mMailboxId = mailboxId;
}
}
}