Legacy account migration
* Create new activity to encapsulate account upgrade * Populate it with a list of legacy accounts, and progress bars for each * Sidestep Welcome when there are legacy accounts to convert * Super lightweight account migration: - Account login info only - no folders, messages, or attachments * Scrub out old data * Return to Welcome screen As noted, the copies working (useable) POP & IMAP accounts, but does not try to deal with folders, messages, or attachments. Bug: 2065528
This commit is contained in:
parent
a5b8b084ff
commit
842ac04828
|
@ -55,14 +55,20 @@
|
|||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:name="Email">
|
||||
<activity android:name=".activity.Welcome">
|
||||
<activity
|
||||
android:name=".activity.Welcome">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activity.UpgradeAccounts"
|
||||
android:label="@string/upgrade_accounts_title"
|
||||
android:theme="@android:style/Theme.NoTitleBar"
|
||||
android:configChanges="keyboardHidden|orientation" >
|
||||
</activity>
|
||||
<!-- Must be exported in order for the AccountManager to launch it -->
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupBasics"
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@*android:drawable/title_bar_medium">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/upgrade_accounts_title"
|
||||
android:gravity="center"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:shadowColor="?android:attr/colorBackground"
|
||||
android:shadowRadius="2" />
|
||||
</LinearLayout>
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="10dip"
|
||||
android:paddingBottom="10dip">
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:drawSelectorOnTop="false"
|
||||
android:fastScrollEnabled="true" />
|
||||
</FrameLayout>
|
||||
<LinearLayout style="@android:style/ButtonBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<View
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
<Button android:id="@+id/action_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/okay_action" />
|
||||
<View
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="vertical"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingLeft="6dip"
|
||||
android:gravity="fill" >
|
||||
|
||||
<TextView android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:layout_marginBottom="2dip" />
|
||||
|
||||
<ProgressBar android:id="@+id/progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="100" />
|
||||
|
||||
<TextView android:id="@+id/error"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:layout_marginBottom="2dip" />
|
||||
|
||||
</LinearLayout>
|
|
@ -573,6 +573,10 @@
|
|||
<!-- Message of Remove account confirmation dialog box -->
|
||||
<string name="account_delete_dlg_instructions_fmt">The account \"<xliff:g id="account">%s</xliff:g>\" will be removed from Email.</string>
|
||||
|
||||
<!-- Title of Upgrade Accounts activity -->
|
||||
<string name="upgrade_accounts_title">Upgrade accounts</string>
|
||||
<string name="upgrade_accounts_error">Unable to upgrade account</string>
|
||||
|
||||
<!-- Message that appears when user adds a Yahoo mail account. This alert has no title. -->
|
||||
<string name="provider_note_yahoo">Mailbox access is not supported for some types of
|
||||
Yahoo! mail accounts. If you have trouble connecting, visit yahoo.com for more
|
||||
|
|
|
@ -450,6 +450,14 @@ public class Account {
|
|||
mSyncWindow = window;
|
||||
}
|
||||
|
||||
public int getBackupFlags() {
|
||||
return mBackupFlags;
|
||||
}
|
||||
|
||||
public void setBackupFlags(int flags) {
|
||||
mBackupFlags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Account) {
|
||||
|
|
|
@ -579,7 +579,7 @@ public class LegacyConversions {
|
|||
* @param fromAccount the legacy account to convert to modern format
|
||||
* @return an Account ready to be committed to provider
|
||||
*/
|
||||
/* package */ static EmailContent.Account makeAccount(Context context, Account fromAccount) {
|
||||
public static EmailContent.Account makeAccount(Context context, Account fromAccount) {
|
||||
|
||||
EmailContent.Account result = new EmailContent.Account();
|
||||
|
||||
|
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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.Account;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.LegacyConversions;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.email.mail.Folder;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.AccountColumns;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This activity will be used whenever we have a large/slow bulk upgrade operation.
|
||||
*
|
||||
* Note: It's preferable to check for "accounts needing upgrade" before launching this
|
||||
* activity, so as to not waste time before every launch.
|
||||
*
|
||||
* TODO: Disable orientation changes, to keep the activity from restarting on rotation. This is
|
||||
* set in the manifest but for some reason it's not working.
|
||||
* TODO: More work on actual conversions
|
||||
*/
|
||||
public class UpgradeAccounts extends ListActivity implements OnClickListener {
|
||||
|
||||
private AccountInfo[] mLegacyAccounts;
|
||||
private UIHandler mHandler = new UIHandler();
|
||||
private AccountsAdapter mAdapter;
|
||||
private ListView mListView;
|
||||
private Button mProceedButton;
|
||||
private ConversionTask mConversionTask;
|
||||
|
||||
/** This projection is for looking up accounts by their legacy UUID */
|
||||
private static final String WHERE_ACCOUNT_UUID_IS = AccountColumns.COMPATIBILITY_UUID + "=?";
|
||||
|
||||
public static void actionStart(Activity fromActivity) {
|
||||
Intent i = new Intent(fromActivity, UpgradeAccounts.class);
|
||||
fromActivity.startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
Preferences p = Preferences.getPreferences(this);
|
||||
loadAccountInfoArray(p.getAccounts());
|
||||
|
||||
Log.d(Email.LOG_TAG, "*** Preparing to upgrade " +
|
||||
Integer.toString(mLegacyAccounts.length) + " accounts");
|
||||
|
||||
setContentView(R.layout.upgrade_accounts);
|
||||
mListView = getListView();
|
||||
mProceedButton = (Button) findViewById(R.id.action_button);
|
||||
mProceedButton.setEnabled(false);
|
||||
mProceedButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
updateList();
|
||||
|
||||
// Start the big conversion engine
|
||||
mConversionTask = new ConversionTask(mLegacyAccounts);
|
||||
mConversionTask.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (mConversionTask != null &&
|
||||
mConversionTask.getStatus() != ConversionTask.Status.FINISHED) {
|
||||
mConversionTask.cancel(true);
|
||||
mConversionTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.action_button:
|
||||
onClickOk();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onClickOk() {
|
||||
Welcome.actionStart(UpgradeAccounts.this);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
mAdapter = new AccountsAdapter();
|
||||
getListView().setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
private static class AccountInfo {
|
||||
Account account;
|
||||
int maxProgress;
|
||||
int progress;
|
||||
String error;
|
||||
}
|
||||
|
||||
private void loadAccountInfoArray(Account[] legacyAccounts) {
|
||||
mLegacyAccounts = new AccountInfo[legacyAccounts.length];
|
||||
for (int i = 0; i < legacyAccounts.length; i++) {
|
||||
AccountInfo ai = new AccountInfo();
|
||||
ai.account = legacyAccounts[i];
|
||||
ai.maxProgress = 0;
|
||||
ai.progress = 0;
|
||||
ai.error = null;
|
||||
mLegacyAccounts[i] = ai;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
TextView displayName;
|
||||
ProgressBar progress;
|
||||
TextView errorReport;
|
||||
}
|
||||
|
||||
class AccountsAdapter extends BaseAdapter {
|
||||
final LayoutInflater mInflater;
|
||||
|
||||
AccountsAdapter() {
|
||||
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mLegacyAccounts.length;
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return mLegacyAccounts[position];
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View v;
|
||||
if (convertView == null) {
|
||||
v = newView(parent);
|
||||
} else {
|
||||
v = convertView;
|
||||
}
|
||||
bindView(v, position);
|
||||
return v;
|
||||
}
|
||||
|
||||
public View newView(ViewGroup parent) {
|
||||
View v = mInflater.inflate(R.layout.upgrade_accounts_item, parent, false);
|
||||
ViewHolder h = new ViewHolder();
|
||||
h.displayName = (TextView) v.findViewById(R.id.name);
|
||||
h.progress = (ProgressBar) v.findViewById(R.id.progress);
|
||||
h.errorReport = (TextView) v.findViewById(R.id.error);
|
||||
v.setTag(h);
|
||||
return v;
|
||||
}
|
||||
|
||||
public void bindView(View view, int position) {
|
||||
ViewHolder vh = (ViewHolder) view.getTag();
|
||||
AccountInfo ai = mLegacyAccounts[position];
|
||||
vh.displayName.setText(ai.account.getDescription());
|
||||
if (ai.error == null) {
|
||||
vh.errorReport.setVisibility(View.GONE);
|
||||
vh.progress.setVisibility(View.VISIBLE);
|
||||
vh.progress.setMax(ai.maxProgress);
|
||||
vh.progress.setProgress(ai.progress);
|
||||
} else {
|
||||
vh.progress.setVisibility(View.GONE);
|
||||
vh.errorReport.setVisibility(View.VISIBLE);
|
||||
vh.errorReport.setText(ai.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for updating UI from async workers
|
||||
*
|
||||
* TODO: I don't know the right paradigm for updating a progress bar in a ListView. I'd
|
||||
* like to be able to say, "update it if it's visible, skip it if it's not visible."
|
||||
*/
|
||||
class UIHandler extends Handler {
|
||||
private static final int MSG_SET_MAX = 1;
|
||||
private static final int MSG_SET_PROGRESS = 2;
|
||||
private static final int MSG_INC_PROGRESS = 3;
|
||||
private static final int MSG_ERROR = 4;
|
||||
|
||||
@Override
|
||||
public void handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_SET_MAX:
|
||||
mLegacyAccounts[msg.arg1].maxProgress = msg.arg2;
|
||||
mListView.invalidateViews(); // find a less annoying way to do that
|
||||
break;
|
||||
case MSG_SET_PROGRESS:
|
||||
mLegacyAccounts[msg.arg1].progress = msg.arg2;
|
||||
mListView.invalidateViews(); // find a less annoying way to do that
|
||||
break;
|
||||
case MSG_INC_PROGRESS:
|
||||
mLegacyAccounts[msg.arg1].progress++;
|
||||
mListView.invalidateViews(); // find a less annoying way to do that
|
||||
break;
|
||||
case MSG_ERROR:
|
||||
mLegacyAccounts[msg.arg1].error = (String) msg.obj;
|
||||
mListView.invalidateViews(); // find a less annoying way to do that
|
||||
mProceedButton.setEnabled(true);
|
||||
break;
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxProgress(int accountNum, int max) {
|
||||
android.os.Message msg = android.os.Message.obtain();
|
||||
msg.what = MSG_SET_MAX;
|
||||
msg.arg1 = accountNum;
|
||||
msg.arg2 = max;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
public void setProgress(int accountNum, int progress) {
|
||||
android.os.Message msg = android.os.Message.obtain();
|
||||
msg.what = MSG_SET_PROGRESS;
|
||||
msg.arg1 = accountNum;
|
||||
msg.arg2 = progress;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
public void incProgress(int accountNum) {
|
||||
android.os.Message msg = android.os.Message.obtain();
|
||||
msg.what = MSG_INC_PROGRESS;
|
||||
msg.arg1 = accountNum;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
// Note: also enables the "OK" button, so we pause when complete
|
||||
public void error(String error) {
|
||||
android.os.Message msg = android.os.Message.obtain();
|
||||
msg.what = MSG_ERROR;
|
||||
msg.obj = error;
|
||||
sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything above was UI plumbing. This is the meat of this class - a conversion
|
||||
* engine to rebuild accounts from the "LocalStore" (pre Android 2.0) format to the
|
||||
* "Provider" (2.0 and beyond) format.
|
||||
*/
|
||||
private class ConversionTask extends AsyncTask<Void, Void, Void> {
|
||||
UpgradeAccounts.AccountInfo[] mAccountInfo;
|
||||
final Context mContext;
|
||||
final Preferences mPreferences;
|
||||
|
||||
public ConversionTask(UpgradeAccounts.AccountInfo[] accountInfo) {
|
||||
// TODO: should I copy this?
|
||||
mAccountInfo = accountInfo;
|
||||
mContext = UpgradeAccounts.this;
|
||||
mPreferences = Preferences.getPreferences(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
UIHandler handler = UpgradeAccounts.this.mHandler;
|
||||
// Step 1: Analyze accounts and generate progress max values
|
||||
for (int i = 0; i < mAccountInfo.length; i++) {
|
||||
int estimate = UpgradeAccounts.estimateWork(mContext, mAccountInfo[i].account);
|
||||
UpgradeAccounts.this.mHandler.setMaxProgress(i, estimate);
|
||||
}
|
||||
|
||||
// Step 2: Clean out IMAP accounts
|
||||
for (int i = 0; i < mAccountInfo.length; i++) {
|
||||
if (mAccountInfo[i].error == null) {
|
||||
cleanImapAccount(mContext, mAccountInfo[i].account, i, handler);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Copy accounts (and delete old accounts)
|
||||
for (int i = 0; i < mAccountInfo.length; i++) {
|
||||
if (mAccountInfo[i].error == null) {
|
||||
copyAccount(mContext, mAccountInfo[i].account, i, handler);
|
||||
}
|
||||
deleteAccountStore(mContext, mAccountInfo[i].account, handler);
|
||||
mAccountInfo[i].account.delete(mPreferences);
|
||||
|
||||
// reset the progress indicator to mark account "complete" (in case est was wrong)
|
||||
UpgradeAccounts.this.mHandler.setMaxProgress(i, 100);
|
||||
UpgradeAccounts.this.mHandler.setProgress(i, 100);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (!isCancelled()) {
|
||||
// if there were no errors, we never enabled the OK button, but
|
||||
// we'll just proceed through anyway and return to the Welcome activity
|
||||
if (!mProceedButton.isEnabled()) {
|
||||
onClickOk();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate the work required to convert an account.
|
||||
* 1 (account) + # folders + # messages + # attachments
|
||||
*/
|
||||
/* package */ static int estimateWork(Context context, Account account) {
|
||||
int estimate = 1; // account
|
||||
try {
|
||||
Store store = LocalStore.newInstance(account.getLocalStoreUri(), context, null);
|
||||
Folder[] folders = store.getPersonalNamespaces();
|
||||
estimate += folders.length;
|
||||
for (int i = 0; i < folders.length; i++) {
|
||||
Folder folder = folders[i];
|
||||
folder.open(Folder.OpenMode.READ_ONLY, null);
|
||||
estimate += folder.getMessageCount();
|
||||
}
|
||||
estimate += ((LocalStore)store).getStoredAttachmentCount();
|
||||
|
||||
} catch (MessagingException e) {
|
||||
Log.d(Email.LOG_TAG, "Exception while estimating account size " + e);
|
||||
}
|
||||
return estimate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean out an IMAP account. Anything we can reload from server, we delete. This seems
|
||||
* drastic, but it greatly reduces the risk of running out of disk space by copying everything.
|
||||
*/
|
||||
/* package */ void cleanImapAccount(Context context, Account account, int accountNum,
|
||||
UIHandler handler) {
|
||||
String storeUri = account.getStoreUri();
|
||||
if (!storeUri.startsWith(Store.STORE_SCHEME_IMAP)) {
|
||||
return;
|
||||
}
|
||||
if (handler != null) {
|
||||
handler.incProgress(accountNum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an account.
|
||||
*/
|
||||
/* package */ void copyAccount(Context context, Account account, int accountNum,
|
||||
UIHandler handler) {
|
||||
// If already exists- just skip it
|
||||
int existCount = EmailContent.count(context, EmailContent.Account.CONTENT_URI,
|
||||
WHERE_ACCOUNT_UUID_IS, new String[] { account.getUuid() });
|
||||
if (existCount > 0) {
|
||||
Log.d(Email.LOG_TAG, "No conversion, account exists: " + account.getDescription());
|
||||
if (handler != null) {
|
||||
handler.error(context.getString(R.string.upgrade_accounts_error));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Create the new account and write it
|
||||
EmailContent.Account newAccount = LegacyConversions.makeAccount(context, account);
|
||||
newAccount.save(context);
|
||||
if (handler != null) {
|
||||
handler.incProgress(accountNum);
|
||||
}
|
||||
|
||||
// TODO folders
|
||||
// TODO messages
|
||||
// TODO attachments
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an account
|
||||
*/
|
||||
/* package */ void deleteAccountStore(Context context, Account account, UIHandler handler) {
|
||||
try {
|
||||
Store store = LocalStore.newInstance(account.getLocalStoreUri(), context, null);
|
||||
store.delete();
|
||||
} catch (MessagingException e) {
|
||||
Log.d(Email.LOG_TAG, "Exception while deleting account " + e);
|
||||
if (handler != null) {
|
||||
handler.error(context.getString(R.string.upgrade_accounts_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,13 +16,16 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Account;
|
||||
import com.android.email.AccountBackupRestore;
|
||||
import com.android.email.ExchangeUtils;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.activity.setup.AccountSetupBasics;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
|
@ -39,6 +42,9 @@ import android.os.Bundle;
|
|||
*/
|
||||
public class Welcome extends Activity {
|
||||
|
||||
/** DO NOT CHECK IN AS 'TRUE' - DEVELOPMENT ONLY */
|
||||
private static final boolean DEBUG_FORCE_UPGRADES = false;
|
||||
|
||||
public static void actionStart(Activity fromActivity) {
|
||||
Intent i = new Intent(fromActivity, Welcome.class);
|
||||
fromActivity.startActivity(i);
|
||||
|
@ -48,6 +54,14 @@ public class Welcome extends Activity {
|
|||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
// Quickly check for bulk upgrades (from older app versions) and switch to the
|
||||
// upgrade activity if necessary
|
||||
if (bulkUpgradesRequired(this, Preferences.getPreferences(this))) {
|
||||
UpgradeAccounts.actionStart(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore accounts, if it has not happened already
|
||||
// NOTE: This is blocking, which it should not be (in the UI thread)
|
||||
// We're going to live with this for the short term and replace with something
|
||||
|
@ -65,8 +79,8 @@ public class Welcome extends Activity {
|
|||
Cursor c = null;
|
||||
try {
|
||||
c = getContentResolver().query(
|
||||
Account.CONTENT_URI,
|
||||
Account.ID_PROJECTION,
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.ID_PROJECTION,
|
||||
null, null, null);
|
||||
switch (c.getCount()) {
|
||||
case 0:
|
||||
|
@ -74,7 +88,7 @@ public class Welcome extends Activity {
|
|||
break;
|
||||
case 1:
|
||||
c.moveToFirst();
|
||||
long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
|
||||
long accountId = c.getLong(EmailContent.Account.CONTENT_ID_COLUMN);
|
||||
MessageList.actionHandleAccount(this, accountId, Mailbox.TYPE_INBOX);
|
||||
break;
|
||||
default:
|
||||
|
@ -90,4 +104,42 @@ public class Welcome extends Activity {
|
|||
// In all cases, do not return to this activity
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for bulk upgrades and return true if necessary
|
||||
*
|
||||
* TODO should be in an AsyncTask since it has DB ops
|
||||
*
|
||||
* @return true if upgrades required (old accounts exit). false otherwise.
|
||||
*/
|
||||
/* package */ boolean bulkUpgradesRequired(Context context, Preferences preferences) {
|
||||
if (DEBUG_FORCE_UPGRADES) {
|
||||
// build at least one fake account
|
||||
Account fake = new Account(this);
|
||||
fake.setDescription("Fake Account");
|
||||
fake.setEmail("user@gmail.com");
|
||||
fake.setName("First Last");
|
||||
fake.setSenderUri("smtp://user:password@smtp.gmail.com");
|
||||
fake.setStoreUri("imap://user:password@imap.gmail.com");
|
||||
fake.save(preferences);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1. Get list of legacy accounts and look for any non-backup entries
|
||||
Account[] legacyAccounts = preferences.getAccounts();
|
||||
if (legacyAccounts.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Look at the first legacy account and decide what to do
|
||||
// We only need to look at the first: If it's not a backup account, then it's a true
|
||||
// legacy account, and there are one or more accounts needing upgrade. If it is a backup
|
||||
// account, then we know for sure that there are no legacy accounts (backup deletes all
|
||||
// old accounts, and indicates that "modern" code has already run on this device.)
|
||||
if (0 != (legacyAccounts[0].getBackupFlags() & Account.BACKUP_FLAGS_IS_BACKUP)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,6 +365,20 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report # of attachments (for migration estimates only - catches all exceptions and
|
||||
* just returns zero)
|
||||
*/
|
||||
public int getStoredAttachmentCount() {
|
||||
try{
|
||||
File[] attachments = mAttachmentsDir.listFiles();
|
||||
return attachments.length;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all cached attachments for the entire store.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue