1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 11:42:16 -05:00

Add dialog to ask for server passwords after import

This commit is contained in:
cketti 2011-10-17 04:34:26 +02:00
parent 849a4e37a0
commit 52a92d93a1
10 changed files with 583 additions and 17 deletions

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dip">
<!-- Intro text -->
<TextView
android:id="@+id/password_prompt_intro"
android:text="In order to be able to use the account &quot;Test&quot; you need to specify the server password(s)"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dip"/>
<!-- Password prompt for the incoming server -->
<TextView
android:id="@+id/password_prompt_incoming_server"
android:text="Incoming server (imap.googlemail.com):"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/incoming_server_password"
android:inputType="textPassword"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginBottom="10dip"/>
<!-- Password prompt for the outgoing server. Won't be shown for WebDAV accounts! -->
<LinearLayout
android:id="@+id/outgoing_server_prompt"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/password_prompt_outgoing_server"
android:text="Outgoing server (smtp.googlemail.com):"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<CheckBox
android:id="@+id/use_incoming_server_password"
android:checked="true"
android:text="Use the incoming server password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/outgoing_server_password"
android:enabled="false"
android:inputType="textPassword"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginBottom="10dip"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- The context menu for disabled (newly imported) accounts -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/activate"
android:title="@string/activate_account_action" />
<item android:id="@+id/advanced"
android:title="@string/advanced">
<menu>
<item android:id="@+id/delete_account"
android:title="@string/remove_account_action" />
<item android:id="@+id/export"
android:title="@string/settings_export_account" />
<item android:id="@+id/move_up"
android:title="@string/manage_accounts_move_up_action" />
<item android:id="@+id/move_down"
android:title="@string/manage_accounts_move_down_action" />
</menu>
</item>
</menu>

View File

@ -1093,6 +1093,19 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="settings_export_failed_header">Export failed</string> <string name="settings_export_failed_header">Export failed</string>
<string name="settings_import_success_header">Import succeeded</string> <string name="settings_import_success_header">Import succeeded</string>
<string name="settings_import_failed_header">Import failed</string> <string name="settings_import_failed_header">Import failed</string>
<string name="settings_import_activate_account_header">Activate account</string>
<string name="settings_import_activate_account_intro">To be able to use the account \"<xliff:g id="account">%s</xliff:g>\" you need to provide the <xliff:g id="server_passwords">%s.</xliff:g></string>
<plurals name="settings_import_server_passwords">
<item quantity="one">server password</item>
<item quantity="other">server passwords</item>
</plurals>
<string name="settings_import_incoming_server">Incoming server (<xliff:g id="hostname">%s</xliff:g>):</string>
<string name="settings_import_outgoing_server">Outgoing server (<xliff:g id="hostname">%s</xliff:g>):</string>
<plurals name="settings_import_setting_passwords">
<item quantity="one">Setting password...</item>
<item quantity="other">Setting passwords...</item>
</plurals>
<string name="activate_account_action">Activate</string>
<string name="settings_unknown_version">Unable to handle file of version <xliff:g id="version">%s</xliff:g></string> <string name="settings_unknown_version">Unable to handle file of version <xliff:g id="version">%s</xliff:g></string>

View File

@ -148,6 +148,16 @@ public class Account implements BaseAccount {
private CryptoProvider mCryptoProvider = null; private CryptoProvider mCryptoProvider = null;
/**
* Indicates whether this account is enabled, i.e. ready for use, or not.
*
* <p>
* Right now newly imported accounts are disabled if the settings file didn't contain a
* password for the incoming and/or outgoing server.
* </p>
*/
private boolean mEnabled;
/** /**
* Name of the folder that was last selected for a copy or move operation. * Name of the folder that was last selected for a copy or move operation.
* *
@ -224,6 +234,7 @@ public class Account implements BaseAccount {
mSyncRemoteDeletions = true; mSyncRemoteDeletions = true;
mCryptoApp = Apg.NAME; mCryptoApp = Apg.NAME;
mCryptoAutoSignature = false; mCryptoAutoSignature = false;
mEnabled = true;
searchableFolders = Searchable.ALL; searchableFolders = Searchable.ALL;
@ -386,6 +397,7 @@ public class Account implements BaseAccount {
mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME); mCryptoApp = prefs.getString(mUuid + ".cryptoApp", Apg.NAME);
mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false); mCryptoAutoSignature = prefs.getBoolean(mUuid + ".cryptoAutoSignature", false);
mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
} }
private String combineUuids(String[] uuids) { private String combineUuids(String[] uuids) {
@ -467,6 +479,7 @@ public class Account implements BaseAccount {
editor.remove(mUuid + ".replyAfterQuote"); editor.remove(mUuid + ".replyAfterQuote");
editor.remove(mUuid + ".cryptoApp"); editor.remove(mUuid + ".cryptoApp");
editor.remove(mUuid + ".cryptoAutoSignature"); editor.remove(mUuid + ".cryptoAutoSignature");
editor.remove(mUuid + ".enabled");
editor.remove(mUuid + ".enableMoveButtons"); editor.remove(mUuid + ".enableMoveButtons");
editor.remove(mUuid + ".hideMoveButtonsEnum"); editor.remove(mUuid + ".hideMoveButtonsEnum");
for (String type : networkTypes) { for (String type : networkTypes) {
@ -619,6 +632,7 @@ public class Account implements BaseAccount {
editor.putBoolean(mUuid + ".replyAfterQuote", mReplyAfterQuote); editor.putBoolean(mUuid + ".replyAfterQuote", mReplyAfterQuote);
editor.putString(mUuid + ".cryptoApp", mCryptoApp); editor.putString(mUuid + ".cryptoApp", mCryptoApp);
editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature); editor.putBoolean(mUuid + ".cryptoAutoSignature", mCryptoAutoSignature);
editor.putBoolean(mUuid + ".enabled", mEnabled);
editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate()); editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate());
editor.putInt(mUuid + ".vibratePattern", mNotificationSetting.getVibratePattern()); editor.putInt(mUuid + ".vibratePattern", mNotificationSetting.getVibratePattern());
@ -1480,4 +1494,11 @@ public class Account implements BaseAccount {
return StorageManager.getInstance(K9.app).isReady(localStorageProviderId); return StorageManager.getInstance(K9.app).isReady(localStorageProviderId);
} }
public synchronized boolean isEnabled() {
return mEnabled;
}
public synchronized void setEnabled(boolean enabled) {
mEnabled = enabled;
}
} }

View File

@ -98,6 +98,23 @@ public class Preferences {
return retval; return retval;
} }
/**
* Returns all enabled accounts.
*
* @return All accounts with {@link Account#isEnabled()}
*/
public List<Account> getEnabledAccounts() {
Account[] allAccounts = getAccounts();
List<Account> enabledAccounts = new ArrayList<Account>();
for (Account account : allAccounts) {
if (account.isEnabled()) {
enabledAccounts.add(account);
}
}
return enabledAccounts;
}
public synchronized Account getAccount(String uuid) { public synchronized Account getAccount(String uuid) {
if (accounts == null) { if (accounts == null) {
loadAccounts(); loadAccounts();
@ -116,12 +133,12 @@ public class Preferences {
} }
public synchronized void deleteAccount(Account account) { public synchronized void deleteAccount(Account account) {
if (accounts != null) { if (accounts != null) {
accounts.remove(account.getUuid()); accounts.remove(account.getUuid());
} }
if (accountsInOrder != null) { if (accountsInOrder != null) {
accountsInOrder.remove(account); accountsInOrder.remove(account);
} }
account.delete(this); account.delete(this);

View File

@ -26,6 +26,8 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.util.TypedValue; import android.util.TypedValue;
@ -40,17 +42,22 @@ import android.view.View.OnClickListener;
import android.webkit.WebView; import android.webkit.WebView;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CheckedTextView; import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.fsck.k9.Account; import com.fsck.k9.Account;
import com.fsck.k9.AccountStats; import com.fsck.k9.AccountStats;
@ -70,13 +77,18 @@ import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.SizeFormatter; import com.fsck.k9.helper.SizeFormatter;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.Transport;
import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.StorageManager; import com.fsck.k9.mail.store.StorageManager;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.view.ColorChip; import com.fsck.k9.view.ColorChip;
import com.fsck.k9.preferences.SettingsExporter; import com.fsck.k9.preferences.SettingsExporter;
import com.fsck.k9.preferences.SettingsImportExportException; import com.fsck.k9.preferences.SettingsImportExportException;
import com.fsck.k9.preferences.SettingsImporter; import com.fsck.k9.preferences.SettingsImporter;
import com.fsck.k9.preferences.SettingsImporter.AccountDescription; import com.fsck.k9.preferences.SettingsImporter.AccountDescription;
import com.fsck.k9.preferences.SettingsImporter.AccountDescriptionPair;
import com.fsck.k9.preferences.SettingsImporter.ImportContents; import com.fsck.k9.preferences.SettingsImporter.ImportContents;
import com.fsck.k9.preferences.SettingsImporter.ImportResults; import com.fsck.k9.preferences.SettingsImporter.ImportResults;
@ -542,7 +554,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
MessageList.actionHandle(this, searchAccount.getDescription(), searchAccount); MessageList.actionHandle(this, searchAccount.getDescription(), searchAccount);
} else { } else {
Account realAccount = (Account)account; Account realAccount = (Account)account;
if (!realAccount.isAvailable(this)) { if (!realAccount.isEnabled()) {
onActivateAccount(realAccount);
return false;
} else if (!realAccount.isAvailable(this)) {
String toastText = getString(R.string.account_unavailable, account.getDescription()); String toastText = getString(R.string.account_unavailable, account.getDescription());
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT); Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT);
toast.show(); toast.show();
@ -559,6 +574,311 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
return true; return true;
} }
private void onActivateAccount(Account account) {
List<Account> disabledAccounts = new ArrayList<Account>();
disabledAccounts.add(account);
promptForServerPasswords(disabledAccounts);
}
/**
* Ask the user to enter the server passwords for disabled accounts.
*
* @param disabledAccounts
* A non-empty list of {@link Account}s to ask the user for passwords. Never
* {@code null}.
* <p><strong>Note:</strong> Calling this method will modify the supplied list.</p>
*/
private void promptForServerPasswords(final List<Account> disabledAccounts) {
Account account = disabledAccounts.remove(0);
PasswordPromptDialog dialog = new PasswordPromptDialog(account, disabledAccounts);
setNonConfigurationInstance(dialog);
dialog.show(this);
}
/**
* Ask the user for the incoming/outgoing server passwords.
*/
private static class PasswordPromptDialog implements NonConfigurationInstance, TextWatcher {
private AlertDialog mDialog;
private EditText mIncomingPasswordView;
private EditText mOutgoingPasswordView;
private CheckBox mUseIncomingView;
private Account mAccount;
private List<Account> mRemainingAccounts;
private String mIncomingPassword;
private String mOutgoingPassword;
private boolean mUseIncoming;
/**
* Constructor
*
* @param account
* The {@link Account} to ask the server passwords for. Never {@code null}.
* @param accounts
* The (possibly empty) list of remaining accounts to ask passwords for. Never
* {@code null}.
*/
PasswordPromptDialog(Account account, List<Account> accounts) {
mAccount = account;
mRemainingAccounts = accounts;
}
@Override
public void restore(Activity activity) {
show((Accounts) activity, true);
}
@Override
public boolean retain() {
if (mDialog != null) {
// Retain entered passwords and checkbox state
mIncomingPassword = mIncomingPasswordView.getText().toString();
if (mOutgoingPasswordView != null) {
mOutgoingPassword = mOutgoingPasswordView.getText().toString();
mUseIncoming = mUseIncomingView.isChecked();
}
// Dismiss dialog
mDialog.dismiss();
// Clear all references to UI objects
mDialog = null;
mIncomingPasswordView = null;
mOutgoingPasswordView = null;
mUseIncomingView = null;
return true;
}
return false;
}
public void show(Accounts activity) {
show(activity, false);
}
private void show(final Accounts activity, boolean restore) {
ServerSettings incoming = Store.decodeStoreUri(mAccount.getStoreUri());
ServerSettings outgoing = Transport.decodeTransportUri(mAccount.getTransportUri());
// Don't ask for the password to the outgoing server for WebDAV accounts, because
// incoming and outgoing servers are identical for this account type.
boolean configureOutgoingServer = !WebDavStore.STORE_TYPE.equals(outgoing.type);
// Create a ScrollView that will be used as container for the whole layout
final ScrollView scrollView = new ScrollView(activity);
// Create the dialog
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(activity.getString(R.string.settings_import_activate_account_header));
builder.setView(scrollView);
builder.setPositiveButton(activity.getString(R.string.okay_action),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String incomingPassword = mIncomingPasswordView.getText().toString();
String outgoingPassword = null;
if (mOutgoingPasswordView != null) {
outgoingPassword = (mUseIncomingView.isChecked()) ?
incomingPassword : mOutgoingPasswordView.getText().toString();
}
dialog.dismiss();
// Set the server passwords in the background
SetPasswordsAsyncTask asyncTask = new SetPasswordsAsyncTask(activity, mAccount,
incomingPassword, outgoingPassword, mRemainingAccounts);
activity.setNonConfigurationInstance(asyncTask);
asyncTask.execute();
}
});
builder.setNegativeButton(activity.getString(R.string.cancel_action),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
activity.setNonConfigurationInstance(null);
}
});
mDialog = builder.create();
// Use the dialog's layout inflater so its theme is used (and not the activity's theme).
View layout = mDialog.getLayoutInflater().inflate(
R.layout.accounts_password_prompt, null);
// Set the intro text that tells the user what to do
TextView intro = (TextView) layout.findViewById(R.id.password_prompt_intro);
String serverPasswords = activity.getResources().getQuantityString(
R.plurals.settings_import_server_passwords,
(configureOutgoingServer) ? 2 : 1);
intro.setText(activity.getString(R.string.settings_import_activate_account_intro,
mAccount.getDescription(), serverPasswords));
// Display the hostname of the incoming server
TextView incomingText = (TextView) layout.findViewById(
R.id.password_prompt_incoming_server);
incomingText.setText(activity.getString(R.string.settings_import_incoming_server,
incoming.host));
mIncomingPasswordView = (EditText) layout.findViewById(R.id.incoming_server_password);
mIncomingPasswordView.addTextChangedListener(this);
if (configureOutgoingServer) {
// Display the hostname of the outgoing server
TextView outgoingText = (TextView) layout.findViewById(
R.id.password_prompt_outgoing_server);
outgoingText.setText(activity.getString(R.string.settings_import_outgoing_server,
outgoing.host));
mOutgoingPasswordView = (EditText) layout.findViewById(
R.id.outgoing_server_password);
mOutgoingPasswordView.addTextChangedListener(this);
mUseIncomingView = (CheckBox) layout.findViewById(
R.id.use_incoming_server_password);
mUseIncomingView.setChecked(true);
mUseIncomingView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mOutgoingPasswordView.setText(null);
mOutgoingPasswordView.setEnabled(false);
} else {
mOutgoingPasswordView.setText(mIncomingPasswordView.getText());
mOutgoingPasswordView.setEnabled(true);
}
}
});
} else {
layout.findViewById(R.id.outgoing_server_prompt).setVisibility(View.GONE);
}
// Add the layout to the ScrollView
scrollView.addView(layout);
// Show the dialog
mDialog.show();
// Restore the contents of the password boxes and the checkbox (if the dialog was
// retained during a configuration change).
if (restore) {
mIncomingPasswordView.setText(mIncomingPassword);
if (configureOutgoingServer) {
mOutgoingPasswordView.setText(mOutgoingPassword);
mUseIncomingView.setChecked(mUseIncoming);
}
} else {
// Trigger afterTextChanged() being called
// Work around this bug: https://code.google.com/p/android/issues/detail?id=6360
mIncomingPasswordView.setText(mIncomingPasswordView.getText());
}
}
@Override
public void afterTextChanged(Editable arg0) {
boolean enable = false;
// Is the password box for the incoming server password empty?
if (mIncomingPasswordView.getText().length() > 0) {
// Do we need to check the outgoing server password box?
if (mOutgoingPasswordView == null) {
enable = true;
}
// If the checkbox to use the incoming server password is checked we need to make
// sure that the password box for the outgoing server isn't empty.
else if (mUseIncomingView.isChecked() ||
mOutgoingPasswordView.getText().length() > 0) {
enable = true;
}
}
// Disable "OK" button if the user hasn't specified all necessary passwords.
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(enable);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Not used
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Not used
}
}
/**
* Set the incoming/outgoing server password in the background.
*/
private static class SetPasswordsAsyncTask extends ExtendedAsyncTask<Void, Void, Void> {
private Account mAccount;
private String mIncomingPassword;
private String mOutgoingPassword;
private List<Account> mRemainingAccounts;
protected SetPasswordsAsyncTask(Activity activity, Account account,
String incomingPassword, String outgoingPassword,
List<Account> remainingAccounts) {
super(activity);
mAccount = account;
mIncomingPassword = incomingPassword;
mOutgoingPassword = outgoingPassword;
mRemainingAccounts = remainingAccounts;
}
@Override
protected void showProgressDialog() {
String title = mActivity.getString(R.string.settings_import_activate_account_header);
int passwordCount = (mOutgoingPassword == null) ? 1 : 2;
String message = mActivity.getResources().getQuantityString(
R.plurals.settings_import_setting_passwords, passwordCount);
mProgressDialog = ProgressDialog.show(mActivity, title, message, true);
}
@Override
protected Void doInBackground(Void... params) {
try {
// Set incoming server password
String storeUri = mAccount.getStoreUri();
ServerSettings incoming = Store.decodeStoreUri(storeUri);
ServerSettings newIncoming = incoming.newPassword(mIncomingPassword);
String newStoreUri = Store.createStoreUri(newIncoming);
mAccount.setStoreUri(newStoreUri);
if (mOutgoingPassword != null) {
// Set outgoing server password
String transportUri = mAccount.getTransportUri();
ServerSettings outgoing = Transport.decodeTransportUri(transportUri);
ServerSettings newOutgoing = outgoing.newPassword(mOutgoingPassword);
String newTransportUri = Transport.createTransportUri(newOutgoing);
mAccount.setTransportUri(newTransportUri);
}
// Mark account as enabled
mAccount.setEnabled(true);
// Save the account settings
mAccount.save(Preferences.getPreferences(mContext));
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Something went while setting account passwords", e);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
Accounts activity = (Accounts) mActivity;
// Let the activity know that the background task is complete
activity.setNonConfigurationInstance(null);
activity.refresh();
removeProgressDialog();
if (mRemainingAccounts.size() > 0) {
activity.promptForServerPasswords(mRemainingAccounts);
}
}
}
public void onClick(View view) { public void onClick(View view) {
if (view.getId() == R.id.next) { if (view.getId() == R.id.next) {
onAddNewAccount(); onAddNewAccount();
@ -683,6 +1003,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
case R.id.open: case R.id.open:
onOpenAccount(mSelectedContextAccount); onOpenAccount(mSelectedContextAccount);
break; break;
case R.id.activate:
onActivateAccount(realAccount);
break;
case R.id.check_mail: case R.id.check_mail:
onCheckMail(realAccount); onCheckMail(realAccount);
break; break;
@ -866,10 +1189,16 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.accounts_context_menu_title); menu.setHeaderTitle(R.string.accounts_context_menu_title);
getMenuInflater().inflate(R.menu.accounts_context, menu);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
BaseAccount account = mAdapter.getItem(info.position); BaseAccount account = mAdapter.getItem(info.position);
if ((account instanceof Account) && !((Account) account).isEnabled()) {
getMenuInflater().inflate(R.menu.disabled_accounts_context, menu);
} else {
getMenuInflater().inflate(R.menu.accounts_context, menu);
}
if (account instanceof SearchAccount) { if (account instanceof SearchAccount) {
for (int i = 0; i < menu.size(); i++) { for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i); MenuItem item = menu.getItem(i);
@ -930,6 +1259,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
setNonConfigurationInstance(dialog); setNonConfigurationInstance(dialog);
} }
/**
* A simple dialog.
*/
private static class SimpleDialog implements NonConfigurationInstance { private static class SimpleDialog implements NonConfigurationInstance {
private final int mHeaderRes; private final int mHeaderRes;
private final int mMessageRes; private final int mMessageRes;
@ -958,7 +1290,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
} }
public void show(final Accounts activity) { public void show(final Accounts activity) {
final String message = activity.getString(mMessageRes, mArguments); final String message = generateMessage(activity);
final AlertDialog.Builder builder = new AlertDialog.Builder(activity); final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(mHeaderRes); builder.setTitle(mHeaderRes);
@ -969,18 +1301,105 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
dialog.dismiss(); dialog.dismiss();
activity.setNonConfigurationInstance(null); activity.setNonConfigurationInstance(null);
okayAction(activity);
} }
}); });
mDialog = builder.show(); mDialog = builder.show();
} }
/**
* Returns the message the dialog should display.
*
* @param activity
* The {@code Activity} this dialog belongs to.
*
* @return The message the dialog should display
*/
protected String generateMessage(Accounts activity) {
return activity.getString(mMessageRes, mArguments);
}
/**
* This method is called after the "OK" button was pressed.
*
* @param activity
* The {@code Activity} this dialog belongs to.
*/
protected void okayAction(Accounts activity) {
// Do nothing
}
} }
/**
* Shows a dialog that displays how many accounts were successfully imported.
*
* @param importResults
* The {@link ImportResults} instance returned by the {@link SettingsImporter}.
* @param filename
* The name of the settings file that was imported.
*/
private void showAccountsImportedDialog(ImportResults importResults, String filename) {
AccountsImportedDialog dialog = new AccountsImportedDialog(importResults, filename);
dialog.show(this);
setNonConfigurationInstance(dialog);
}
/**
* A dialog that displays how many accounts were successfully imported.
*/
private static class AccountsImportedDialog extends SimpleDialog {
private ImportResults mImportResults;
private String mFilename;
AccountsImportedDialog(ImportResults importResults, String filename) {
super(R.string.settings_import_success_header, R.string.settings_import_success);
mImportResults = importResults;
mFilename = filename;
}
@Override
protected String generateMessage(Accounts activity) {
//TODO: display names of imported accounts (name from file *and* possibly new name)
int imported = mImportResults.importedAccounts.size();
String accounts = activity.getResources().getQuantityString(
R.plurals.settings_import_success, imported, imported);
return activity.getString(R.string.settings_import_success, accounts, mFilename);
}
@Override
protected void okayAction(Accounts activity) {
Context context = activity.getApplicationContext();
Preferences preferences = Preferences.getPreferences(context);
List<Account> disabledAccounts = new ArrayList<Account>();
for (AccountDescriptionPair accountPair : mImportResults.importedAccounts) {
Account account = preferences.getAccount(accountPair.imported.uuid);
if (!account.isEnabled()) {
disabledAccounts.add(account);
}
}
activity.promptForServerPasswords(disabledAccounts);
}
}
/**
* Display a dialog that lets the user select which accounts to import from the settings file.
*
* @param importContents
* The {@link ImportContents} instance returned by
* {@link SettingsImporter#getImportStreamContents(InputStream)}
* @param uri
* The (content) URI of the settings file.
*/
private void showImportSelectionDialog(ImportContents importContents, Uri uri) { private void showImportSelectionDialog(ImportContents importContents, Uri uri) {
ImportSelectionDialog dialog = new ImportSelectionDialog(importContents, uri); ImportSelectionDialog dialog = new ImportSelectionDialog(importContents, uri);
dialog.show(this); dialog.show(this);
setNonConfigurationInstance(dialog); setNonConfigurationInstance(dialog);
} }
/**
* A dialog that lets the user select which accounts to import from the settings file.
*/
private static class ImportSelectionDialog implements NonConfigurationInstance { private static class ImportSelectionDialog implements NonConfigurationInstance {
private ImportContents mImportContents; private ImportContents mImportContents;
private Uri mUri; private Uri mUri;
@ -1104,6 +1523,14 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
} }
} }
/**
* Set the {@code NonConfigurationInstance} this activity should retain on configuration
* changes.
*
* @param inst
* The {@link NonConfigurationInstance} that should be retained when
* {@link Accounts#onRetainNonConfigurationInstance()} is called.
*/
private void setNonConfigurationInstance(NonConfigurationInstance inst) { private void setNonConfigurationInstance(NonConfigurationInstance inst) {
mNonConfigurationInstance = inst; mNonConfigurationInstance = inst;
} }
@ -1438,17 +1865,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
boolean globalSettings = mImportResults.globalSettings; boolean globalSettings = mImportResults.globalSettings;
int imported = mImportResults.importedAccounts.size(); int imported = mImportResults.importedAccounts.size();
if (success && (globalSettings || imported > 0)) { if (success && (globalSettings || imported > 0)) {
//TODO: display names of imported accounts (name from file *and* possibly new name)
if (imported == 0) { if (imported == 0) {
activity.showSimpleDialog(R.string.settings_import_success_header, activity.showSimpleDialog(R.string.settings_import_success_header,
R.string.settings_import_global_settings_success, filename); R.string.settings_import_global_settings_success, filename);
} else { } else {
String importedAccounts = activity.getResources().getQuantityString( activity.showAccountsImportedDialog(mImportResults, filename);
R.plurals.settings_import_success, imported);
activity.showSimpleDialog(R.string.settings_import_success_header,
R.string.settings_import_success, importedAccounts, filename);
} }
activity.refresh(); activity.refresh();

View File

@ -125,4 +125,9 @@ public class ServerSettings {
map.put(key, value); map.put(key, value);
} }
} }
public ServerSettings newPassword(String newPassword) {
return new ServerSettings(type, host, port, connectionSecurity, authenticationType,
username, newPassword);
}
} }

View File

@ -305,6 +305,12 @@ public class ImapStore extends Store {
putIfNotNull(extra, PATH_PREFIX_KEY, pathPrefix); putIfNotNull(extra, PATH_PREFIX_KEY, pathPrefix);
return extra; return extra;
} }
@Override
public ServerSettings newPassword(String newPassword) {
return new ImapStoreSettings(host, port, connectionSecurity, authenticationType,
username, newPassword, pathPrefix);
}
} }

View File

@ -298,6 +298,12 @@ public class WebDavStore extends Store {
putIfNotNull(extra, MAILBOX_PATH_KEY, mailboxPath); putIfNotNull(extra, MAILBOX_PATH_KEY, mailboxPath);
return extra; return extra;
} }
@Override
public ServerSettings newPassword(String newPassword) {
return new WebDavStoreSettings(host, port, connectionSecurity, authenticationType,
username, newPassword, alias, path, authPath, mailboxPath);
}
} }

View File

@ -77,7 +77,7 @@ public class SettingsImporter {
} }
} }
private static class AccountDescriptionPair { public static class AccountDescriptionPair {
public final AccountDescription original; public final AccountDescription original;
public final AccountDescription imported; public final AccountDescription imported;