AI 144953: Provide UI for push mode accounts.

1.  Generalize the code for the various spinners that control
  account check frequency.
  2.  Provide an API for looking up store attributes (and refactor
  existing instatiateStore logic to use it).
  3.  Cleanup the old code that was used to setup frequency spinners.
  4.  Hardwire Exchange accounts to default into push mode.
  Notes to tester:
  1.  For each account type (POP, IMAP, EAS) we need to check that
  auto & manual creation "do the right thing" for frequencies.
  POP & IMAP should offer "none" or time intervals, while EAS
  should offer "push", "none", or time intervals.
  2.  EAS accounts should default to "push", all others to "15 min"
  3.  Make sure that you can edit existing account settings and see
  the right choices (only EAS should be offered push).
  4.  I couldn't write an automated test for the mail checker service,
  please confirm that POP & IMAP accounts are checked at the right
  intervals (or never, if set for "none".)
  BUG=1776149

Automated import of CL 144953
This commit is contained in:
Andy Stadler 2009-04-07 17:35:13 -07:00 committed by The Android Open Source Project
parent 1b32206538
commit ea6fea9bb2
12 changed files with 447 additions and 50 deletions

View File

@ -39,4 +39,26 @@
<item>60</item>
</string-array>
<!-- The arrays that are presented to push-enabled accounts -->
<string-array name="account_settings_check_frequency_entries_push">
<item>@string/account_setup_options_mail_check_frequency_push</item>
<item>@string/account_setup_options_mail_check_frequency_never</item>
<item>@string/account_setup_options_mail_check_frequency_5min</item>
<item>@string/account_setup_options_mail_check_frequency_10min</item>
<item>@string/account_setup_options_mail_check_frequency_15min</item>
<item>@string/account_setup_options_mail_check_frequency_30min</item>
<item>@string/account_setup_options_mail_check_frequency_1hour</item>
</string-array>
<string-array name="account_settings_check_frequency_values_push" translatable="false">
<item>-2</item>
<item>-1</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>30</item>
<item>60</item>
</string-array>
</resources>

View File

@ -310,6 +310,8 @@
<string name="account_setup_options_mail_check_frequency_label">Email checking frequency</string>
<!-- In Account setup options & Account Settings screens, label for email check frequency option -->
<string name="account_setup_options_mail_check_frequency_never">Never</string>
<!-- In Account setup options & Account Settings screens, label for email check frequency option -->
<string name="account_setup_options_mail_check_frequency_push">Automatic (Push)</string>
<!-- In Account setup options & Account Settings screens, email check frequency option -->
<string name="account_setup_options_mail_check_frequency_5min">Every 5 minutes</string>
<!-- In Account setup options & Account Settings screens, email check frequency option -->

View File

@ -35,5 +35,6 @@
<store scheme="imap" class="com.android.email.mail.store.ImapStore" />
<!-- This is here for temporary demo purposes only. Do not ship with this. -->
<!-- store scheme="eas" class="com.android.email.mail.exchange.ExchangeStoreExample" / -->
<store scheme="eas" class="com.android.email.mail.exchange.ExchangeStoreExample"
push="true" />
</stores>

View File

@ -35,6 +35,9 @@ public class Account implements Serializable {
public static final int DELETE_POLICY_7DAYS = 1;
public static final int DELETE_POLICY_ON_DELETE = 2;
public static final int CHECK_INTERVAL_NEVER = -1;
public static final int CHECK_INTERVAL_PUSH = -2;
private static final long serialVersionUID = 2975156672298625121L;
String mUuid;

View File

@ -101,8 +101,16 @@ public class AccountSettings extends PreferenceActivity {
return false;
}
});
mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
// Before setting value, we may need to adjust the lists
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(mAccount.getStoreUri(), this);
if (info.mPushSupported) {
mCheckFrequency.setEntries(R.array.account_settings_check_frequency_entries_push);
mCheckFrequency.setEntryValues(R.array.account_settings_check_frequency_values_push);
}
mCheckFrequency.setValue(String.valueOf(mAccount.getAutomaticCheckIntervalMinutes()));
mCheckFrequency.setSummary(mCheckFrequency.getEntry());
mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {

View File

@ -109,7 +109,8 @@ public class AccountSetupAccountType extends Activity implements OnClickListener
/**
* The user has selected an exchange account type. Try to put together a URI using the entered
* email address. Also set the mail delete policy here, because there is no UI (for exchange).
* email address. Also set the mail delete policy here, because there is no UI (for exchange),
* and switch the default sync interval to "push".
*/
private void onExchange() {
try {
@ -125,6 +126,7 @@ public class AccountSetupAccountType extends Activity implements OnClickListener
}
// TODO: Confirm correct delete policy for exchange
mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE);
mAccount.setAutomaticCheckIntervalMinutes(Account.CHECK_INTERVAL_PUSH);
AccountSetupExchange.actionIncomingSettings(this, mAccount, mMakeDefault);
finish();
}

View File

@ -20,6 +20,7 @@ import com.android.email.Account;
import com.android.email.Email;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.mail.Store;
import android.app.Activity;
import android.content.Intent;
@ -61,24 +62,29 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
findViewById(R.id.next).setOnClickListener(this);
// NOTE: If you change these values, confirm that the new intervals exist in arrays.xml
// NOTE: It would be cleaner if the numeric values were obtained from the
// account_settings_check_frequency_values, array, so the options could be controlled
// entirely via XML.
SpinnerOption checkFrequencies[] = {
new SpinnerOption(-1,
getString(R.string.account_setup_options_mail_check_frequency_never)),
new SpinnerOption(5,
getString(R.string.account_setup_options_mail_check_frequency_5min)),
new SpinnerOption(10,
getString(R.string.account_setup_options_mail_check_frequency_10min)),
new SpinnerOption(15,
getString(R.string.account_setup_options_mail_check_frequency_15min)),
new SpinnerOption(30,
getString(R.string.account_setup_options_mail_check_frequency_30min)),
new SpinnerOption(60,
getString(R.string.account_setup_options_mail_check_frequency_1hour)),
};
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
boolean makeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
// Generate spinner entries using XML arrays used by the preferences
int frequencyValuesId;
int frequencyEntriesId;
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(mAccount.getStoreUri(), this);
if (info.mPushSupported) {
frequencyValuesId = R.array.account_settings_check_frequency_values_push;
frequencyEntriesId = R.array.account_settings_check_frequency_entries_push;
} else {
frequencyValuesId = R.array.account_settings_check_frequency_values;
frequencyEntriesId = R.array.account_settings_check_frequency_entries;
}
CharSequence[] frequencyValues = getResources().getTextArray(frequencyValuesId);
CharSequence[] frequencyEntries = getResources().getTextArray(frequencyEntriesId);
// Now create the array used by the Spinner
SpinnerOption[] checkFrequencies = new SpinnerOption[frequencyEntries.length];
for (int i = 0; i < frequencyEntries.length; i++) {
checkFrequencies[i] = new SpinnerOption(
Integer.valueOf(frequencyValues[i].toString()), frequencyEntries[i].toString());
}
ArrayAdapter<SpinnerOption> checkFrequenciesAdapter = new ArrayAdapter<SpinnerOption>(this,
android.R.layout.simple_spinner_item, checkFrequencies);
@ -86,9 +92,6 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCheckFrequencyView.setAdapter(checkFrequenciesAdapter);
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
boolean makeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
if (mAccount.equals(Preferences.getPreferences(this).getDefaultAccount()) || makeDefault) {
mDefaultView.setChecked(true);
}

View File

@ -85,33 +85,47 @@ public abstract class Store {
}
/**
* Find Store implementation object consulting with stores.xml file.
* Look up descriptive information about a particular type of store.
*/
private static Store findStore(int resourceId, String uri, Context context)
throws MessagingException {
Store store = null;
try {
XmlResourceParser xml = context.getResources().getXml(resourceId);
int xmlEventType;
// walk through stores.xml file.
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG &&
"store".equals(xml.getName())) {
String scheme = xml.getAttributeValue(null, "scheme");
if (uri.startsWith(scheme)) {
// found store entry whose scheme is matched with uri.
// then load store class.
String className = xml.getAttributeValue(null, "class");
store = instantiateStore(className, uri, context);
public static class StoreInfo {
public String mScheme;
public String mClassName;
public boolean mPushSupported = false;
public static StoreInfo getStoreInfo(String scheme, Context context) {
StoreInfo result = getStoreInfo(R.xml.stores_product, scheme, context);
if (result == null) {
result = getStoreInfo(R.xml.stores, scheme, context);
}
return result;
}
public static StoreInfo getStoreInfo(int resourceId, String scheme, Context context) {
try {
XmlResourceParser xml = context.getResources().getXml(resourceId);
int xmlEventType;
// walk through stores.xml file.
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG &&
"store".equals(xml.getName())) {
String xmlScheme = xml.getAttributeValue(null, "scheme");
if (scheme.startsWith(xmlScheme)) {
StoreInfo result = new StoreInfo();
result.mScheme = scheme;
result.mClassName = xml.getAttributeValue(null, "class");
result.mPushSupported = xml.getAttributeBooleanValue(
null, "push", false);
return result;
}
}
}
} catch (XmlPullParserException e) {
// ignore
} catch (IOException e) {
// ignore
}
} catch (XmlPullParserException e) {
// ignore
} catch (IOException e) {
// ignore
return null;
}
return store;
}
/**
@ -139,9 +153,9 @@ public abstract class Store {
throws MessagingException {
Store store = mStores.get(uri);
if (store == null) {
store = findStore(R.xml.stores_product, uri, context);
if (store == null) {
store = findStore(R.xml.stores, uri, context);
StoreInfo info = StoreInfo.getStoreInfo(uri, context);
if (info != null) {
store = instantiateStore(info.mClassName, uri, context);
}
if (store != null) {

View File

@ -86,7 +86,7 @@ public class MailService extends Service {
// and make a single call to controller.checkMail().
ArrayList<Account> accountsToCheck = new ArrayList<Account>();
for (Account account : Preferences.getPreferences(this).getAccounts()) {
if (account.getAutomaticCheckIntervalMinutes() != -1) {
if (account.getAutomaticCheckIntervalMinutes() > 0) {
accountsToCheck.add(account);
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2009 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.setup;
import com.android.email.Account;
import com.android.email.mail.Store;
import android.content.Intent;
import android.preference.ListPreference;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
/**
* Tests of basic UI logic in the AccountSettings screen.
*/
@MediumTest
public class AccountSettingsTests extends ActivityInstrumentationTestCase2<AccountSettings> {
private AccountSettings mActivity;
private ListPreference mCheckFrequency;
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
public AccountSettingsTests() {
super("com.android.email", AccountSettings.class);
}
/**
* Test that POP accounts aren't displayed with a push option
*/
public void testPushOptionPOP() {
Intent i = getTestIntent("Name", "pop3://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertFalse(hasPush);
}
/**
* Test that IMAP accounts aren't displayed with a push option
*/
public void testPushOptionIMAP() {
Intent i = getTestIntent("Name", "imap://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertFalse(hasPush);
}
/**
* Test that EAS accounts are displayed with a push option
*/
public void testPushOptionEAS() {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", this.getInstrumentation().getTargetContext())
== null) {
return;
}
Intent i = getTestIntent("Name", "eas://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertTrue(hasPush);
}
/**
* Get the activity (which causes it to be started, using our intent) and get the UI fields
*/
private void getActivityAndFields() {
mActivity = getActivity();
mCheckFrequency = (ListPreference) mActivity.findPreference(PREFERENCE_FREQUENCY);
}
/**
* Test the frequency values list for a particular value
*/
private boolean frequencySpinnerHasValue(int value) {
CharSequence[] values = mCheckFrequency.getEntryValues();
for (CharSequence listValue : values) {
if (listValue != null && Integer.parseInt(listValue.toString()) == value) {
return true;
}
}
return false;
}
/**
* Create an intent with the Account in it
*/
private Intent getTestIntent(String name, String storeUri) {
Account account = new Account(this.getInstrumentation().getTargetContext());
account.setName(name);
account.setStoreUri(storeUri);
Intent i = new Intent(Intent.ACTION_MAIN);
i.putExtra("account", account); // AccountSetupNames.EXTRA_ACCOUNT == "account"
return i;
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2009 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.setup;
import com.android.email.Account;
import com.android.email.R;
import com.android.email.mail.Store;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
/**
* Tests of basic UI logic in the AccountSetupOptions screen.
*/
@MediumTest
public class AccountSetupOptionsTests
extends ActivityInstrumentationTestCase2<AccountSetupOptions> {
private AccountSetupOptions mActivity;
private Spinner mCheckFrequencyView;
public AccountSetupOptionsTests() {
super("com.android.email", AccountSetupOptions.class);
}
/**
* Test that POP accounts aren't displayed with a push option
*/
public void testPushOptionPOP() {
Intent i = getTestIntent("Name", "pop3://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertFalse(hasPush);
}
/**
* Test that IMAP accounts aren't displayed with a push option
*/
public void testPushOptionIMAP() {
Intent i = getTestIntent("Name", "imap://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertFalse(hasPush);
}
/**
* Test that EAS accounts are displayed with a push option
*/
public void testPushOptionEAS() {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", this.getInstrumentation().getTargetContext())
== null) {
return;
}
Intent i = getTestIntent("Name", "eas://user:password@server.com");
this.setActivityIntent(i);
getActivityAndFields();
boolean hasPush = frequencySpinnerHasValue(Account.CHECK_INTERVAL_PUSH);
assertTrue(hasPush);
}
/**
* Get the activity (which causes it to be started, using our intent) and get the UI fields
*/
private void getActivityAndFields() {
mActivity = getActivity();
mCheckFrequencyView = (Spinner) mActivity.findViewById(R.id.account_check_frequency);
}
/**
* Test the frequency values list for a particular value
*/
private boolean frequencySpinnerHasValue(int value) {
SpinnerAdapter sa = mCheckFrequencyView.getAdapter();
for (int i = 0; i < sa.getCount(); ++i) {
SpinnerOption so = (SpinnerOption) sa.getItem(i);
if (so != null && ((Integer)so.value).intValue() == value) {
return true;
}
}
return false;
}
/**
* Create an intent with the Account in it
*/
private Intent getTestIntent(String name, String storeUri) {
Account account = new Account(this.getInstrumentation().getTargetContext());
account.setName(name);
account.setStoreUri(storeUri);
Intent i = new Intent(Intent.ACTION_MAIN);
i.putExtra("account", account); // AccountSetupNames.EXTRA_ACCOUNT == "account"
return i;
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2009 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.mail;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
/**
* Tests of StoreInfo & Store lookup in the Store abstract class
*/
@MediumTest
public class StoreTests extends AndroidTestCase {
/**
* Test StoreInfo & Store lookup for POP accounts
*/
public void testStoreLookupPOP() throws MessagingException {
final String storeUri = "pop3://user:password@server.com";
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(storeUri, getContext());
assertNotNull("storeInfo null", info);
assertNotNull("scheme null", info.mScheme);
assertNotNull("classname null", info.mClassName);
assertFalse(info.mPushSupported);
// This will throw MessagingException if the result would have been null
Store store = Store.getInstance(storeUri, getContext());
}
/**
* Test StoreInfo & Store lookup for IMAP accounts
*/
public void testStoreLookupIMAP() throws MessagingException {
final String storeUri = "imap://user:password@server.com";
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(storeUri, getContext());
assertNotNull("storeInfo null", info);
assertNotNull("scheme null", info.mScheme);
assertNotNull("classname null", info.mClassName);
assertFalse(info.mPushSupported);
// This will throw MessagingException if the result would have been null
Store store = Store.getInstance(storeUri, getContext());
}
/**
* Test StoreInfo & Store lookup for EAS accounts
*/
public void testStoreLookupEAS() throws MessagingException {
final String storeUri = "eas://user:password@server.com";
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(storeUri, getContext());
if (info != null) {
assertNotNull("scheme null", info.mScheme);
assertNotNull("classname null", info.mClassName);
assertTrue(info.mPushSupported);
// This will throw MessagingException if the result would have been null
Store store = Store.getInstance(storeUri, getContext());
} else {
try {
Store store = Store.getInstance(storeUri, getContext());
fail("MessagingException expected when EAS not supported");
} catch (MessagingException me) {
// expected - fall through
}
}
}
/**
* Test StoreInfo & Store lookup for unknown accounts
*/
public void testStoreLookupUnknown() {
final String storeUri = "bogus-scheme://user:password@server.com";
Store.StoreInfo info = Store.StoreInfo.getStoreInfo(storeUri, getContext());
assertNull(info);
try {
Store store = Store.getInstance(storeUri, getContext());
fail("MessagingException expected from bogus URI scheme");
} catch (MessagingException me) {
// expected - fall through
}
}
}