Improve trash folder picker upon account creation

* Use setup intent uri
* TODO: More cleanup

Bug: 7077441

Change-Id: Ieab5b0ed33b73b7a0e9012aedd6becf867db1566
This commit is contained in:
Marc Blank 2012-09-06 10:19:34 -07:00
parent a2c286493d
commit 2616405471
9 changed files with 185 additions and 50 deletions

View File

@ -213,12 +213,6 @@
</intent-filter>
</activity-alias>
<activity
android:name=".provider.FolderPickerActivity"
android:label="@string/folder_picker_title"
>
</activity>
<!-- Must be exported in order for the AccountManager to launch it -->
<!-- Also available for continuous test systems to force account creation -->
<activity
@ -283,6 +277,21 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".provider.FolderPickerActivity"
android:label="@string/folder_picker_title"
android:theme="@android:style/Theme.Holo.Light"
>
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="content"
android:host="ui.email.android.com"
android:pathPrefix="/setup"
/>
</intent-filter>
</activity>
<activity
android:name=".activity.setup.AccountSecurity"
android.label="@string/account_security_title"

View File

@ -90,6 +90,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
// Whether or not server-side search supports global search (i.e. all mailboxes); only valid
// if FLAGS_SUPPORTS_SEARCH is true
public static final int FLAGS_SUPPORTS_GLOBAL_SEARCH = 1<<12;
// Whether or not the initial folder list has been loaded
public static final int FLAGS_INITIAL_FOLDER_LIST_LOADED = 1<<13;
// Deletion policy (see FLAGS_DELETE_POLICY_MASK, above)
public static final int DELETE_POLICY_NEVER = 0;
@ -113,6 +115,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce
NOTIFIER_URI = Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/account");
DEFAULT_ACCOUNT_ID_URI = Uri.parse(EmailContent.CONTENT_URI + "/account/default");
}
public String mDisplayName;
public String mEmailAddress;
public String mSyncKey;

View File

@ -1317,12 +1317,11 @@ as <xliff:g id="filename">%s</xliff:g>.</string>
<string name="imap2_name">IMAP</string>
<string name="pop3_name">POP3</string>
<string name="folder_picker_title">Picky, picky, picky!</string>
<string name="folder_picker_title">Folder picker</string>
<!-- Displayed when the user must pick his server's trash folder from a list [CHAR LIMIT 30]-->
<string name="trash_folder_selection_title">Select server trash folder</string>
<string name="trash_folder_selection_title">Select server trash folder for <xliff:g id="account">%s</xliff:g></string>
<!-- Displayed when the user must pick his server's sent items folder from a list [CHAR LIMIT 30]-->
<string name="sent_folder_selection_title">Select server sent items folder</string>
<string name="sent_folder_selection_title">Select server sent items folder for <xliff:g id="account">%s</xliff:g></string>
<string name="create_new_folder">Create folder</string>
</resources>
<string name="account_waiting_for_folders_msg">Loading folder list&#8230;</string>
</resources>

View File

@ -274,17 +274,6 @@ public class Imap2SyncManager extends SyncManager {
inbox.save(getContext());
log("Creating inbox for account: " + acct.mDisplayName);
Imap2SyncManager.kick("New account");
// Need to sync folder list first; sigh
Imap2SyncService svc = new Imap2SyncService(Imap2SyncManager.this, acct);
try {
svc.loadFolderList();
mResolver.update(
ContentUris.withAppendedId(EmailContent.PICK_TRASH_FOLDER_URI, acctId),
new ContentValues(), null, null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}

View File

@ -1379,6 +1379,17 @@ public class Imap2SyncService extends AbstractSyncService {
}
applyBatch(ops);
// Set folder list loaded flag, if it hasn't already been
if ((mAccount.mFlags & Account.FLAGS_INITIAL_FOLDER_LIST_LOADED) == 0) {
userLog("Notify initial folder list loaded...");
mAccount.mFlags |= Account.FLAGS_INITIAL_FOLDER_LIST_LOADED;
ContentValues values = new ContentValues();
values.put(AccountColumns.FLAGS, mAccount.mFlags);
mResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId),
values, null, null);
}
// Fixup parent stuff, flags...
MailboxUtilities.fixupUninitializedParentKeys(mContext,
Mailbox.ACCOUNT_KEY + "=" + mAccountId);
@ -2173,7 +2184,8 @@ public class Imap2SyncService extends AbstractSyncService {
idle();
}
} catch (Exception e) {
userLog("Exception in imap2 sync", e);
} finally {
// Don't kill the connection until mBodyThread is done...
if (mBodyThread != null) {
@ -2253,6 +2265,7 @@ public class Imap2SyncService extends AbstractSyncService {
public void run() {
try {
TAG = Thread.currentThread().getName();
userLog("Starting imap sync thread...");
// Check for Outbox (special "sync") and stopped
if (mMailbox.mType == Mailbox.TYPE_OUTBOX) {

View File

@ -2820,6 +2820,15 @@ outer:
// Email doesn't support priority inbox, so always state priority arrows disabled.
values.put(UIProvider.AccountColumns.SettingsColumns.PRIORITY_ARROWS_ENABLED, "0");
}
if (projectionColumns.contains(
UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI)) {
// Use this if needed
long trashId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_TRASH);
if (trashId == Mailbox.NO_MAILBOX) {
values.put(UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI,
getExternalUriString("setup", id));
}
}
final StringBuilder sb = genSelect(getAccountListMap(), uiProjection, values);
sb.append(" FROM " + Account.TABLE_NAME + " WHERE " + AccountColumns.ID + "=?");

View File

@ -18,32 +18,147 @@
package com.android.email.provider;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.android.email.R;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
import com.android.mail.providers.Folder;
public class FolderPickerActivity extends Activity implements FolderPickerCallback {
private static final String TAG = "FolderPickerActivity";
private long mAccountId;
private int mMailboxType;
private AccountObserver mAccountObserver;
private String mAccountName;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent i = getIntent();
com.android.mail.providers.Account account =
i.getParcelableExtra(EmailProvider.PICKER_UI_ACCOUNT);
mAccountId = Long.parseLong(account.uri.getLastPathSegment());
mMailboxType = i.getIntExtra(EmailProvider.PICKER_MAILBOX_TYPE, -1);
int headerId = i.getIntExtra(EmailProvider.PICKER_HEADER_ID, 0);
if (headerId == 0) {
finish();
return;
Uri uri = i.getData();
int headerId;
com.android.mail.providers.Account uiAccount = null;
// If we've gotten a Uri, then this is a call from the UI in response to setupIntentUri
// in an account (meaning the account requires setup)
if (uri != null) {
String id = uri.getQueryParameter("account");
if (id == null) {
Log.w(TAG, "No account # in Uri?");
finish();
return;
}
try {
mAccountId = Long.parseLong(id);
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid account # in Uri?");
finish();
return;
}
mMailboxType = Mailbox.TYPE_TRASH;
Account account = Account.restoreAccountWithId(this, mAccountId);
if (account == null) {
Log.w(TAG, "No account?");
finish();
} else {
mAccountName = account.mDisplayName;
// Two possibilities here; either we have our folder list, or we don't
if ((account.mFlags & Account.FLAGS_INITIAL_FOLDER_LIST_LOADED) != 0) {
// If we've got them, just start up the picker dialog
startPickerForAccount();
} else {
// Otherwise, wait for the folders to show up
waitForFolders();
}
}
} else {
// In this case, we're coming from Settings
uiAccount = i.getParcelableExtra(EmailProvider.PICKER_UI_ACCOUNT);
mAccountName = uiAccount.name;
mAccountId = Long.parseLong(uiAccount.uri.getLastPathSegment());
mMailboxType = i.getIntExtra(EmailProvider.PICKER_MAILBOX_TYPE, -1);
headerId = i.getIntExtra(EmailProvider.PICKER_HEADER_ID, 0);
if (headerId == 0) {
finish();
return;
}
startPicker(uiAccount.folderListUri, headerId);
}
new FolderSelectionDialog(this, account, this, headerId).show();
}
public void onDestroy() {
super.onDestroy();
// Clean up
if (mAccountObserver != null) {
getContentResolver().unregisterContentObserver(mAccountObserver);
mAccountObserver = null;
}
if (mWaitingForFoldersDialog != null) {
mWaitingForFoldersDialog.dismiss();
mWaitingForFoldersDialog = null;
}
}
private class AccountObserver extends ContentObserver {
private final Context mContext;
public AccountObserver(Context context, Handler handler) {
super(handler);
mContext = context;
}
public void onChange(boolean selfChange) {
Account account = Account.restoreAccountWithId(mContext, mAccountId);
// All we care about is whether the folder list is now loaded
if ((account.mFlags & Account.FLAGS_INITIAL_FOLDER_LIST_LOADED) != 0) {
mContext.getContentResolver().unregisterContentObserver(this);
mAccountObserver = null;
// Bring down the ProgressDialog and show the picker
if (mWaitingForFoldersDialog != null) {
mWaitingForFoldersDialog.dismiss();
mWaitingForFoldersDialog = null;
}
startPickerForAccount();
}
}
}
private ProgressDialog mWaitingForFoldersDialog;
private void waitForFolders() {
/// Show "Waiting for folders..." dialog
mWaitingForFoldersDialog = new ProgressDialog(this);
mWaitingForFoldersDialog.setIndeterminate(true);
mWaitingForFoldersDialog.setMessage(getString(R.string.account_waiting_for_folders_msg));
mWaitingForFoldersDialog.show();
// Listen for account changes
mAccountObserver = new AccountObserver(this, new Handler());
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId);
getContentResolver().registerContentObserver(uri, false, mAccountObserver);
}
private void startPickerForAccount() {
int headerId = R.string.trash_folder_selection_title;
Uri uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/uiallfolders/" + mAccountId);
startPicker(uri, headerId);
}
private void startPicker(Uri uri, int headerId) {
String header = getString(headerId, mAccountName);
FolderSelectionDialog dialog = new FolderSelectionDialog(this, uri, this, header);
dialog.show();
}
@Override
@ -68,13 +183,14 @@ public class FolderPickerActivity extends Activity implements FolderPickerCallba
getContentResolver().update(
ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailbox.mId), values,
null, null);
values.clear();
// Touch the account so that UI won't bring up this picker again
Account account = Account.restoreAccountWithId(this, mAccountId);
values.put(AccountColumns.FLAGS, account.mFlags);
getContentResolver().update(
ContentUris.withAppendedId(Account.CONTENT_URI, account.mId), values,
null, null);
}
finish();
}
@Override
public void create() {
// TODO: Not sure about this...
finish();
}
}

View File

@ -21,5 +21,4 @@ import com.android.mail.providers.Folder;
public interface FolderPickerCallback {
public void select(Folder folder);
public void create();
}

View File

@ -20,15 +20,16 @@ package com.android.email.provider;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.database.Cursor;
import android.net.Uri;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import com.android.mail.R;
import com.android.mail.providers.Account;
import com.android.mail.providers.Folder;
import com.android.mail.providers.UIProvider;
import com.android.mail.ui.FolderSelectorAdapter;
@ -46,18 +47,18 @@ public class FolderSelectionDialog implements OnClickListener, OnMultiChoiceClic
private final SeparatedFolderListAdapter mAdapter;
private final FolderPickerCallback mCallback;
public FolderSelectionDialog(final Context context, Account account,
FolderPickerCallback callback, int headerId) {
public FolderSelectionDialog(final Context context, Uri uri,
FolderPickerCallback callback, String header) {
mCallback = callback;
// Mapping of a folder's uri to its checked state
mCheckedState = new HashMap<Folder, Boolean>();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(headerId);
builder.setTitle(header);
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.create_new_folder, this);
builder.setCancelable(false);
// TODO: Do this on a background thread
final Cursor foldersCursor = context.getContentResolver().query(
account.fullFolderListUri != null ? account.fullFolderListUri
: account.folderListUri, UIProvider.FOLDERS_PROJECTION, null, null, null);
uri, UIProvider.FOLDERS_PROJECTION, null, null, null);
try {
mAdapter = new SeparatedFolderListAdapter(context);
String[] headers = context.getResources()
@ -135,9 +136,6 @@ public class FolderSelectionDialog implements OnClickListener, OnMultiChoiceClic
}
mCallback.select(folder);
break;
case DialogInterface.BUTTON_NEGATIVE:
mCallback.create();
break;
default:
onClick(dialog, which, true);
break;