Continue generalization of account setup

* Put most setup parameters in services.xml (at a later date
  these can be obtained directly from services, but we're not
  in a position to modify Exchange until next OS release)
* Make more parts of setup reference service information rather
  than directly refer to specific protocols
* Base account type buttons on declared services
* Continue the effort to make Stores obsolete

Change-Id: I50d08f3c0676e606b6b6c09fc22571ee5a7690e6
This commit is contained in:
Marc Blank 2012-06-09 18:36:00 -07:00
parent 58035979ff
commit 83adfb99a0
22 changed files with 445 additions and 741 deletions

View File

@ -212,7 +212,7 @@
</intent-filter>
</activity>
<activity
android:name=".activity.setup.AccountSetupAccountType"
android:name=".activity.setup.AccountSetupType"
android:label="@string/account_setup_account_type_title"
>
</activity>
@ -226,11 +226,6 @@
android:label="@string/account_setup_outgoing_title"
>
</activity>
<activity
android:name=".activity.setup.AccountSetupExchange"
android:label="@string/account_setup_exchange_title"
>
</activity>
<activity
android:name=".activity.setup.AccountSetupOptions"
android:label="@string/account_setup_options_title"

View File

@ -17,6 +17,7 @@
<!-- small -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/accountTypes"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@ -31,32 +32,4 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
/>
<Button
android:id="@+id/pop"
android:text="@string/account_setup_account_type_pop_action"
android:layout_height="wrap_content"
android:layout_width="150sp"
android:layout_marginTop="25dip"
android:minWidth="@dimen/button_minWidth"
android:layout_gravity="center_horizontal"
/>
<Button
android:id="@+id/imap"
android:text="@string/account_setup_account_type_imap_action"
android:layout_height="wrap_content"
android:layout_width="150sp"
android:layout_marginTop="25dip"
android:minWidth="@dimen/button_minWidth"
android:layout_gravity="center_horizontal"
/>
<Button
android:id="@+id/exchange"
android:text="@string/account_setup_account_type_exchange_action"
android:layout_height="wrap_content"
android:layout_width="150sp"
android:layout_marginTop="25dip"
android:minWidth="@dimen/button_minWidth"
android:layout_gravity="center_horizontal"
android:visibility="gone"
/>
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- small -->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/button"
android:text="@string/account_setup_options_mail_window_auto"
android:layout_height="wrap_content"
android:layout_width="150sp"
android:layout_marginTop="25dip"
android:minWidth="@dimen/button_minWidth"
android:layout_gravity="center_horizontal"
/>

View File

@ -21,4 +21,23 @@
<attr name="maxWidth" format="dimension"/>
<attr name="maxHeight" format="dimension"/>
</declare-styleable>
<declare-styleable name="EmailServiceInfo">
<attr name="protocol" format="string"/>
<attr name="name" format="string"/>
<attr name="accountType" format="string"/>
<attr name="serviceClass" format="string"/>
<attr name="intent" format="string"/>
<attr name="port" format="integer"/>
<attr name="portSsl" format="integer"/>
<attr name="preferSsl" format="boolean"/>
<attr name="usesSmtp" format="boolean"/>
<attr name="push" format="boolean"/>
<attr name="contacts" format="boolean"/>
<attr name="calendar" format="boolean"/>
<attr name="autodiscover" format="boolean"/>
<attr name="lookback" format="boolean"/>
<attr name="attachmentPreload" format="boolean"/>
<attr name="syncIntervalStrings" format="reference"/>
<attr name="syncIntervals" format="reference"/>
</declare-styleable>
</resources>

View File

@ -635,9 +635,7 @@ as <xliff:g id="filename">%s</xliff:g>.</string>
<!-- "Incoming server settings" screen, label for text field -->
<string name="account_setup_incoming_password_label">Password</string>
<!-- "Incoming server settings" screen, label for text field -->
<string name="account_setup_incoming_pop_server_label">POP3 server</string>
<!-- "Incoming server settings" screen, label for text field -->
<string name="account_setup_incoming_imap_server_label">IMAP server</string>
<string name="account_setup_incoming_server_label">Server</string>
<!-- "Incoming server settings" screen, label for text field -->
<string name="account_setup_incoming_port_label">Port</string>
<!-- "Incoming server settings" screen, label for pop-up menu -->

View File

@ -14,8 +14,42 @@
limitations under the License.
-->
<services>
<service protocol="pop3" name="POP3" class="com.android.email.service.ImapService" />
<service protocol="imap" name="IMAP" class="com.android.email.service.Pop3Service" />
<service protocol="eas" name="Exchange" intent="com.android.email.EXCHANGE_INTENT" />
</services>
<emailservices xmlns:email="http://schemas.android.com/apk/res/com.android.email">
<emailservice
email:protocol="pop3"
email:name="POP3"
email:accountType="com.android.email"
email:serviceClass="com.android.email.service.ImapService"
email:port="110"
email:portSsl="995"
email:usesSmtp="true"
email:syncIntervalStrings="@array/account_settings_check_frequency_entries"
email:syncIntervals="@array/account_settings_check_frequency_values" />
<emailservice
email:protocol="imap"
email:name="IMAP"
email:accountType="com.android.email"
email:serviceClass="com.android.email.service.Pop3Service"
email:attachmentPreload="true"
email:port="143"
email:portSsl="995"
email:usesSmtp="true"
email:syncIntervalStrings="@array/account_settings_check_frequency_entries"
email:syncIntervals="@array/account_settings_check_frequency_values" />
<emailservice
email:protocol="eas"
email:name="Exchange"
email:accountType="com.android.exchange"
email:intent="com.android.email.EXCHANGE_INTENT"
email:port="80"
email:portSsl="443"
email:preferSsl="true"
email:syncIntervalStrings="@array/account_settings_check_frequency_entries_push"
email:syncIntervals="@array/account_settings_check_frequency_values_push"
email:autodiscover="true"
email:attachmentPreload="true"
email:push="true"
email:lookback="true"
email:contacts="true"
email:calendar="true" />
</emailservices>

View File

@ -22,9 +22,6 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
@ -148,15 +145,6 @@ public abstract class AccountServerBaseFragment extends Fragment
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem item = menu.findItem(R.id.add_new_account);
//***
//if (item != null && !UiUtilities.useTwoPane(getActivity())) {
// item.setVisible(false);
//}
}
/**
* Called from onCreateView, to do settings mode configuration
*/
@ -423,6 +411,11 @@ public abstract class AccountServerBaseFragment extends Fragment
return sendChanged || recvChanged;
}
public boolean setHostAuthFromAutodiscover(HostAuth hostAuth) {
// This is overridden, if necessary
return true;
}
/**
* Save settings after "OK" result from checker. Concrete classes must implement.
* This is called from a worker thread and is allowed to perform DB operations.

View File

@ -40,7 +40,6 @@ import android.view.MenuItem;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.email.provider.EmailProvider;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
@ -313,10 +312,7 @@ public class AccountSettings extends PreferenceActivity {
}
private void launchMailboxSettings(Intent intent) {
final Folder folder =
(Folder)intent.getParcelableExtra(EditSettingsExtras.EXTRA_FOLDER);
final com.android.mail.providers.Account account = (com.android.mail.providers.Account)
intent.getParcelableExtra(EditSettingsExtras.EXTRA_ACCOUNT);
final Folder folder = (Folder)intent.getParcelableExtra(EditSettingsExtras.EXTRA_FOLDER);
// TODO: determine from the account if we should navigate to the mailbox settings.
// See bug 6242668
@ -648,27 +644,13 @@ public class AccountSettings extends PreferenceActivity {
/**
* Dispatch to edit incoming settings.
*
* TODO: Make things less hardwired
*/
public void onIncomingSettings(Account account) {
try {
Store store = Store.getInstance(account, getApplication());
if (store != null) {
Class<? extends android.app.Activity> setting = store.getSettingActivityClass();
if (setting != null) {
SetupData.init(SetupData.FLOW_MODE_EDIT, account);
if (setting.equals(AccountSetupIncoming.class)) {
startPreferencePanel(AccountSetupIncomingFragment.class.getName(),
AccountSetupIncomingFragment.getSettingsModeArgs(),
R.string.account_settings_incoming_label, null, null, 0);
} else if (setting.equals(AccountSetupExchange.class)) {
startPreferencePanel(AccountSetupExchangeFragment.class.getName(),
AccountSetupExchangeFragment.getSettingsModeArgs(),
R.string.account_settings_incoming_label, null, null, 0);
}
}
}
SetupData.init(SetupData.FLOW_MODE_EDIT, account);
startPreferencePanel(AccountSetupIncomingFragment.class.getName(),
AccountSetupIncomingFragment.getSettingsModeArgs(),
R.string.account_settings_incoming_label, null, null, 0);
} catch (Exception e) {
Log.d(Logging.LOG_TAG, "Error while trying to invoke store settings.", e);
}

View File

@ -37,12 +37,12 @@ import android.util.Log;
import com.android.email.R;
import com.android.email.SecurityPolicy;
import com.android.email.mail.Sender;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.email2.ui.MailActivityEmail;
import com.android.emailcommon.AccountManagerTypes;
import com.android.emailcommon.CalendarProviderStub;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.HostAuth;
@ -483,14 +483,10 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
mAccountSignature.setOnPreferenceChangeListener(this);
mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
// TODO Move protocol into Account to avoid retrieving the HostAuth (implicitly)
String protocol = Account.getProtocol(mContext, mAccount.mId);
if (HostAuth.SCHEME_EAS.equals(protocol)) {
mCheckFrequency.setEntries(R.array.account_settings_check_frequency_entries_push);
mCheckFrequency.setEntryValues(R.array.account_settings_check_frequency_values_push);
}
EmailServiceInfo info = EmailServiceUtils.getServiceInfo(mContext, protocol);
mCheckFrequency.setEntries(info.syncIntervalStrings);
mCheckFrequency.setEntryValues(info.syncIntervals);
mCheckFrequency.setValue(String.valueOf(mAccount.getSyncInterval()));
mCheckFrequency.setSummary(mCheckFrequency.getEntry());
mCheckFrequency.setOnPreferenceChangeListener(this);
@ -510,7 +506,7 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
(PreferenceCategory) findPreference(PREFERENCE_CATEGORY_DATA_USAGE);
mSyncWindow = null;
if (HostAuth.SCHEME_EAS.equals(protocol)) {
if (info.lookback) {
mSyncWindow = new ListPreference(mContext);
mSyncWindow.setTitle(R.string.account_setup_options_mail_window_label);
mSyncWindow.setValue(String.valueOf(mAccount.getSyncLookback()));
@ -533,10 +529,9 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
dataUsageCategory.addPreference(mSyncWindow);
}
// Show "background attachments" for IMAP & EAS - hide it for POP3.
mAccountBackgroundAttachments = (CheckBoxPreference)
findPreference(PREFERENCE_BACKGROUND_ATTACHMENTS);
if (HostAuth.SCHEME_POP3.equals(mAccount.mHostAuthRecv.mProtocol)) {
if (!info.attachmentPreload) {
dataUsageCategory.removePreference(mAccountBackgroundAttachments);
} else {
mAccountBackgroundAttachments.setChecked(
@ -639,17 +634,7 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
// Hide the outgoing account setup link if it's not activated
Preference prefOutgoing = findPreference(PREFERENCE_OUTGOING);
boolean showOutgoing = true;
try {
Sender sender = Sender.getInstance(mContext, mAccount);
if (sender != null) {
Class<? extends android.app.Activity> setting = sender.getSettingActivityClass();
showOutgoing = (setting != null);
}
} catch (MessagingException me) {
// just leave showOutgoing as true - bias towards showing it, so user can fix it
}
if (showOutgoing) {
if (info.usesSmtp) {
prefOutgoing.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
@ -668,15 +653,25 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
mSyncContacts = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CONTACTS);
mSyncCalendar = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_CALENDAR);
mSyncEmail = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_EMAIL);
if (mAccount.mHostAuthRecv.mProtocol.equals(HostAuth.SCHEME_EAS)) {
if (info.contacts || info.calendar) {
android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress,
AccountManagerTypes.TYPE_EXCHANGE);
mSyncContacts.setChecked(ContentResolver
.getSyncAutomatically(acct, ContactsContract.AUTHORITY));
mSyncContacts.setOnPreferenceChangeListener(this);
mSyncCalendar.setChecked(ContentResolver
.getSyncAutomatically(acct, CalendarProviderStub.AUTHORITY));
mSyncCalendar.setOnPreferenceChangeListener(this);
info.accountType);
if (info.contacts) {
mSyncContacts.setChecked(ContentResolver
.getSyncAutomatically(acct, ContactsContract.AUTHORITY));
mSyncContacts.setOnPreferenceChangeListener(this);
} else {
mSyncContacts.setChecked(false);
mSyncContacts.setEnabled(false);
}
if (info.calendar) {
mSyncCalendar.setChecked(ContentResolver
.getSyncAutomatically(acct, CalendarProviderStub.AUTHORITY));
mSyncCalendar.setOnPreferenceChangeListener(this);
} else {
mSyncCalendar.setChecked(false);
mSyncCalendar.setEnabled(false);
}
mSyncEmail.setChecked(ContentResolver
.getSyncAutomatically(acct, EmailContent.AUTHORITY));
mSyncEmail.setOnPreferenceChangeListener(this);
@ -728,7 +723,9 @@ public class AccountSettingsFragment extends EmailPreferenceFragment
mAccount.setRingtone(prefs.getString(PREFERENCE_RINGTONE, null));
mAccount.setFlags(newFlags);
if (mAccount.mHostAuthRecv.mProtocol.equals("eas")) {
EmailServiceInfo info =
EmailServiceUtils.getServiceInfo(mContext, mAccount.getProtocol(mContext));
if (info.contacts || info.calendar) {
android.accounts.Account acct = new android.accounts.Account(mAccount.mEmailAddress,
AccountManagerTypes.TYPE_EXCHANGE);
ContentResolver.setSyncAutomatically(acct, ContactsContract.AUTHORITY,

View File

@ -1,150 +0,0 @@
/*
* 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.setup;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.android.email.R;
import com.android.email.VendorPolicyLoader;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
/**
* Prompts the user to select an account type. The account type, along with the
* passed in email address, password and makeDefault are then passed on to the
* AccountSetupIncoming activity.
*/
public class AccountSetupAccountType extends AccountSetupActivity implements OnClickListener {
public static void actionSelectAccountType(Activity fromActivity) {
Intent i = new ForwardingIntent(fromActivity, AccountSetupAccountType.class);
fromActivity.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
int flowMode = SetupData.getFlowMode();
// If we're in account setup flow mode, for EAS, skip this screen and "click" EAS
if (flowMode == SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) {
onExchange();
return;
}
// Otherwise proceed into this screen
setContentView(R.layout.account_setup_account_type);
UiUtilities.getView(this, R.id.pop).setOnClickListener(this);
UiUtilities.getView(this, R.id.imap).setOnClickListener(this);
final Button exchangeButton = (Button) UiUtilities.getView(this, R.id.exchange);
exchangeButton.setVisibility(View.INVISIBLE);
final Button previousButton = (Button) findViewById(R.id.previous); // xlarge only
if (previousButton != null) previousButton.setOnClickListener(this);
// TODO If we decide to exclude the Exchange option in POP_IMAP mode, use the following line
// instead of the line that follows it
//if (ExchangeUtils.isExchangeAvailable(this) && flowMode != SetupData.FLOW_MODE_POP_IMAP) {
if (EmailServiceUtils.isServiceAvailable(this, "eas")) {
exchangeButton.setOnClickListener(this);
exchangeButton.setVisibility(View.VISIBLE);
if (VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings()) {
exchangeButton.setText(
R.string.account_setup_account_type_exchange_action_alternate);
}
}
// TODO: Dynamic creation of buttons, instead of just hiding things we don't need
}
/**
* For POP accounts, we rewrite the username to the full user@domain, and we set the
* default server name to pop3.domain
*/
private void onPop() {
Account account = SetupData.getAccount();
HostAuth hostAuth = account.mHostAuthRecv;
hostAuth.mProtocol = HostAuth.SCHEME_POP3;
hostAuth.mLogin = hostAuth.mLogin + "@" + hostAuth.mAddress;
hostAuth.mAddress = AccountSettingsUtils.inferServerName(hostAuth.mAddress,
HostAuth.SCHEME_POP3, null);
AccountSetupBasics.setFlagsForProtocol(account, HostAuth.SCHEME_POP3);
SetupData.setCheckSettingsMode(SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING);
AccountSetupIncoming.actionIncomingSettings(this, SetupData.getFlowMode(), account);
finish();
}
/**
* The user has selected an IMAP 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 IMAP).
*/
private void onImap() {
Account account = SetupData.getAccount();
HostAuth hostAuth = account.mHostAuthRecv;
hostAuth.mProtocol = HostAuth.SCHEME_IMAP;
hostAuth.mLogin = hostAuth.mLogin + "@" + hostAuth.mAddress;
hostAuth.mAddress = AccountSettingsUtils.inferServerName(hostAuth.mAddress,
HostAuth.SCHEME_IMAP, null);
AccountSetupBasics.setFlagsForProtocol(account, HostAuth.SCHEME_IMAP);
SetupData.setCheckSettingsMode(SetupData.CHECK_INCOMING | SetupData.CHECK_OUTGOING);
AccountSetupIncoming.actionIncomingSettings(this, SetupData.getFlowMode(), account);
finish();
}
/**
* The user has selected an exchange account type. Set the mail delete policy here, because
* there is no UI (for exchange), and switch the default sync interval to "push".
*/
private void onExchange() {
Account account = SetupData.getAccount();
HostAuth recvAuth = account.getOrCreateHostAuthRecv(this);
recvAuth.setConnection(HostAuth.SCHEME_EAS, recvAuth.mAddress, recvAuth.mPort,
recvAuth.mFlags | HostAuth.FLAG_SSL);
HostAuth sendAuth = account.getOrCreateHostAuthSend(this);
sendAuth.setConnection(HostAuth.SCHEME_EAS, sendAuth.mAddress, sendAuth.mPort,
sendAuth.mFlags | HostAuth.FLAG_SSL);
AccountSetupBasics.setFlagsForProtocol(account, HostAuth.SCHEME_EAS);
SetupData.setCheckSettingsMode(SetupData.CHECK_AUTODISCOVER);
AccountSetupExchange.actionIncomingSettings(this, SetupData.getFlowMode(), account);
finish();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.pop:
onPop();
break;
case R.id.imap:
onImap();
break;
case R.id.exchange:
onExchange();
break;
case R.id.previous:
finish();
break;
}
}
}

View File

@ -607,7 +607,7 @@ public class AccountSetupBasics extends AccountSetupActivity
populateSetupData(getOwnerName(), email, mDefaultView.isChecked());
SetupData.setAllowAutodiscover(allowAutoDiscover);
AccountSetupAccountType.actionSelectAccountType(this);
AccountSetupType.actionSelectAccountType(this);
}
/**

View File

@ -1,223 +0,0 @@
/*
* 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 android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
/**
* Provides generic setup for Exchange accounts. The following fields are supported:
*
* Email Address (from previous setup screen)
* Server
* Domain
* Requires SSL?
* User (login)
* Password
*
* There are two primary paths through this activity:
* Edit existing:
* Load existing values from account into fields
* When user clicks 'next':
* Confirm not a duplicate account
* Try new values (check settings)
* If new values are OK:
* Write new values (save to provider)
* finish() (pop to previous)
*
* Creating New:
* Try Auto-discover to get details from server
* If Auto-discover reports an authentication failure:
* finish() (pop to previous, to re-enter username & password)
* If Auto-discover succeeds:
* write server's account details into account
* Load values from account into fields
* Confirm not a duplicate account
* Try new values (check settings)
* If new values are OK:
* Write new values (save to provider)
* Proceed to options screen
* finish() (removes self from back stack)
*/
public class AccountSetupExchange extends AccountSetupActivity
implements AccountSetupExchangeFragment.Callback, OnClickListener {
// Keys for savedInstanceState
private final static String STATE_STARTED_AUTODISCOVERY =
"AccountSetupExchange.StartedAutoDiscovery";
boolean mStartedAutoDiscovery;
/* package */ AccountSetupExchangeFragment mFragment;
private Button mNextButton;
/* package */ boolean mNextButtonEnabled;
public static void actionIncomingSettings(Activity fromActivity, int mode, Account account) {
SetupData.setFlowMode(mode);
SetupData.setAccount(account);
fromActivity.startActivity(new ForwardingIntent(fromActivity, AccountSetupExchange.class));
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
setContentView(R.layout.account_setup_exchange);
mFragment = (AccountSetupExchangeFragment)
getFragmentManager().findFragmentById(R.id.setup_fragment);
mFragment.setCallback(this);
mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
// One-shot to launch autodiscovery at the entry to this activity (but not if it restarts)
mStartedAutoDiscovery = false;
if (savedInstanceState != null) {
mStartedAutoDiscovery = savedInstanceState.getBoolean(STATE_STARTED_AUTODISCOVERY);
}
if (!mStartedAutoDiscovery) {
startAutoDiscover();
}
}
/**
* Implements View.OnClickListener
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.next:
mFragment.onNext();
break;
case R.id.previous:
onBackPressed();
break;
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_STARTED_AUTODISCOVERY, mStartedAutoDiscovery);
}
/**
* If the conditions are right, launch the autodiscover fragment. If it succeeds (even
* partially) it will prefill the setup fields and we can proceed as if the user entered them.
*
* Conditions for skipping:
* Editing existing account
* AutoDiscover blocked (used for unit testing only)
* Username or password not entered yet
*/
private void startAutoDiscover() {
// Note that we've started autodiscovery - even if we decide not to do it,
// this prevents repeating.
mStartedAutoDiscovery = true;
if (!SetupData.isAllowAutodiscover()) {
return;
}
Account account = SetupData.getAccount();
// If we've got a username and password and we're NOT editing, try autodiscover
String username = account.mHostAuthRecv.mLogin;
String password = account.mHostAuthRecv.mPassword;
if (username != null && password != null) {
onProceedNext(SetupData.CHECK_AUTODISCOVER, mFragment);
}
}
/**
* Implements AccountCheckSettingsFragment.Callbacks
*
* @param result configuration data returned by AD server, or null if no data available
*/
public void onAutoDiscoverComplete(int result, HostAuth hostAuth) {
// If authentication failed, exit immediately (to re-enter credentials)
if (result == AccountCheckSettingsFragment.AUTODISCOVER_AUTHENTICATION) {
finish();
return;
}
// If data was returned, populate the account & populate the UI fields and validate it
if (result == AccountCheckSettingsFragment.AUTODISCOVER_OK) {
boolean valid = mFragment.setHostAuthFromAutodiscover(hostAuth);
if (valid) {
// "click" next to launch server verification
mFragment.onNext();
}
}
// Otherwise, proceed into this activity for manual setup
}
/**
* Implements AccountServerBaseFragment.Callback
*/
@Override
public void onProceedNext(int checkMode, AccountServerBaseFragment target) {
AccountCheckSettingsFragment checkerFragment =
AccountCheckSettingsFragment.newInstance(checkMode, target);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(checkerFragment, AccountCheckSettingsFragment.TAG);
transaction.addToBackStack("back");
transaction.commit();
}
/**
* Implements AccountServerBaseFragment.Callback
*/
@Override
public void onEnableProceedButtons(boolean enable) {
mNextButtonEnabled = enable;
mNextButton.setEnabled(enable);
}
/**
* Implements AccountServerBaseFragment.Callback
*
* If the checked settings are OK, proceed to options screen. If the user rejects security,
* exit this screen. For all other errors, remain here for editing.
*/
@Override
public void onCheckSettingsComplete(int result, int setupMode) {
switch (result) {
case AccountCheckSettingsFragment.CHECK_SETTINGS_OK:
AccountSetupOptions.actionOptions(this);
finish();
break;
case AccountCheckSettingsFragment.CHECK_SETTINGS_SECURITY_USER_DENY:
finish();
break;
default:
case AccountCheckSettingsFragment.CHECK_SETTINGS_SERVER_ERROR:
// Do nothing - remain in this screen
break;
}
}
}

View File

@ -393,7 +393,7 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
*/
@Override
public void onAutoDiscoverComplete(int result, HostAuth hostAuth) {
AccountSetupExchange activity = (AccountSetupExchange) getActivity();
AccountSetupIncoming activity = (AccountSetupIncoming) getActivity();
activity.onAutoDiscoverComplete(result, hostAuth);
}

View File

@ -16,11 +16,6 @@
package com.android.email.activity.setup;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.emailcommon.provider.Account;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.Intent;
@ -29,6 +24,14 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
/**
* Provides setup flow for IMAP/POP accounts.
*
@ -38,9 +41,15 @@ import android.widget.Button;
public class AccountSetupIncoming extends AccountSetupActivity
implements AccountSetupIncomingFragment.Callback, OnClickListener {
/* package */ AccountSetupIncomingFragment mFragment;
/* package */ AccountServerBaseFragment mFragment;
private Button mNextButton;
/* package */ boolean mNextButtonEnabled;
private boolean mStartedAutoDiscovery;
private EmailServiceInfo mServiceInfo;
// Keys for savedInstanceState
private final static String STATE_STARTED_AUTODISCOVERY =
"AccountSetupExchange.StartedAutoDiscovery";
public static void actionIncomingSettings(Activity fromActivity, int mode, Account account) {
SetupData.setFlowMode(mode);
@ -52,9 +61,14 @@ public class AccountSetupIncoming extends AccountSetupActivity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
setContentView(R.layout.account_setup_incoming);
mFragment = (AccountSetupIncomingFragment)
HostAuth hostAuth = SetupData.getAccount().mHostAuthRecv;
mServiceInfo = EmailServiceUtils.getServiceInfo(this, hostAuth.mProtocol);
setContentView(hostAuth.mProtocol.equals("eas") ? R.layout.account_setup_exchange :
R.layout.account_setup_incoming);
mFragment = (AccountServerBaseFragment)
getFragmentManager().findFragmentById(R.id.setup_fragment);
// Configure fragment
@ -63,6 +77,17 @@ public class AccountSetupIncoming extends AccountSetupActivity
mNextButton = (Button) UiUtilities.getView(this, R.id.next);
mNextButton.setOnClickListener(this);
UiUtilities.getView(this, R.id.previous).setOnClickListener(this);
// One-shot to launch autodiscovery at the entry to this activity (but not if it restarts)
if (mServiceInfo.autodiscover) {
mStartedAutoDiscovery = false;
if (savedInstanceState != null) {
mStartedAutoDiscovery = savedInstanceState.getBoolean(STATE_STARTED_AUTODISCOVERY);
}
if (!mStartedAutoDiscovery) {
startAutoDiscover();
}
}
}
/**
@ -80,6 +105,62 @@ public class AccountSetupIncoming extends AccountSetupActivity
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_STARTED_AUTODISCOVERY, mStartedAutoDiscovery);
}
/**
* If the conditions are right, launch the autodiscover fragment. If it succeeds (even
* partially) it will prefill the setup fields and we can proceed as if the user entered them.
*
* Conditions for skipping:
* Editing existing account
* AutoDiscover blocked (used for unit testing only)
* Username or password not entered yet
*/
private void startAutoDiscover() {
// Note that we've started autodiscovery - even if we decide not to do it,
// this prevents repeating.
mStartedAutoDiscovery = true;
if (!SetupData.isAllowAutodiscover()) {
return;
}
Account account = SetupData.getAccount();
// If we've got a username and password and we're NOT editing, try autodiscover
String username = account.mHostAuthRecv.mLogin;
String password = account.mHostAuthRecv.mPassword;
if (username != null && password != null) {
onProceedNext(SetupData.CHECK_AUTODISCOVER, mFragment);
}
}
/**
* Implements AccountCheckSettingsFragment.Callbacks
*
* @param result configuration data returned by AD server, or null if no data available
*/
public void onAutoDiscoverComplete(int result, HostAuth hostAuth) {
// If authentication failed, exit immediately (to re-enter credentials)
if (result == AccountCheckSettingsFragment.AUTODISCOVER_AUTHENTICATION) {
finish();
return;
}
// If data was returned, populate the account & populate the UI fields and validate it
if (result == AccountCheckSettingsFragment.AUTODISCOVER_OK) {
boolean valid = mFragment.setHostAuthFromAutodiscover(hostAuth);
if (valid) {
// "click" next to launch server verification
mFragment.onNext();
}
}
// Otherwise, proceed into this activity for manual setup
}
/**
* Implements AccountServerBaseFragment.Callback
*
@ -109,9 +190,13 @@ public class AccountSetupIncoming extends AccountSetupActivity
*/
public void onCheckSettingsComplete(int result, int setupMode) {
if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) {
AccountSetupOutgoing.actionOutgoingSettings(this, SetupData.getFlowMode(),
SetupData.getAccount());
finish();
if (mServiceInfo.usesSmtp) {
AccountSetupOutgoing.actionOutgoingSettings(this, SetupData.getFlowMode(),
SetupData.getAccount());
} else {
AccountSetupOptions.actionOptions(this);
finish();
}
}
}
}

View File

@ -37,6 +37,8 @@ import android.widget.TextView;
import com.android.email.R;
import com.android.email.activity.UiUtilities;
import com.android.email.provider.AccountBackupRestore;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.email2.ui.MailActivityEmail;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
@ -54,12 +56,6 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
private final static String STATE_KEY_CREDENTIAL = "AccountSetupIncomingFragment.credential";
private final static String STATE_KEY_LOADED = "AccountSetupIncomingFragment.loaded";
private static final int POP3_PORT_NORMAL = 110;
private static final int POP3_PORT_SSL = 995;
private static final int IMAP_PORT_NORMAL = 143;
private static final int IMAP_PORT_SSL = 993;
private EditText mUsernameView;
private EditText mPasswordView;
private TextView mServerLabelView;
@ -290,16 +286,13 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
}
TextView lastView = mImapPathPrefixView;
mBaseScheme = account.mHostAuthRecv.mProtocol;
mServerLabelView.setText(R.string.account_setup_incoming_server_label);
mServerView.setContentDescription(getResources().getText(
R.string.account_setup_incoming_server_label));
if (HostAuth.SCHEME_POP3.equals(mBaseScheme)) {
mServerLabelView.setText(R.string.account_setup_incoming_pop_server_label);
mServerView.setContentDescription(
getResources().getString(R.string.account_setup_incoming_pop_server_label));
mImapPathPrefixSectionView.setVisibility(View.GONE);
lastView = mPortView;
} else if (HostAuth.SCHEME_IMAP.equals(mBaseScheme)) {
mServerLabelView.setText(R.string.account_setup_incoming_imap_server_label);
mServerView.setContentDescription(
getResources().getString(R.string.account_setup_incoming_imap_server_label));
mDeletePolicyLabelView.setVisibility(View.GONE);
mDeletePolicyView.setVisibility(View.GONE);
mPortView.setImeOptions(EditorInfo.IME_ACTION_NEXT);
@ -390,10 +383,9 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
private int getPortFromSecurityType() {
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
boolean useSsl = ((securityType & HostAuth.FLAG_SSL) != 0);
int port = useSsl ? IMAP_PORT_SSL : IMAP_PORT_NORMAL; // default to IMAP
if (HostAuth.SCHEME_POP3.equals(mBaseScheme)) {
port = useSsl ? POP3_PORT_SSL : POP3_PORT_NORMAL;
}
EmailServiceInfo info = EmailServiceUtils.getServiceInfo(mContext,
SetupData.getAccount().mHostAuthRecv.mProtocol);
int port = useSsl ? info.portSsl : info.port;
return port;
}

View File

@ -39,20 +39,17 @@ import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.email.service.MailService;
import com.android.email2.ui.MailActivityEmail;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.service.SyncWindow;
import com.android.emailcommon.utility.Utility;
import java.io.IOException;
/**
* TODO: Cleanup the manipulation of Account.FLAGS_INCOMPLETE and make sure it's never left set.
*/
public class AccountSetupOptions extends AccountSetupActivity implements OnClickListener {
private Spinner mCheckFrequencyView;
@ -96,37 +93,26 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
UiUtilities.getView(this, R.id.next).setOnClickListener(this);
mAccountSyncWindowRow = UiUtilities.getView(this, R.id.account_sync_window_row);
// Generate spinner entries using XML arrays used by the preferences
int frequencyValuesId;
int frequencyEntriesId;
Account account = SetupData.getAccount();
String protocol = account.mHostAuthRecv.mProtocol;
boolean eas = HostAuth.SCHEME_EAS.equals(protocol);
if (eas) {
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);
EmailServiceInfo info = EmailServiceUtils.getServiceInfo(getApplicationContext(),
account.mHostAuthRecv.mProtocol);
CharSequence[] frequencyValues = info.syncIntervals;
CharSequence[] frequencyEntries = info.syncIntervalStrings;
// Now create the array used by the Spinner
// Now create the array used by the sync interval 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);
checkFrequenciesAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCheckFrequencyView.setAdapter(checkFrequenciesAdapter);
if (eas) {
enableEASSyncWindowSpinner();
if (info.lookback) {
enableLookbackSpinner();
}
// Note: It is OK to use mAccount.mIsDefault here *only* because the account
@ -138,20 +124,18 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
(account.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL) != 0);
SpinnerOption.setSpinnerOptionValue(mCheckFrequencyView, account.getSyncInterval());
// Setup any additional items to support EAS & EAS flow mode
if (eas) {
// "also sync contacts" == "true"
if (info.contacts) {
mSyncContactsView.setVisibility(View.VISIBLE);
mSyncContactsView.setChecked(true);
UiUtilities.setVisibilitySafe(this, R.id.account_sync_contacts_divider, View.VISIBLE);
}
if (info.calendar) {
mSyncCalendarView.setVisibility(View.VISIBLE);
mSyncCalendarView.setChecked(true);
// Show the associated dividers
UiUtilities.setVisibilitySafe(this, R.id.account_sync_contacts_divider, View.VISIBLE);
UiUtilities.setVisibilitySafe(this, R.id.account_sync_calendar_divider, View.VISIBLE);
}
// If we are in POP3, hide the "Background Attachments" mode
if (HostAuth.SCHEME_POP3.equals(protocol)) {
if (info.attachmentPreload) {
mBackgroundAttachmentsView.setVisibility(View.GONE);
UiUtilities.setVisibilitySafe(this, R.id.account_background_attachments_divider,
View.GONE);
@ -204,6 +188,7 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
* the account to the database (making it real for the first time.)
* Finally, we call setupAccountManagerAccount(), which will eventually complete via callback.
*/
@SuppressWarnings("deprecation")
private void onDone() {
final Account account = SetupData.getAccount();
if (account.isSaved()) {
@ -362,6 +347,7 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
* Enable exchange services
* Move to final setup screen
*/
@SuppressWarnings("deprecation")
private void saveAccountAndFinish() {
Utility.runAsync(new Runnable() {
@Override
@ -373,7 +359,7 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
AccountSettingsUtils.commitSettings(context, account);
// Start up services based on new account(s)
MailActivityEmail.setServicesEnabledSync(context);
EmailServiceUtils.startService(context, "eas");
EmailServiceUtils.startService(context, account.mHostAuthRecv.mProtocol);
// Move to final setup screen
AccountSetupNames.actionSetNames(context);
finish();
@ -384,7 +370,7 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick
/**
* Enable an additional spinner using the arrays normally handled by preferences
*/
private void enableEASSyncWindowSpinner() {
private void enableLookbackSpinner() {
// Show everything
mAccountSyncWindowRow.setVisibility(View.VISIBLE);

View File

@ -0,0 +1,112 @@
/*
* 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.setup;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.UiUtilities;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
/**
* Prompts the user to select an account type. The account type, along with the
* passed in email address, password and makeDefault are then passed on to the
* AccountSetupIncoming activity.
*/
public class AccountSetupType extends AccountSetupActivity implements OnClickListener {
public static void actionSelectAccountType(Activity fromActivity) {
Intent i = new ForwardingIntent(fromActivity, AccountSetupType.class);
fromActivity.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityHelper.debugSetWindowFlags(this);
int flowMode = SetupData.getFlowMode();
// If we're in account setup flow mode, for EAS, skip this screen and "click" EAS
if (flowMode == SetupData.FLOW_MODE_ACCOUNT_MANAGER_EAS) {
onSelect("eas");
return;
}
// Otherwise proceed into this screen
setContentView(R.layout.account_setup_account_type);
int i = 1;
for (EmailServiceInfo info: EmailServiceUtils.getServiceInfoList(this)) {
if (EmailServiceUtils.isServiceAvailable(this, info.protocol)) {
ViewGroup parent = UiUtilities.getView(this, R.id.accountTypes);
LinearLayout view = (LinearLayout)LayoutInflater.from(this)
.inflate(R.layout.account_type, parent);
Button button = (Button)view.getChildAt(i);
button.setTag(info.protocol);
button.setText(info.name);
button.setOnClickListener(this);
i++;
// TODO: Remember vendor overlay for exchange name
}
}
final Button previousButton = (Button) findViewById(R.id.previous); // xlarge only
if (previousButton != null) previousButton.setOnClickListener(this);
}
/**
* The user has selected an exchange account type. Set the mail delete policy here, because
* there is no UI (for exchange), and switch the default sync interval to "push".
*/
private void onSelect(String protocol) {
Account account = SetupData.getAccount();
HostAuth recvAuth = account.getOrCreateHostAuthRecv(this);
recvAuth.setConnection(protocol, recvAuth.mAddress, recvAuth.mPort, recvAuth.mFlags);
EmailServiceInfo info = EmailServiceUtils.getServiceInfo(this, protocol);
if (info.autodiscover) {
SetupData.setCheckSettingsMode(SetupData.CHECK_AUTODISCOVER);
} else {
SetupData.setCheckSettingsMode(
SetupData.CHECK_INCOMING | (info.usesSmtp ? SetupData.CHECK_OUTGOING : 0));
}
recvAuth.mLogin = recvAuth.mLogin + "@" + recvAuth.mAddress;
AccountSetupBasics.setFlagsForProtocol(account, protocol);
AccountSetupIncoming.actionIncomingSettings(this, SetupData.getFlowMode(), account);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
onSelect((String)v.getTag());
break;
case R.id.previous:
finish();
break;
}
}
}

View File

@ -20,9 +20,9 @@ import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import com.android.email.mail.store.ExchangeStore;
import com.android.email.mail.store.ImapStore;
import com.android.email.mail.store.Pop3Store;
import com.android.email.mail.store.ServiceStore;
import com.android.email2.ui.MailActivityEmail;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.Folder;
@ -58,7 +58,6 @@ public abstract class Store {
new HashMap<String, Class<? extends Store>>();
static {
sStoreClasses.put(HostAuth.SCHEME_EAS, ExchangeStore.class);
sStoreClasses.put(HostAuth.SCHEME_IMAP, ImapStore.class);
sStoreClasses.put(HostAuth.SCHEME_POP3, Pop3Store.class);
}
@ -94,6 +93,9 @@ public abstract class Store {
if (store == null) {
Context appContext = context.getApplicationContext();
Class<? extends Store> klass = sStoreClasses.get(hostAuth.mProtocol);
if (klass == null) {
klass = ServiceStore.class;
}
try {
// invoke "newInstance" class method
Method m = klass.getMethod("newInstance", Account.class, Context.class);
@ -126,15 +128,6 @@ public abstract class Store {
return sStores.remove(HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv));
}
/**
* Get class of SettingActivity for this Store class.
* @return Activity class that has class method actionEditIncomingSettings().
*/
public Class<? extends android.app.Activity> getSettingActivityClass() {
// default SettingActivity class
return com.android.email.activity.setup.AccountSetupIncoming.class;
}
/**
* Some protocols require that a sent message be copied (uploaded) into the Sent folder
* while others can take care of it automatically (ideally, on the server). This function

View File

@ -1,55 +0,0 @@
/*
* 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.store;
import android.content.Context;
import com.android.email.mail.Store;
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.service.IEmailService;
/**
* Our Exchange service does not use the sender/store model.
*/
public class ExchangeStore extends ServiceStore {
/**
* Static named constructor.
*/
public static Store newInstance(Account account, Context context) throws MessagingException {
return new ExchangeStore(account, context);
}
/**
* Creates a new store for the given account.
*/
public ExchangeStore(Account account, Context context) throws MessagingException {
super(account, context);
}
@Override
public Class<? extends android.app.Activity> getSettingActivityClass() {
return com.android.email.activity.setup.AccountSetupExchange.class;
}
@Override
protected IEmailService getService() {
return EmailServiceUtils.getService(mContext, null, "eas");
}
}

View File

@ -21,6 +21,7 @@ import android.os.Bundle;
import android.os.RemoteException;
import com.android.email.mail.Store;
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
@ -30,11 +31,9 @@ import com.android.emailcommon.service.IEmailService;
/**
* Base class for service-based stores
*/
public abstract class ServiceStore extends Store {
public class ServiceStore extends Store {
protected final HostAuth mHostAuth;
protected abstract IEmailService getService();
/**
* Creates a new store for the given account.
*/
@ -43,6 +42,17 @@ public abstract class ServiceStore extends Store {
mHostAuth = account.getOrCreateHostAuthRecv(mContext);
}
/**
* Static named constructor.
*/
public static Store newInstance(Account account, Context context) throws MessagingException {
return new ServiceStore(account, context);
}
private IEmailService getService() {
return EmailServiceUtils.getService(mContext, null, mHostAuth.mProtocol);
}
@Override
public Bundle checkSettings() throws MessagingException {
/**

View File

@ -19,6 +19,8 @@ package com.android.email.service;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import com.android.email.R;
@ -29,14 +31,15 @@ import com.android.emailcommon.service.IEmailServiceCallback;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
/**
* Utility functions for EmailService support.
*/
public class EmailServiceUtils {
private static final HashMap<String, EmailServiceInfo> sServiceMap =
new HashMap<String, EmailServiceInfo>();
private static final ArrayList<EmailServiceInfo> sServiceList =
new ArrayList<EmailServiceInfo>();
/**
* Starts an EmailService by protocol
@ -73,10 +76,25 @@ public class EmailServiceUtils {
* Holder of service information (currently just name and class/intent); if there is a class
* member, this is a (local, i.e. same process) service; otherwise, this is a remote service
*/
static class EmailServiceInfo {
String name;
public static class EmailServiceInfo {
public String protocol;
public String name;
public String accountType;
Class<? extends Service> klass;
String intentAction;
public int port;
public int portSsl;
public boolean preferSsl = false;
public boolean usesSmtp = true;
public boolean autodiscover = false;
public boolean push = false;
public boolean lookback = false;
public boolean contacts = false;
public boolean calendar = false;
public boolean attachmentPreload = true;
public int serverLabel;
public CharSequence[] syncIntervalStrings;
public CharSequence[] syncIntervals;
}
public static EmailServiceProxy getService(Context context, IEmailServiceCallback callback,
@ -89,11 +107,23 @@ public class EmailServiceUtils {
}
}
private static EmailServiceInfo getServiceInfo(Context context, String protocol) {
if (sServiceMap.isEmpty()) {
public static EmailServiceInfo getServiceInfo(Context context, String protocol) {
if (sServiceList.isEmpty()) {
findServices(context);
}
return sServiceMap.get(protocol);
for (EmailServiceInfo info: sServiceList) {
if (info.protocol.equals(protocol)) {
return info;
}
}
return null;
}
public static List<EmailServiceInfo> getServiceInfoList(Context context) {
if (sServiceList.isEmpty()) {
findServices(context);
}
return sServiceList;
}
/**
@ -102,24 +132,38 @@ public class EmailServiceUtils {
@SuppressWarnings("unchecked")
private static void findServices(Context context) {
try {
XmlResourceParser xml = context.getResources().getXml(R.xml.services);
Resources res = context.getResources();
XmlResourceParser xml = res.getXml(R.xml.services);
int xmlEventType;
// walk through senders.xml file.
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG &&
"service".equals(xml.getName())) {
"emailservice".equals(xml.getName())) {
EmailServiceInfo info = new EmailServiceInfo();
String protocol = xml.getAttributeValue(null, "protocol");
if (protocol == null) {
throw new IllegalStateException(
"No protocol specified in service descriptor");
}
info.name = xml.getAttributeValue(null, "name");
if (info.name == null) {
throw new IllegalStateException(
"No name specified in service descriptor");
}
String klass = xml.getAttributeValue(null, "class");
TypedArray ta = res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
info.name = ta.getString(R.styleable.EmailServiceInfo_name);
String klass = ta.getString(R.styleable.EmailServiceInfo_serviceClass);
info.intentAction = ta.getString(R.styleable.EmailServiceInfo_intent);
info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
info.preferSsl = ta.getBoolean(R.styleable.EmailServiceInfo_preferSsl, false);
info.port = ta.getInteger(R.styleable.EmailServiceInfo_port, 0);
info.portSsl = ta.getInteger(R.styleable.EmailServiceInfo_portSsl, 0);
info.usesSmtp = ta.getBoolean(R.styleable.EmailServiceInfo_usesSmtp, false);
info.autodiscover =
ta.getBoolean(R.styleable.EmailServiceInfo_autodiscover, false);
info.push = ta.getBoolean(R.styleable.EmailServiceInfo_push, false);
info.lookback = ta.getBoolean(R.styleable.EmailServiceInfo_lookback, false);
info.contacts = ta.getBoolean(R.styleable.EmailServiceInfo_contacts, false);
info.calendar = ta.getBoolean(R.styleable.EmailServiceInfo_calendar, false);
info.attachmentPreload =
ta.getBoolean(R.styleable.EmailServiceInfo_attachmentPreload, false);
info.syncIntervalStrings =
ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervalStrings);
info.syncIntervals =
ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervals);
// Must have either "class" (local) or "intent" (remote)
if (klass != null) {
try {
info.klass = (Class<? extends Service>) Class.forName(klass);
@ -128,8 +172,6 @@ public class EmailServiceUtils {
"Class not found in service descriptor: " + klass);
}
}
info.intentAction = xml.getAttributeValue(null, "intent");
if (info.klass == null && info.intentAction == null) {
throw new IllegalStateException(
"No class or intent action specified in service descriptor");
@ -138,7 +180,7 @@ public class EmailServiceUtils {
throw new IllegalStateException(
"Both class and intent action specified in service descriptor");
}
sServiceMap.put(protocol, info);
sServiceList.add(info);
}
}
} catch (XmlPullParserException e) {

View File

@ -1,106 +0,0 @@
/*
* 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.setup;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.test.ActivityUnitTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import com.android.email.R;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import java.net.URISyntaxException;
import java.util.HashSet;
/**
* This is a series of unit tests for the AccountSetupAccountType class.
* You can run this entire test case with:
* runtest -c com.android.email.activity.setup.AccountSetupAccountTypeTests email
*/
@SmallTest
public class AccountSetupAccountTypeTests
extends ActivityUnitTestCase<AccountSetupAccountType> {
Context mContext;
private HashSet<Account> mAccounts = new HashSet<Account>();
public AccountSetupAccountTypeTests() {
super(AccountSetupAccountType.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = this.getInstrumentation().getTargetContext();
}
/**
* Delete any dummy accounts we set up for this test
*/
@Override
protected void tearDown() throws Exception {
for (Account account : mAccounts) {
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account.mId);
mContext.getContentResolver().delete(uri, null, null);
}
// must call last because it scrubs member variables
super.tearDown();
}
/**
* Confirm that EAS is presented, when supported.
*/
public void testEasOffered() throws URISyntaxException {
createTestAccount("scheme1");
AccountSetupAccountType activity = startActivity(getTestIntent(), null, null);
View exchangeButton = activity.findViewById(R.id.exchange);
int expected = View.GONE; // Default is hidden
//EXCHANGE-REMOVE-SECTION-START
expected = View.VISIBLE; // Will be visible if supported.
//EXCHANGE-REMOVE-SECTION-END
assertEquals(expected, exchangeButton.getVisibility());
}
/**
* Create a dummy account with minimal fields
*/
private Account createTestAccount(String scheme) throws URISyntaxException {
Account account = new Account();
HostAuth auth = account.getOrCreateHostAuthRecv(mContext);
HostAuth.setHostAuthFromString(auth, scheme + "://user:pass@server.com:123");
account.save(mContext);
mAccounts.add(account);
SetupData.init(SetupData.FLOW_MODE_NORMAL, account);
return account;
}
/**
* Create an intent with the Account in it
*/
private Intent getTestIntent() {
return new Intent(Intent.ACTION_MAIN);
}
}