applied compromise code reformatting:

find  src/com/android/email/ -name \*java|xargs astyle --style=ansi \
    --mode=java  --indent-switches --indent=spaces=4 --convert-tabs \
    --unpad=paren
This commit is contained in:
Jesse Vincent 2009-11-25 00:40:29 +00:00
parent 04e8c6a55c
commit 9cac2cd5b7
87 changed files with 13278 additions and 8766 deletions

File diff suppressed because it is too large Load diff

View file

@ -20,18 +20,19 @@ import com.android.email.mail.internet.BinaryTempFileBody;
import com.android.email.service.BootReceiver;
import com.android.email.service.MailService;
public class Email extends Application {
public class Email extends Application
{
public static Application app = null;
public static File tempDirectory;
public static final String LOG_TAG = "k9";
public enum BACKGROUND_OPS
{
WHEN_CHECKED, ALWAYS, NEVER
WHEN_CHECKED, ALWAYS, NEVER
}
private static int theme = android.R.style.Theme_Light;
private static int theme = android.R.style.Theme_Light;
private static BACKGROUND_OPS backgroundOps = BACKGROUND_OPS.WHEN_CHECKED;
/**
* Some log messages can be sent to a file, so that the logs
@ -67,34 +68,39 @@ public class Email extends Application {
* item in the list. The entire list will be used to filter down attachments that are added
* with Intent.ACTION_SEND.
*/
public static final String[] ACCEPTABLE_ATTACHMENT_SEND_TYPES = new String[] {
public static final String[] ACCEPTABLE_ATTACHMENT_SEND_TYPES = new String[]
{
"*/*"
};
/**
* The MIME type(s) of attachments we're willing to view.
*/
public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
public static final String[] ACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[]
{
"*/*",
};
/**
* The MIME type(s) of attachments we're not willing to view.
*/
public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[] {
public static final String[] UNACCEPTABLE_ATTACHMENT_VIEW_TYPES = new String[]
{
};
/**
* The MIME type(s) of attachments we're willing to download to SD.
*/
public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[]
{
"*/*",
};
/**
* The MIME type(s) of attachments we're not willing to download to SD.
*/
public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[]
{
};
/**
@ -102,18 +108,18 @@ public class Email extends Application {
* the server refers to as the user's Inbox. Placed here to ease use.
*/
public static final String INBOX = "INBOX";
/**
* For use when displaying that no folder is selected
*/
public static final String FOLDER_NONE = "-NONE-";
public static final String LOCAL_UID_PREFIX = "K9LOCAL:";
public static final String REMOTE_UID_PREFIX = "K9REMOTE:";
public static final String K9MAIL_IDENTITY = "X-K9mail-Identity";
/**
* Specifies how many messages will be shown in a folder by default. This number is set
* on each new folder and can be incremented with "Load more messages..." by the
@ -125,7 +131,7 @@ public class Email extends Application {
* Number of additioanl messages to load when a user selectes "Load more messages..."
*/
public static int VISIBLE_LIMIT_INCREMENT = 25;
public static int MAX_SEND_ATTEMPTS = 5;
/**
@ -135,16 +141,16 @@ public class Email extends Application {
* 6.8MB downloaded but only 5MB saved.
*/
public static final int MAX_ATTACHMENT_DOWNLOAD_SIZE = (5 * 1024 * 1024);
/**
* Max time (in millis) the wake lock will be held for when background sync is happening
* Max time (in millis) the wake lock will be held for when background sync is happening
*/
public static final int WAKE_LOCK_TIMEOUT = 600000;
public static final int MANUAL_WAKE_LOCK_TIMEOUT = 120000;
public static final int PUSH_WAKE_LOCK_TIMEOUT = 60000;
public static final int MAIL_SERVICE_WAKE_LOCK_TIMEOUT = 30000;
public static final int BOOT_RECEIVER_WAKE_LOCK_TIMEOUT = 60000;
@ -158,38 +164,39 @@ public class Email extends Application {
/**
* Time the LED is on when blicking on new email notification
*/
public static final int NOTIFICATION_LED_ON_TIME = 500;
public static final int NOTIFICATION_LED_ON_TIME = 500;
/**
* Time the LED is off when blicking on new email notification
*/
public static final int NOTIFICATION_LED_OFF_TIME = 2000;
public static final boolean NOTIFICATION_LED_WHILE_SYNCING = false;
public static final int NOTIFICATION_LED_DIM_COLOR = 0x77770077;
public static final int NOTIFICATION_LED_FAST_ON_TIME = 100;
public static final int NOTIFICATION_LED_FAST_OFF_TIME = 100;
public static final int NOTIFICATION_LED_SENDING_FAILURE_COLOR = 0xffff0000;
// Must not conflict with an account number
public static final int FETCHING_EMAIL_NOTIFICATION_ID = -4;
public static final int FETCHING_EMAIL_NOTIFICATION_ID = -4;
public static final int FETCHING_EMAIL_NOTIFICATION_MULTI_ACCOUNT_ID = -1;
public static final int FETCHING_EMAIL_NOTIFICATION_NO_ACCOUNT = -2;
public static final int CONNECTIVITY_ID = -3;
// Backup formats in case they can't be fetched from the system
public static final String BACKUP_DATE_FORMAT = "MM-dd-yyyy";
public static final String TIME_FORMAT_12 = "h:mm a";
public static final String TIME_FORMAT_24 = "H:mm";
public static final int FLAGGED_COLOR = 0xff4444;
/*
* http://www.w3schools.com/media/media_mimeref.asp
* + png
*/
public static final String[][] CONTENT_TYPE_BY_EXTENSION_MAP = new String[][] {
public static final String[][] CONTENT_TYPE_BY_EXTENSION_MAP = new String[][]
{
{ "", "application/octet-stream" },
{ "323", "text/h323"},
{ "acx", "application/internet-property-stream"},
@ -381,9 +388,11 @@ public class Email extends Application {
{ "zip", "application/zip"}
};
public class Intents {
public class Intents
{
public class EmailReceived {
public class EmailReceived
{
public static final String ACTION_EMAIL_RECEIVED = "com.android.email.intent.action.EMAIL_RECEIVED";
public static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
public static final String EXTRA_FOLDER = "com.android.email.intent.extra.FOLDER";
@ -395,7 +404,7 @@ public class Email extends Application {
public static final String EXTRA_SUBJECT = "com.android.email.intent.extra.SUBJECT";
public static final String EXTRA_FROM_SELF = "com.android.email.intent.extra.FROM_SELF";
}
}
/**
@ -403,24 +412,28 @@ public class Email extends Application {
* enables or disables the Compose activity, the boot receiver and the service based on
* whether any accounts are configured.
*/
public static void setServicesEnabled(Context context) {
public static void setServicesEnabled(Context context)
{
int acctLength = Preferences.getPreferences(context).getAccounts().length;
setServicesEnabled(context, acctLength > 0, null);
}
public static void setServicesEnabled(Context context, Integer wakeLockId) {
public static void setServicesEnabled(Context context, Integer wakeLockId)
{
setServicesEnabled(context, Preferences.getPreferences(context).getAccounts().length > 0, wakeLockId);
}
public static void setServicesEnabled(Context context, boolean enabled, Integer wakeLockId) {
public static void setServicesEnabled(Context context, boolean enabled, Integer wakeLockId)
{
PackageManager pm = context.getPackageManager();
if (!enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
{
/*
* If no accounts now exist but the service is still enabled we're about to disable it
* so we'll reschedule to kill off any existing alarms.
@ -428,34 +441,35 @@ public class Email extends Application {
MailService.actionReschedule(context, wakeLockId);
}
Class[] classes = { MessageCompose.class, BootReceiver.class, MailService.class };
for (Class clazz : classes)
{
boolean alreadyEnabled = pm.getComponentEnabledSetting(new ComponentName(context, clazz)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
boolean alreadyEnabled = pm.getComponentEnabledSetting(new ComponentName(context, clazz)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
if (enabled != alreadyEnabled)
{
pm.setComponentEnabledSetting(
new ComponentName(context, clazz),
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
new ComponentName(context, clazz),
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
if (enabled && pm.getComponentEnabledSetting(new ComponentName(context, MailService.class)) ==
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
{
/*
* And now if accounts do exist then we've just enabled the service and we want to
* schedule alarms for the new accounts.
*/
MailService.actionReschedule(context, wakeLockId);
}
}
public static void save(SharedPreferences preferences)
{
SharedPreferences.Editor editor = preferences.edit();
@ -467,14 +481,15 @@ public class Email extends Application {
}
@Override
public void onCreate() {
public void onCreate()
{
super.onCreate();
app = this;
Preferences prefs = Preferences.getPreferences(this);
SharedPreferences sprefs = prefs.getPreferences();
DEBUG = sprefs.getBoolean("enableDebugLogging", false);
DEBUG_SENSITIVE = sprefs.getBoolean("enableSensitiveLogging", false);
try
{
setBackgroundOps(BACKGROUND_OPS.valueOf(sprefs.getString("backgroundOperations", "WHEN_CHECKED")));
@ -483,7 +498,7 @@ public class Email extends Application {
{
setBackgroundOps(BACKGROUND_OPS.WHEN_CHECKED);
}
Email.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts());
@ -493,16 +508,19 @@ public class Email extends Application {
*/
BinaryTempFileBody.setTempDirectory(getCacheDir());
/*
/*
* Enable background sync of messages
*/
setServicesEnabled(this);
MessagingController.getInstance(this).addListener(new MessagingListener() {
MessagingController.getInstance(this).addListener(new MessagingListener()
{
@Override
public void synchronizeMailboxNewMessage(Account account, String folder, Message message) {
try {
public void synchronizeMailboxNewMessage(Account account, String folder, Message message)
{
try
{
Uri uri = Uri.parse("email://messages/" + account.getAccountNumber() + "/" + Uri.encode(folder) + "/" + Uri.encode(message.getUid()));
Intent intent = new Intent(Email.Intents.EmailReceived.ACTION_EMAIL_RECEIVED, uri);
intent.putExtra(Email.Intents.EmailReceived.EXTRA_ACCOUNT, account.getDescription());
@ -517,7 +535,8 @@ public class Email extends Application {
Email.this.sendBroadcast(intent);
Log.d(Email.LOG_TAG, "Broadcasted intent: " + message.getSubject());
}
catch (MessagingException e) {
catch (MessagingException e)
{
Log.w(Email.LOG_TAG, "Account=" + account.getName() + " folder=" + folder + "message uid=" + message.getUid(), e);
}
}
@ -544,7 +563,7 @@ public class Email extends Application {
{
Email.backgroundOps = backgroundOps;
}
public static void setBackgroundOps(String nbackgroundOps)
{
Email.backgroundOps = BACKGROUND_OPS.valueOf(nbackgroundOps);

View file

@ -29,7 +29,8 @@ import android.widget.TextView;
import com.android.email.mail.Address;
public class EmailAddressAdapter extends ResourceCursorAdapter {
public class EmailAddressAdapter extends ResourceCursorAdapter
{
public static final int NAME_INDEX = 1;
public static final int DATA_INDEX = 2;
@ -38,20 +39,23 @@ public class EmailAddressAdapter extends ResourceCursorAdapter {
private ContentResolver mContentResolver;
private static final String[] PROJECTION = {
ContactMethods._ID, // 0
ContactMethods.NAME, // 1
ContactMethods.DATA
// 2
private static final String[] PROJECTION =
{
ContactMethods._ID, // 0
ContactMethods.NAME, // 1
ContactMethods.DATA
// 2
};
public EmailAddressAdapter(Context context) {
public EmailAddressAdapter(Context context)
{
super(context, R.layout.recipient_dropdown_item, null);
mContentResolver = context.getContentResolver();
}
@Override
public final String convertToString(Cursor cursor) {
public final String convertToString(Cursor cursor)
{
String name = cursor.getString(NAME_INDEX);
String address = cursor.getString(DATA_INDEX);
@ -59,7 +63,8 @@ public class EmailAddressAdapter extends ResourceCursorAdapter {
}
@Override
public final void bindView(View view, Context context, Cursor cursor) {
public final void bindView(View view, Context context, Cursor cursor)
{
TextView text1 = (TextView)view.findViewById(R.id.text1);
TextView text2 = (TextView)view.findViewById(R.id.text2);
text1.setText(cursor.getString(NAME_INDEX));
@ -67,10 +72,12 @@ public class EmailAddressAdapter extends ResourceCursorAdapter {
}
@Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
public Cursor runQueryOnBackgroundThread(CharSequence constraint)
{
String where = null;
if (constraint != null) {
if (constraint != null)
{
String filter = DatabaseUtils.sqlEscapeString(constraint.toString() + '%');
StringBuilder s = new StringBuilder();

View file

@ -5,12 +5,15 @@ import android.text.util.Rfc822Tokenizer;
import android.widget.AutoCompleteTextView.Validator;
public class EmailAddressValidator implements Validator {
public CharSequence fixText(CharSequence invalidText) {
public class EmailAddressValidator implements Validator
{
public CharSequence fixText(CharSequence invalidText)
{
return "";
}
public boolean isValid(CharSequence text) {
public boolean isValid(CharSequence text)
{
return Rfc822Tokenizer.tokenize(text).length > 0;
}
}

View file

@ -1,6 +1,7 @@
package com.android.email;
public class EmailReceivedIntent {
public class EmailReceivedIntent
{
public static final String ACTION_EMAIL_RECEIVED = "com.android.email.intent.action.EMAIL_RECEIVED";
public static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";

View file

@ -7,54 +7,70 @@ import java.io.InputStream;
/**
* A filtering InputStream that stops allowing reads after the given length has been read. This
* is used to allow a client to read directly from an underlying protocol stream without reading
* past where the protocol handler intended the client to read.
* past where the protocol handler intended the client to read.
*/
public class FixedLengthInputStream extends InputStream {
public class FixedLengthInputStream extends InputStream
{
private InputStream mIn;
private int mLength;
private int mCount;
public FixedLengthInputStream(InputStream in, int length) {
public FixedLengthInputStream(InputStream in, int length)
{
this.mIn = in;
this.mLength = length;
}
@Override
public int available() throws IOException {
public int available() throws IOException
{
return mLength - mCount;
}
@Override
public int read() throws IOException {
if (mCount < mLength) {
public int read() throws IOException
{
if (mCount < mLength)
{
mCount++;
return mIn.read();
} else {
}
else
{
return -1;
}
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if (mCount < mLength) {
public int read(byte[] b, int offset, int length) throws IOException
{
if (mCount < mLength)
{
int d = mIn.read(b, offset, Math.min(mLength - mCount, length));
if (d == -1) {
if (d == -1)
{
return -1;
} else {
}
else
{
mCount += d;
return d;
}
} else {
}
else
{
return -1;
}
}
@Override
public int read(byte[] b) throws IOException {
public int read(byte[] b) throws IOException
{
return read(b, 0, b.length);
}
public String toString() {
public String toString()
{
return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength);
}
}

View file

@ -5,9 +5,11 @@ import android.app.Activity;
import android.os.Bundle;
public class K9Activity extends Activity {
public class K9Activity extends Activity
{
@Override
public void onCreate(Bundle icicle) {
public void onCreate(Bundle icicle)
{
setTheme(Email.getK9Theme());
super.onCreate(icicle);
}

View file

@ -4,9 +4,11 @@ import android.app.ListActivity;
import android.os.Bundle;
public class K9ListActivity extends ListActivity {
public class K9ListActivity extends ListActivity
{
@Override
public void onCreate(Bundle icicle) {
public void onCreate(Bundle icicle)
{
setTheme(Email.getK9Theme());
super.onCreate(icicle);
}

View file

@ -5,9 +5,11 @@ import android.os.Bundle;
public class K9PreferenceActivity extends PreferenceActivity {
public class K9PreferenceActivity extends PreferenceActivity
{
@Override
public void onCreate(Bundle icicle) {
public void onCreate(Bundle icicle)
{
setTheme(Email.getK9Theme());
super.onCreate(icicle);
}

View file

@ -7,8 +7,10 @@
package com.android.email;
public final class Manifest {
public static final class permission {
public final class Manifest
{
public static final class permission
{
public static final String READ_ATTACHMENT="com.android.email.permission.READ_ATTACHMENT";
}
}

File diff suppressed because it is too large Load diff

View file

@ -16,146 +16,179 @@ import com.android.email.mail.Part;
* this interface use the @Override annotation in their implementations to avoid being caught by
* changes in this class.
*/
public class MessagingListener {
public void accountStatusChanged(Account account, int unreadMessageCount) {
public class MessagingListener
{
public void accountStatusChanged(Account account, int unreadMessageCount)
{
}
public void accountSizeChanged(Account account, long oldSize, long newSize)
{
}
public void listFoldersStarted(Account account) {
public void listFoldersStarted(Account account)
{
}
public void listFolders(Account account, Folder[] folders) {
public void listFolders(Account account, Folder[] folders)
{
}
public void listFoldersFailed(Account account, String message) {
public void listFoldersFailed(Account account, String message)
{
}
public void listFoldersFinished(Account account) {
public void listFoldersFinished(Account account)
{
}
public void listLocalMessagesStarted(Account account, String folder) {
public void listLocalMessagesStarted(Account account, String folder)
{
}
public void listLocalMessages(Account account, String folder, Message[] messages) {
}
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
public void listLocalMessages(Account account, String folder, Message[] messages)
{
}
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages)
{
}
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message) {
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message)
{
}
public void listLocalMessagesFailed(Account account, String folder, String message) {
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message)
{
}
public void listLocalMessagesFinished(Account account, String folder) {
public void listLocalMessagesFailed(Account account, String folder, String message)
{
}
public void synchronizeMailboxStarted(Account account, String folder) {
public void listLocalMessagesFinished(Account account, String folder)
{
}
public void synchronizeMailboxNewMessage(Account account, String folder, Message message) {
public void synchronizeMailboxStarted(Account account, String folder)
{
}
public void synchronizeMailboxAddOrUpdateMessage(Account account, String folder, Message message) {
public void synchronizeMailboxNewMessage(Account account, String folder, Message message)
{
}
public void synchronizeMailboxRemovedMessage(Account account, String folder,Message message) {
public void synchronizeMailboxAddOrUpdateMessage(Account account, String folder, Message message)
{
}
public void synchronizeMailboxRemovedMessage(Account account, String folder,Message message)
{
}
public void synchronizeMailboxFinished(Account account, String folder,
int totalMessagesInMailbox, int numNewMessages) {
int totalMessagesInMailbox, int numNewMessages)
{
}
public void synchronizeMailboxFailed(Account account, String folder,
String message) {
String message)
{
}
public void loadMessageForViewStarted(Account account, String folder, String uid) {
public void loadMessageForViewStarted(Account account, String folder, String uid)
{
}
public void loadMessageForViewHeadersAvailable(Account account, String folder, String uid,
Message message) {
Message message)
{
}
public void loadMessageForViewBodyAvailable(Account account, String folder, String uid,
Message message) {
Message message)
{
}
public void loadMessageForViewFinished(Account account, String folder, String uid,
Message message) {
Message message)
{
}
public void loadMessageForViewFailed(Account account, String folder, String uid, Throwable t) {
public void loadMessageForViewFailed(Account account, String folder, String uid, Throwable t)
{
}
public void checkMailStarted(Context context, Account account) {
public void checkMailStarted(Context context, Account account)
{
}
public void checkMailFinished(Context context, Account account) {
}
public void checkMailFailed(Context context, Account account, String reason) {
public void checkMailFinished(Context context, Account account)
{
}
public void sendPendingMessagesStarted(Account account) {
public void checkMailFailed(Context context, Account account, String reason)
{
}
public void sendPendingMessagesCompleted(Account account) {
public void sendPendingMessagesStarted(Account account)
{
}
public void sendPendingMessagesFailed(Account account) {
public void sendPendingMessagesCompleted(Account account)
{
}
public void sendPendingMessagesFailed(Account account)
{
}
public void messageDeleted(Account account, String folder, Message message)
{
}
public void emptyTrashCompleted(Account account) {
}
public void folderStatusChanged(Account account, String folderName) {
}
public void messageUidChanged(Account account, String folder, String oldUid, String newUid) {
}
public void emptyTrashCompleted(Account account)
{
}
public void folderStatusChanged(Account account, String folderName)
{
}
public void messageUidChanged(Account account, String folder, String oldUid, String newUid)
{
}
public void setPushActive(Account account, String folderName, boolean enabled)
{
}
public void loadAttachmentStarted(
Account account,
Message message,
Part part,
Object tag,
boolean requiresDownload)
Account account,
Message message,
Part part,
Object tag,
boolean requiresDownload)
{
}
public void loadAttachmentFinished(
Account account,
Message message,
Part part,
Object tag)
Account account,
Message message,
Part part,
Object tag)
{
}
public void loadAttachmentFailed(
Account account,
Message message,
Part part,
Object tag,
String reason)
Account account,
Message message,
Part part,
Object tag,
String reason)
{
}
@ -166,7 +199,8 @@ public class MessagingListener {
* @param moreCommandsToRun True if the controller will continue on to another command
* immediately.
*/
public void controllerCommandCompleted(boolean moreCommandsToRun) {
public void controllerCommandCompleted(boolean moreCommandsToRun)
{
}
}

View file

@ -7,29 +7,37 @@ import java.io.InputStream;
/**
* A filtering InputStream that allows single byte "peeks" without consuming the byte. The
* client of this stream can call peek() to see the next available byte in the stream
* and a subsequent read will still return the peeked byte.
* and a subsequent read will still return the peeked byte.
*/
public class PeekableInputStream extends InputStream {
public class PeekableInputStream extends InputStream
{
private InputStream mIn;
private boolean mPeeked;
private int mPeekedByte;
public PeekableInputStream(InputStream in) {
public PeekableInputStream(InputStream in)
{
this.mIn = in;
}
@Override
public int read() throws IOException {
if (!mPeeked) {
public int read() throws IOException
{
if (!mPeeked)
{
return mIn.read();
} else {
}
else
{
mPeeked = false;
return mPeekedByte;
}
}
public int peek() throws IOException {
if (!mPeeked) {
public int peek() throws IOException
{
if (!mPeeked)
{
mPeekedByte = read();
mPeeked = true;
}
@ -37,28 +45,37 @@ public class PeekableInputStream extends InputStream {
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if (!mPeeked) {
public int read(byte[] b, int offset, int length) throws IOException
{
if (!mPeeked)
{
return mIn.read(b, offset, length);
} else {
}
else
{
b[0] = (byte)mPeekedByte;
mPeeked = false;
int r = mIn.read(b, offset + 1, length - 1);
if (r == -1) {
if (r == -1)
{
return 1;
} else {
}
else
{
return r + 1;
}
}
}
@Override
public int read(byte[] b) throws IOException {
public int read(byte[] b) throws IOException
{
return read(b, 0, b.length);
}
public String toString() {
public String toString()
{
return String.format("PeekableInputStream(in=%s, peeked=%b, peekedByte=%d)",
mIn.toString(), mPeeked, mPeekedByte);
mIn.toString(), mPeeked, mPeekedByte);
}
}

View file

@ -10,22 +10,24 @@ import android.net.Uri;
import android.util.Config;
import android.util.Log;
public class Preferences {
public class Preferences
{
private static Preferences preferences;
private Storage mStorage;
private Preferences(Context context) {
mStorage = Storage.getStorage(context);
if (mStorage.size() == 0)
{
Log.i(Email.LOG_TAG, "Preferences storage is zero-size, importing from Android-style preferences");
Editor editor = mStorage.edit();
editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE));
editor.commit();
}
private Preferences(Context context)
{
mStorage = Storage.getStorage(context);
if (mStorage.size() == 0)
{
Log.i(Email.LOG_TAG, "Preferences storage is zero-size, importing from Android-style preferences");
Editor editor = mStorage.edit();
editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE));
editor.commit();
}
}
/**
* TODO need to think about what happens if this gets GCed along with the
@ -35,8 +37,10 @@ public class Preferences {
*
* @return
*/
public static synchronized Preferences getPreferences(Context context) {
if (preferences == null) {
public static synchronized Preferences getPreferences(Context context)
{
if (preferences == null)
{
preferences = new Preferences(context);
}
return preferences;
@ -48,20 +52,24 @@ public class Preferences {
*
* @return
*/
public Account[] getAccounts() {
public Account[] getAccounts()
{
String accountUuids = getPreferences().getString("accountUuids", null);
if (accountUuids == null || accountUuids.length() == 0) {
if (accountUuids == null || accountUuids.length() == 0)
{
return new Account[] {};
}
String[] uuids = accountUuids.split(",");
Account[] accounts = new Account[uuids.length];
for (int i = 0, length = uuids.length; i < length; i++) {
for (int i = 0, length = uuids.length; i < length; i++)
{
accounts[i] = new Account(this, uuids[i]);
}
return accounts;
}
public Account getAccountByContentUri(Uri uri) {
public Account getAccountByContentUri(Uri uri)
{
return new Account(this, uri.getPath().substring(1));
}
@ -72,21 +80,27 @@ public class Preferences {
*
* @return
*/
public Account getDefaultAccount() {
public Account getDefaultAccount()
{
String defaultAccountUuid = getPreferences().getString("defaultAccountUuid", null);
Account defaultAccount = null;
Account[] accounts = getAccounts();
if (defaultAccountUuid != null) {
for (Account account : accounts) {
if (account.getUuid().equals(defaultAccountUuid)) {
if (defaultAccountUuid != null)
{
for (Account account : accounts)
{
if (account.getUuid().equals(defaultAccountUuid))
{
defaultAccount = account;
break;
}
}
}
if (defaultAccount == null) {
if (accounts.length > 0) {
if (defaultAccount == null)
{
if (accounts.length > 0)
{
defaultAccount = accounts[0];
setDefaultAccount(defaultAccount);
}
@ -95,13 +109,17 @@ public class Preferences {
return defaultAccount;
}
public void setDefaultAccount(Account account) {
public void setDefaultAccount(Account account)
{
getPreferences().edit().putString("defaultAccountUuid", account.getUuid()).commit();
}
public void dump() {
if (Config.LOGV) {
for (String key : getPreferences().getAll().keySet()) {
public void dump()
{
if (Config.LOGV)
{
for (String key : getPreferences().getAll().keySet())
{
Log.v(Email.LOG_TAG, key + " = " + getPreferences().getAll().get(key));
}
}
@ -109,6 +127,6 @@ public class Preferences {
public SharedPreferences getPreferences()
{
return mStorage;
return mStorage;
}
}

View file

@ -13,21 +13,27 @@ import android.text.Editable;
import android.widget.EditText;
import android.widget.TextView;
public class Utility {
public final static String readInputStream(InputStream in, String encoding) throws IOException {
public class Utility
{
public final static String readInputStream(InputStream in, String encoding) throws IOException
{
InputStreamReader reader = new InputStreamReader(in, encoding);
StringBuffer sb = new StringBuffer();
int count;
char[] buf = new char[512];
while ((count = reader.read(buf)) != -1) {
while ((count = reader.read(buf)) != -1)
{
sb.append(buf, 0, count);
}
return sb.toString();
}
public final static boolean arrayContains(Object[] a, Object o) {
for (int i = 0, count = a.length; i < count; i++) {
if (a[i].equals(o)) {
public final static boolean arrayContains(Object[] a, Object o)
{
for (int i = 0, count = a.length; i < count; i++)
{
if (a[i].equals(o))
{
return true;
}
}
@ -43,55 +49,70 @@ public class Utility {
* @param seperator
* @return
*/
public static String combine(Object[] parts, char seperator) {
if (parts == null) {
public static String combine(Object[] parts, char seperator)
{
if (parts == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < parts.length; i++) {
for (int i = 0; i < parts.length; i++)
{
sb.append(parts[i].toString());
if (i < parts.length - 1) {
if (i < parts.length - 1)
{
sb.append(seperator);
}
}
return sb.toString();
}
public static String base64Decode(String encoded) {
if (encoded == null) {
public static String base64Decode(String encoded)
{
if (encoded == null)
{
return null;
}
byte[] decoded = new Base64().decode(encoded.getBytes());
return new String(decoded);
}
public static String base64Encode(String s) {
if (s == null) {
public static String base64Encode(String s)
{
if (s == null)
{
return s;
}
byte[] encoded = new Base64().encode(s.getBytes());
return new String(encoded);
}
public static boolean requiredFieldValid(TextView view) {
public static boolean requiredFieldValid(TextView view)
{
return view.getText() != null && view.getText().length() > 0;
}
public static boolean requiredFieldValid(Editable s) {
public static boolean requiredFieldValid(Editable s)
{
return s != null && s.length() > 0;
}
public static boolean domainFieldValid(EditText view) {
if (view.getText() != null) {
public static boolean domainFieldValid(EditText view)
{
if (view.getText() != null)
{
String s = view.getText().toString();
if (s.matches("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$")) {
if (s.matches("^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"))
{
return true;
}
if (s.matches("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")) {
if (s.matches("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"))
{
return true;
}
if ((s.equalsIgnoreCase("localhost"))||(s.equalsIgnoreCase("localhost.localdomain"))) {
if ((s.equalsIgnoreCase("localhost"))||(s.equalsIgnoreCase("localhost.localdomain")))
{
return true;
}
}
@ -112,14 +133,18 @@ public class Utility {
* @param s
* @return
*/
public static String quoteString(String s) {
if (s == null) {
public static String quoteString(String s)
{
if (s == null)
{
return null;
}
if (!s.matches("^\".*\"$")) {
if (!s.matches("^\".*\"$"))
{
return "\"" + s + "\"";
}
else {
else
{
return s;
}
}
@ -129,36 +154,45 @@ public class Utility {
* allocations. This version is around 3x as fast as the standard one and I'm using it
* hundreds of times in places that slow down the UI, so it helps.
*/
public static String fastUrlDecode(String s) {
try {
public static String fastUrlDecode(String s)
{
try
{
byte[] bytes = s.getBytes("UTF-8");
byte ch;
int length = 0;
for (int i = 0, count = bytes.length; i < count; i++) {
for (int i = 0, count = bytes.length; i < count; i++)
{
ch = bytes[i];
if (ch == '%') {
if (ch == '%')
{
int h = (bytes[i + 1] - '0');
int l = (bytes[i + 2] - '0');
if (h > 9) {
if (h > 9)
{
h -= 7;
}
if (l > 9) {
if (l > 9)
{
l -= 7;
}
bytes[length] = (byte) ((h << 4) | l);
bytes[length] = (byte)((h << 4) | l);
i += 2;
}
else if (ch == '+') {
else if (ch == '+')
{
bytes[length] = ' ';
}
else {
else
{
bytes[length] = bytes[i];
}
length++;
}
return new String(bytes, 0, length, "UTF-8");
}
catch (UnsupportedEncodingException uee) {
catch (UnsupportedEncodingException uee)
{
return null;
}
}
@ -168,11 +202,15 @@ public class Utility {
* @param date
* @return
*/
public static boolean isDateToday(Date date) {
public static boolean isDateToday(Date date)
{
Date now = new Date();
if (now.getTime() - 64800000 > date.getTime() || now.getTime() + 64800000 < date.getTime()) {
if (now.getTime() - 64800000 > date.getTime() || now.getTime() + 64800000 < date.getTime())
{
return false;
} else {
}
else
{
return true;
}
}
@ -181,7 +219,8 @@ public class Utility {
* TODO disabled this method globally. It is used in all the settings screens but I just
* noticed that an unrelated icon was dimmed. Android must share drawables internally.
*/
public static void setCompoundDrawablesAlpha(TextView view, int alpha) {
public static void setCompoundDrawablesAlpha(TextView view, int alpha)
{
// Drawable[] drawables = view.getCompoundDrawables();
// for (Drawable drawable : drawables) {
// if (drawable != null) {

View file

@ -53,7 +53,8 @@ import com.android.email.mail.Store;
import com.android.email.mail.store.LocalStore;
import com.android.email.mail.store.LocalStore.LocalFolder;
public class Accounts extends K9ListActivity implements OnItemClickListener, OnClickListener {
public class Accounts extends K9ListActivity implements OnItemClickListener, OnClickListener
{
private static final int DIALOG_REMOVE_ACCOUNT = 1;
private ConcurrentHashMap<String, Integer> unreadMessageCounts = new ConcurrentHashMap<String, Integer>();
@ -64,13 +65,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
private AccountsHandler mHandler = new AccountsHandler();
private AccountsAdapter mAdapter;
private class AccountSizeChangedHolder {
private class AccountSizeChangedHolder
{
Account account;
long oldSize;
long newSize;
}
class AccountsHandler extends Handler {
class AccountsHandler extends Handler
{
private static final int DATA_CHANGED = 1;
private static final int MSG_ACCOUNT_SIZE_CHANGED = 2;
private static final int MSG_WORKING_ACCOUNT = 3;
@ -78,62 +81,71 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
private static final int MSG_FOLDER_SYNCING = 5;
private static final int MSG_DEFINITE_PROGRESS = 6;
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case DATA_CHANGED:
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
break;
case MSG_WORKING_ACCOUNT: {
Account account = (Account)msg.obj;
int res = msg.arg1;
String toastText = getString(res, account.getDescription());
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case DATA_CHANGED:
if (mAdapter != null)
{
mAdapter.notifyDataSetChanged();
}
break;
case MSG_WORKING_ACCOUNT:
{
Account account = (Account)msg.obj;
int res = msg.arg1;
String toastText = getString(res, account.getDescription());
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT);
toast.show();
break;
}
case MSG_ACCOUNT_SIZE_CHANGED: {
AccountSizeChangedHolder holder = (AccountSizeChangedHolder)msg.obj;
Account account = holder.account;
Long oldSize = holder.oldSize;
Long newSize = holder.newSize;
String toastText = getString(R.string.account_size_changed, account.getDescription(),
SizeFormatter.formatSize(getApplication(), oldSize), SizeFormatter.formatSize(getApplication(), newSize));;
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_LONG);
toast.show();
break;
}
case MSG_FOLDER_SYNCING: {
String folderName = (String) ((Object[]) msg.obj)[0];
String dispString;
dispString = getString(R.string.accounts_title);
if (folderName != null) {
dispString += " (" + getString(R.string.status_loading)
+ folderName + ")";
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT);
toast.show();
break;
}
setTitle(dispString);
break;
}
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
//setProgressBarVisibility(msg.arg1 != 0);
break;
case MSG_DEFINITE_PROGRESS:
getWindow().setFeatureInt(Window.FEATURE_PROGRESS, msg.arg1);
break;
default:
super.handleMessage(msg);
case MSG_ACCOUNT_SIZE_CHANGED:
{
AccountSizeChangedHolder holder = (AccountSizeChangedHolder)msg.obj;
Account account = holder.account;
Long oldSize = holder.oldSize;
Long newSize = holder.newSize;
String toastText = getString(R.string.account_size_changed, account.getDescription(),
SizeFormatter.formatSize(getApplication(), oldSize), SizeFormatter.formatSize(getApplication(), newSize));;
Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_LONG);
toast.show();
break;
}
case MSG_FOLDER_SYNCING:
{
String folderName = (String)((Object[]) msg.obj)[0];
String dispString;
dispString = getString(R.string.accounts_title);
if (folderName != null)
{
dispString += " (" + getString(R.string.status_loading)
+ folderName + ")";
}
setTitle(dispString);
break;
}
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
//setProgressBarVisibility(msg.arg1 != 0);
break;
case MSG_DEFINITE_PROGRESS:
getWindow().setFeatureInt(Window.FEATURE_PROGRESS, msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
public void dataChanged() {
public void dataChanged()
{
sendEmptyMessage(DATA_CHANGED);
}
public void workingAccount(Account account, int res) {
public void workingAccount(Account account, int res)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_WORKING_ACCOUNT;
msg.obj = account;
@ -142,7 +154,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
sendMessage(msg);
}
public void accountSizeChanged(Account account, long oldSize, long newSize) {
public void accountSizeChanged(Account account, long oldSize, long newSize)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_ACCOUNT_SIZE_CHANGED;
AccountSizeChangedHolder holder = new AccountSizeChangedHolder();
@ -153,19 +166,22 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
sendMessage(msg);
}
public void progress(boolean progress) {
public void progress(boolean progress)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_PROGRESS;
msg.arg1 = progress ? 1 : 0;
sendMessage(msg);
}
public void progress(int progress) {
public void progress(int progress)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_DEFINITE_PROGRESS;
msg.arg1 = progress ;
sendMessage(msg);
}
public void folderSyncing(String folder) {
public void folderSyncing(String folder)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_FOLDER_SYNCING;
msg.obj = new String[] { folder };
@ -174,24 +190,30 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
MessagingListener mListener = new MessagingListener() {
MessagingListener mListener = new MessagingListener()
{
@Override
public void accountStatusChanged(Account account, int unreadMessageCount) {
public void accountStatusChanged(Account account, int unreadMessageCount)
{
unreadMessageCounts.put(account.getUuid(), unreadMessageCount);
mHandler.dataChanged();
pendingWork.remove(account);
if (pendingWork.isEmpty()) {
if (pendingWork.isEmpty())
{
mHandler.progress(Window.PROGRESS_END);
} else {
}
else
{
int level = (Window.PROGRESS_END / mAdapter.getCount()) * (mAdapter.getCount() - pendingWork.size()) ;
mHandler.progress(level);
}
}
@Override
public void accountSizeChanged(Account account, long oldSize, long newSize) {
public void accountSizeChanged(Account account, long oldSize, long newSize)
{
mHandler.accountSizeChanged(account, oldSize, newSize);
@ -202,7 +224,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
Account account,
String folder,
int totalMessagesInMailbox,
int numNewMessages) {
int numNewMessages)
{
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
mHandler.progress(false);
@ -210,7 +233,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
@Override
public void synchronizeMailboxStarted(Account account, String folder) {
public void synchronizeMailboxStarted(Account account, String folder)
{
mHandler.progress(true);
mHandler.folderSyncing(account.getDescription()
+ getString(R.string.notification_bg_title_separator) + folder);
@ -218,7 +242,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
@Override
public void synchronizeMailboxFailed(Account account, String folder,
String message) {
String message)
{
mHandler.progress(false);
mHandler.folderSyncing(null);
}
@ -231,13 +256,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
public static final String EXTRA_STARTUP = "startup";
public static void actionLaunch(Context context) {
public static void actionLaunch(Context context)
{
Intent intent = new Intent(context, Accounts.class);
intent.putExtra(EXTRA_STARTUP, true);
context.startActivity(intent);
}
public static void listAccounts(Context context) {
public static void listAccounts(Context context)
{
Intent intent = new Intent(context, Accounts.class);
intent.putExtra(EXTRA_STARTUP, false);
context.startActivity(intent);
@ -245,16 +272,20 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
@Override
public void onCreate(Bundle icicle) {
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
Account[] accounts = Preferences.getPreferences(this).getAccounts();
Intent intent = getIntent();
boolean startup = (boolean)intent.getBooleanExtra(EXTRA_STARTUP, false);
if (startup && accounts.length == 1) {
if (startup && accounts.length == 1)
{
FolderList.actionHandleAccount(this, accounts[0], accounts[0].getAutoExpandFolderName());
finish();
} else {
}
else
{
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);
@ -266,13 +297,16 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
findViewById(R.id.next).setOnClickListener(this);
registerForContextMenu(listView);
if (icicle != null && icicle.containsKey(SELECTED_CONTEXT_ACCOUNT)) {
if (icicle != null && icicle.containsKey(SELECTED_CONTEXT_ACCOUNT))
{
mSelectedContextAccount = (Account) icicle.getSerializable("selectedContextAccount");
}
if (icicle != null) {
if (icicle != null)
{
Map<String, Integer> oldUnreadMessageCounts = (Map<String, Integer>)icicle.get(UNREAD_MESSAGE_COUNTS);
if (oldUnreadMessageCounts != null) {
if (oldUnreadMessageCounts != null)
{
unreadMessageCounts.putAll(oldUnreadMessageCounts);
}
}
@ -280,16 +314,19 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (mSelectedContextAccount != null) {
if (mSelectedContextAccount != null)
{
outState.putSerializable(SELECTED_CONTEXT_ACCOUNT, mSelectedContextAccount);
}
outState.putSerializable(UNREAD_MESSAGE_COUNTS, unreadMessageCounts);
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
refresh();
@ -297,108 +334,136 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
@Override
public void onPause() {
public void onPause()
{
super.onPause();
MessagingController.getInstance(getApplication()).removeListener(mListener);
}
private void refresh() {
private void refresh()
{
Account[] accounts = Preferences.getPreferences(this).getAccounts();
mAdapter = new AccountsAdapter(accounts);
getListView().setAdapter(mAdapter);
if (accounts.length > 0) {
if (accounts.length > 0)
{
mHandler.progress(Window.PROGRESS_START);
}
pendingWork.clear();
for (Account account : accounts) {
for (Account account : accounts)
{
pendingWork.put(account, "true");
MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener);
}
}
private void onAddNewAccount() {
private void onAddNewAccount()
{
AccountSetupBasics.actionNewAccount(this);
}
private void onEditAccount(Account account) {
private void onEditAccount(Account account)
{
AccountSettings.actionSettings(this, account);
}
private void onEditPrefs() {
private void onEditPrefs()
{
Prefs.actionPrefs(this);
}
private void onCheckMail(Account account) {
private void onCheckMail(Account account)
{
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, null);
}
private void onClearCommands(Account account) {
private void onClearCommands(Account account)
{
MessagingController.getInstance(getApplication()).clearAllPending(account);
}
private void onEmptyTrash(Account account) {
private void onEmptyTrash(Account account)
{
MessagingController.getInstance(getApplication()).emptyTrash(account, null);
}
private void onCompose() {
private void onCompose()
{
Account defaultAccount = Preferences.getPreferences(this).getDefaultAccount();
if (defaultAccount != null) {
if (defaultAccount != null)
{
MessageCompose.actionCompose(this, defaultAccount);
} else {
}
else
{
onAddNewAccount();
}
}
private void onOpenAccount(Account account) {
private void onOpenAccount(Account account)
{
FolderList.actionHandleAccount(this, account, true);
}
public void onClick(View view) {
if (view.getId() == R.id.next) {
public void onClick(View view)
{
if (view.getId() == R.id.next)
{
onAddNewAccount();
}
}
private void onDeleteAccount(Account account) {
private void onDeleteAccount(Account account)
{
mSelectedContextAccount = account;
showDialog(DIALOG_REMOVE_ACCOUNT);
}
@Override
public Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_REMOVE_ACCOUNT:
return createRemoveAccountDialog();
public Dialog onCreateDialog(int id)
{
switch (id)
{
case DIALOG_REMOVE_ACCOUNT:
return createRemoveAccountDialog();
}
return super.onCreateDialog(id);
}
public void onPrepareDialog(int id, Dialog d) {
switch (id) {
case DIALOG_REMOVE_ACCOUNT:
AlertDialog alert = (AlertDialog) d;
alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
mSelectedContextAccount.getDescription()));
break;
public void onPrepareDialog(int id, Dialog d)
{
switch (id)
{
case DIALOG_REMOVE_ACCOUNT:
AlertDialog alert = (AlertDialog) d;
alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
mSelectedContextAccount.getDescription()));
break;
}
super.onPrepareDialog(id, d);
}
private Dialog createRemoveAccountDialog() {
private Dialog createRemoveAccountDialog()
{
return new AlertDialog.Builder(this)
.setTitle(R.string.account_delete_dlg_title)
.setMessage(getString(R.string.account_delete_dlg_instructions_fmt, mSelectedContextAccount.getDescription()))
.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
dismissDialog(DIALOG_REMOVE_ACCOUNT);
try {
((LocalStore)Store.getInstance( mSelectedContextAccount.getLocalStoreUri(), getApplication())).delete();
} catch (Exception e) {
try
{
((LocalStore)Store.getInstance(mSelectedContextAccount.getLocalStoreUri(), getApplication())).delete();
}
catch (Exception e)
{
// Ignore
}
mSelectedContextAccount.delete(Preferences.getPreferences(Accounts.this));
@ -406,90 +471,100 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
refresh();
}
})
.setNegativeButton(R.string.cancel_action, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
.setNegativeButton(R.string.cancel_action, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
dismissDialog(DIALOG_REMOVE_ACCOUNT);
}
})
.create();
}
public boolean onContextItemSelected(MenuItem item) {
public boolean onContextItemSelected(MenuItem item)
{
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo();
Account account = (Account)getListView().getItemAtPosition(menuInfo.position);
switch (item.getItemId()) {
case R.id.edit_prefs:
onEditPrefs();
break;
case R.id.delete_account:
onDeleteAccount(account);
break;
case R.id.edit_account:
onEditAccount(account);
break;
case R.id.open:
onOpenAccount(account);
break;
case R.id.check_mail:
onCheckMail(account);
break;
case R.id.clear_pending:
onClearCommands(account);
break;
case R.id.empty_trash:
onEmptyTrash(account);
break;
case R.id.compact:
onCompact(account);
break;
case R.id.clear:
onClear(account);
break;
switch (item.getItemId())
{
case R.id.edit_prefs:
onEditPrefs();
break;
case R.id.delete_account:
onDeleteAccount(account);
break;
case R.id.edit_account:
onEditAccount(account);
break;
case R.id.open:
onOpenAccount(account);
break;
case R.id.check_mail:
onCheckMail(account);
break;
case R.id.clear_pending:
onClearCommands(account);
break;
case R.id.empty_trash:
onEmptyTrash(account);
break;
case R.id.compact:
onCompact(account);
break;
case R.id.clear:
onClear(account);
break;
}
return true;
}
private void onCompact(Account account) {
private void onCompact(Account account)
{
mHandler.workingAccount(account, R.string.compacting_account);
MessagingController.getInstance(getApplication()).compact(account, null);
}
private void onClear(Account account) {
private void onClear(Account account)
{
mHandler.workingAccount(account, R.string.clearing_account);
MessagingController.getInstance(getApplication()).clear(account, null);
}
public void onItemClick(AdapterView parent, View view, int position, long id) {
public void onItemClick(AdapterView parent, View view, int position, long id)
{
Account account = (Account)parent.getItemAtPosition(position);
onOpenAccount(account);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_new_account:
onAddNewAccount();
break;
case R.id.edit_prefs:
onEditPrefs();
break;
case R.id.check_mail:
onCheckMail(null);
break;
case R.id.compose:
onCompose();
break;
case R.id.about:
onAbout();
break;
default:
return super.onOptionsItemSelected(item);
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.add_new_account:
onAddNewAccount();
break;
case R.id.edit_prefs:
onEditPrefs();
break;
case R.id.check_mail:
onCheckMail(null);
break;
case R.id.compose:
onCompose();
break;
case R.id.about:
onAbout();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
private void onAbout() {
private void onAbout()
{
String appName = getString(R.string.app_name);
WebView wv = new WebView(this);
String html = "<h1>" + String.format(getString(R.string.about_title_fmt).toString(),
@ -506,8 +581,10 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
new AlertDialog.Builder(this)
.setView(wv)
.setCancelable(true)
.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener () {
public void onClick(DialogInterface d, int c) {
.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface d, int c)
{
d.dismiss();
}
})
@ -519,57 +596,72 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
*
* @return String version
*/
private String getVersionNumber() {
private String getVersionNumber()
{
String version = "?";
try {
try
{
PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
version = pi.versionName;
} catch (PackageManager.NameNotFoundException e) {
}
catch (PackageManager.NameNotFoundException e)
{
//Log.e(TAG, "Package name not found", e);
};
return version;
}
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.accounts_option, menu);
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.accounts_context_menu_title);
getMenuInflater().inflate(R.menu.accounts_context, menu);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
return super.onKeyDown(keyCode, event);
}
class AccountsAdapter extends ArrayAdapter<Account> {
public AccountsAdapter(Account[] accounts) {
class AccountsAdapter extends ArrayAdapter<Account>
{
public AccountsAdapter(Account[] accounts)
{
super(Accounts.this, 0, accounts);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(int position, View convertView, ViewGroup parent)
{
Account account = getItem(position);
View view;
if (convertView != null) {
if (convertView != null)
{
view = convertView;
} else {
}
else
{
view = getLayoutInflater().inflate(R.layout.accounts_item, parent, false);
}
AccountViewHolder holder = (AccountViewHolder) view.getTag();
if (holder == null) {
if (holder == null)
{
holder = new AccountViewHolder();
holder.description = (TextView) view.findViewById(R.id.description);
holder.email = (TextView) view.findViewById(R.id.email);
@ -578,15 +670,19 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
}
holder.description.setText(account.getDescription());
holder.email.setText(account.getEmail());
if (account.getEmail().equals(account.getDescription())) {
if (account.getEmail().equals(account.getDescription()))
{
holder.email.setVisibility(View.GONE);
}
Integer unreadMessageCount = unreadMessageCounts.get(account.getUuid());
if (unreadMessageCount != null) {
if (unreadMessageCount != null)
{
holder.newMessageCount.setText(Integer.toString(unreadMessageCount));
holder.newMessageCount.setVisibility(unreadMessageCount > 0 ? View.VISIBLE : View.GONE);
} else {
}
else
{
//holder.newMessageCount.setText("-");
holder.newMessageCount.setVisibility(View.GONE);
}
@ -594,7 +690,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
return view;
}
class AccountViewHolder {
class AccountViewHolder
{
public TextView description;
public TextView email;
public TextView newMessageCount;

View file

@ -27,7 +27,8 @@ import com.android.email.R;
import com.android.email.mail.Folder;
import com.android.email.mail.MessagingException;
public class ChooseFolder extends K9ListActivity {
public class ChooseFolder extends K9ListActivity
{
String mFolder;
Account mAccount;
String mUID;
@ -47,7 +48,8 @@ public class ChooseFolder extends K9ListActivity {
public static final String EXTRA_SHOW_DISPLAYABLE_ONLY = "com.android.email.ChooseFolder_showDisplayableOnly";
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
@ -59,13 +61,16 @@ public class ChooseFolder extends K9ListActivity {
mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT);
mUID = intent.getStringExtra(EXTRA_MESSAGE_UID);
mFolder = intent.getStringExtra(EXTRA_CUR_FOLDER);
if (intent.getStringExtra(EXTRA_SHOW_CURRENT) != null) {
if (intent.getStringExtra(EXTRA_SHOW_CURRENT) != null)
{
hideCurrentFolder = false;
}
if (intent.getStringExtra(EXTRA_SHOW_FOLDER_NONE) != null) {
if (intent.getStringExtra(EXTRA_SHOW_FOLDER_NONE) != null)
{
showOptionNone = true;
}
if (intent.getStringExtra(EXTRA_SHOW_DISPLAYABLE_ONLY) != null) {
if (intent.getStringExtra(EXTRA_SHOW_DISPLAYABLE_ONLY) != null)
{
showDisplayableOnly = true;
}
if (mFolder == null)
@ -80,12 +85,15 @@ public class ChooseFolder extends K9ListActivity {
false, mListener);
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterview, View view, int i, long l) {
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView adapterview, View view, int i, long l)
{
Intent intent = new Intent();
intent.putExtra(EXTRA_CUR_FOLDER, mFolder);
String destFolderName = (String)((TextView)view).getText();
if (heldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
if (heldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName))
{
destFolderName = heldInbox;
}
intent.putExtra(EXTRA_NEW_FOLDER, destFolderName);
@ -97,93 +105,114 @@ public class ChooseFolder extends K9ListActivity {
}
class ChooseFolderHandler extends Handler {
class ChooseFolderHandler extends Handler
{
private static final int MSG_PROGRESS = 2;
private static final int MSG_DATA_CHANGED = 3;
private static final int MSG_SET_SELECTED_FOLDER = 4;
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
adapter.notifyDataSetChanged();
break;
case MSG_SET_SELECTED_FOLDER:
// TODO: I want this to highlight the chosen folder, but this doesn't work.
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
adapter.notifyDataSetChanged();
break;
case MSG_SET_SELECTED_FOLDER:
// TODO: I want this to highlight the chosen folder, but this doesn't work.
// getListView().setSelection(msg.arg1);
// getListView().setItemChecked(msg.arg1, true);
break;
break;
}
}
public void progress(boolean progress) {
public void progress(boolean progress)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_PROGRESS;
msg.arg1 = progress ? 1 : 0;
sendMessage(msg);
}
public void setSelectedFolder(int position) {
public void setSelectedFolder(int position)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_SET_SELECTED_FOLDER;
msg.arg1 = position;
sendMessage(msg);
}
public void dataChanged() {
public void dataChanged()
{
sendEmptyMessage(MSG_DATA_CHANGED);
}
}
private MessagingListener mListener = new MessagingListener() {
public void listFoldersStarted(Account account) {
if (!account.equals(mAccount)) {
private MessagingListener mListener = new MessagingListener()
{
public void listFoldersStarted(Account account)
{
if (!account.equals(mAccount))
{
return;
}
mHandler.progress(true);
}
@Override
public void listFoldersFailed(Account account, String message) {
if (!account.equals(mAccount)) {
public void listFoldersFailed(Account account, String message)
{
if (!account.equals(mAccount))
{
return;
}
mHandler.progress(false);
}
@Override
public void listFoldersFinished(Account account) {
if (!account.equals(mAccount)) {
public void listFoldersFinished(Account account)
{
if (!account.equals(mAccount))
{
return;
}
mHandler.progress(false);
}
@Override
public void listFolders(Account account, Folder[] folders) {
if (!account.equals(mAccount)) {
public void listFolders(Account account, Folder[] folders)
{
if (!account.equals(mAccount))
{
return;
}
Account.FolderMode aMode = Account.FolderMode.ALL;
if (showDisplayableOnly) {
if (showDisplayableOnly)
{
aMode = account.getFolderDisplayMode();
} else {
}
else
{
aMode = account.getFolderTargetMode();
}
Preferences prefs = Preferences.getPreferences(getApplication().getApplicationContext());
ArrayList<String> localFolders = new ArrayList<String>();
for (Folder folder : folders) {
for (Folder folder : folders)
{
String name = folder.getName();
// Inbox needs to be compared case-insensitively
if (hideCurrentFolder && (name.equals(mFolder) || (Email.INBOX.equalsIgnoreCase(mFolder) && Email.INBOX.equalsIgnoreCase(name)))) {
if (hideCurrentFolder && (name.equals(mFolder) || (Email.INBOX.equalsIgnoreCase(mFolder) && Email.INBOX.equalsIgnoreCase(name))))
{
continue;
}
try {
try
{
folder.refresh(prefs);
Folder.FolderClass fMode = folder.getDisplayClass();
@ -191,10 +220,13 @@ public class ChooseFolder extends K9ListActivity {
|| (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS &&
fMode != Folder.FolderClass.SECOND_CLASS)
|| (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
|| (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS))
{
continue;
}
} catch (MessagingException me) {
}
catch (MessagingException me)
{
Log.e(Email.LOG_TAG, "Couldn't get prefs to check for displayability of folder " + folder.getName(), me);
}
@ -202,22 +234,29 @@ public class ChooseFolder extends K9ListActivity {
}
if (showOptionNone) {
if (showOptionNone)
{
localFolders.add(Email.FOLDER_NONE);
}
Collections.sort(localFolders, new Comparator<String>() {
public int compare(String aName, String bName) {
if (Email.FOLDER_NONE.equalsIgnoreCase(aName)) {
Collections.sort(localFolders, new Comparator<String>()
{
public int compare(String aName, String bName)
{
if (Email.FOLDER_NONE.equalsIgnoreCase(aName))
{
return -1;
}
if (Email.FOLDER_NONE.equalsIgnoreCase(bName)) {
if (Email.FOLDER_NONE.equalsIgnoreCase(bName))
{
return 1;
}
if (Email.INBOX.equalsIgnoreCase(aName)) {
if (Email.INBOX.equalsIgnoreCase(aName))
{
return -1;
}
if (Email.INBOX.equalsIgnoreCase(bName)) {
if (Email.INBOX.equalsIgnoreCase(bName))
{
return 1;
}
@ -228,20 +267,26 @@ public class ChooseFolder extends K9ListActivity {
adapter.clear();
int selectedFolder = -1;
int position = 0;
for (String name : localFolders) {
if (Email.INBOX.equalsIgnoreCase(name)) {
for (String name : localFolders)
{
if (Email.INBOX.equalsIgnoreCase(name))
{
adapter.add(getString(R.string.special_mailbox_name_inbox));
heldInbox = name;
} else {
}
else
{
adapter.add(name);
}
if ((name.equals(mFolder) || (Email.INBOX.equalsIgnoreCase(mFolder) && Email.INBOX.equalsIgnoreCase(name)))) {
if ((name.equals(mFolder) || (Email.INBOX.equalsIgnoreCase(mFolder) && Email.INBOX.equalsIgnoreCase(name))))
{
selectedFolder = position;
}
position++;
}
if (selectedFolder != -1) {
if (selectedFolder != -1)
{
mHandler.setSelectedFolder(selectedFolder);
}
mHandler.dataChanged();

View file

@ -19,7 +19,8 @@ import com.android.email.K9ListActivity;
import com.android.email.Preferences;
import com.android.email.R;
public class ChooseIdentity extends K9ListActivity {
public class ChooseIdentity extends K9ListActivity
{
Account mAccount;
String mUID;
ArrayAdapter<String> adapter;
@ -31,7 +32,8 @@ public class ChooseIdentity extends K9ListActivity {
protected List<Account.Identity> identities = null;
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
@ -50,20 +52,24 @@ public class ChooseIdentity extends K9ListActivity {
@Override
public void onResume() {
public void onResume()
{
super.onResume();
refreshView();
}
protected void refreshView() {
protected void refreshView()
{
adapter.clear();
identities = mAccount.getIdentities();
for (Account.Identity identity : identities) {
for (Account.Identity identity : identities)
{
String email = identity.getEmail();
String description = identity.getDescription();
if (description == null || description.trim().length() == 0) {
if (description == null || description.trim().length() == 0)
{
description = getString(R.string.message_view_from_format, identity.getName(), identity.getEmail());
}
adapter.add(description);
@ -71,18 +77,24 @@ public class ChooseIdentity extends K9ListActivity {
}
protected void setupClickListeners() {
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterview, View view, int i, long l) {
protected void setupClickListeners()
{
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView adapterview, View view, int i, long l)
{
Account.Identity identity = mAccount.getIdentity(i);
String email = identity.getEmail();
if (email != null && email.trim().equals("") == false) {
if (email != null && email.trim().equals("") == false)
{
Intent intent = new Intent();
intent.putExtra(EXTRA_IDENTITY, mAccount.getIdentity(i));
setResult(RESULT_OK, intent);
finish();
} else {
}
else
{
Toast.makeText(ChooseIdentity.this, getString(R.string.identity_has_no_email),
Toast.LENGTH_LONG).show();
}
@ -91,30 +103,35 @@ public class ChooseIdentity extends K9ListActivity {
}
class ChooseIdentityHandler extends Handler {
class ChooseIdentityHandler extends Handler
{
private static final int MSG_PROGRESS = 2;
private static final int MSG_DATA_CHANGED = 3;
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
adapter.notifyDataSetChanged();
break;
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
adapter.notifyDataSetChanged();
break;
}
}
public void progress(boolean progress) {
public void progress(boolean progress)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_PROGRESS;
msg.arg1 = progress ? 1 : 0;
sendMessage(msg);
}
public void dataChanged() {
public void dataChanged()
{
sendEmptyMessage(MSG_DATA_CHANGED);
}
}

View file

@ -13,7 +13,8 @@ import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.EditText;
public class EditIdentity extends K9Activity {
public class EditIdentity extends K9Activity
{
public static final String EXTRA_IDENTITY = "com.android.email.EditIdentity_identity";
public static final String EXTRA_IDENTITY_INDEX = "com.android.email.EditIdentity_identity_index";
@ -29,14 +30,16 @@ public class EditIdentity extends K9Activity {
private EditText mNameView;
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mIdentity = (Account.Identity)getIntent().getSerializableExtra(EXTRA_IDENTITY);
mIdentityIndex = getIntent().getIntExtra(EXTRA_IDENTITY_INDEX, -1);
mAccount = (Account) getIntent().getSerializableExtra(EXTRA_ACCOUNT);
if (mIdentityIndex == -1) {
if (mIdentityIndex == -1)
{
mIdentity = mAccount.new Identity();
}
@ -46,7 +49,8 @@ public class EditIdentity extends K9Activity {
* If we're being reloaded we override the original account with the one
* we saved
*/
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_IDENTITY)) {
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_IDENTITY))
{
mIdentity = (Account.Identity)savedInstanceState.getSerializable(EXTRA_IDENTITY);
}
@ -67,11 +71,13 @@ public class EditIdentity extends K9Activity {
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
}
private void saveIdentity() {
private void saveIdentity()
{
mIdentity.setDescription(mDescriptionView.getText().toString());
mIdentity.setEmail(mEmailView.getText().toString());
@ -80,9 +86,12 @@ public class EditIdentity extends K9Activity {
mIdentity.setSignature(mSignatureView.getText().toString());
List<Account.Identity> identities = mAccount.getIdentities();
if (mIdentityIndex == -1) {
if (mIdentityIndex == -1)
{
identities.add(mIdentity);
} else {
}
else
{
identities.remove(mIdentityIndex);
identities.add(mIdentityIndex, mIdentity);
}
@ -93,8 +102,10 @@ public class EditIdentity extends K9Activity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveIdentity();
return true;
}
@ -102,7 +113,8 @@ public class EditIdentity extends K9Activity {
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_IDENTITY, mIdentity);
}

File diff suppressed because it is too large Load diff

View file

@ -16,14 +16,18 @@ import com.android.email.Account;
import com.android.email.Preferences;
import com.android.email.R;
public class ManageIdentities extends ChooseIdentity {
public class ManageIdentities extends ChooseIdentity
{
private boolean mIdentitiesChanged = false;
public static final String EXTRA_IDENTITIES = "com.android.email.EditIdentity_identities";
private static final int ACTIVITY_EDIT_IDENTITY = 1;
protected void setupClickListeners() {
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterview, View view, int i, long l) {
protected void setupClickListeners()
{
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView adapterview, View view, int i, long l)
{
editItem(i);
}
});
@ -32,7 +36,8 @@ public class ManageIdentities extends ChooseIdentity {
registerForContextMenu(listView);
}
private void editItem(int i) {
private void editItem(int i)
{
Intent intent = new Intent(ManageIdentities.this, EditIdentity.class);
intent.putExtra(EditIdentity.EXTRA_ACCOUNT, mAccount);
@ -42,80 +47,92 @@ public class ManageIdentities extends ChooseIdentity {
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.manage_identities_option, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.new_identity:
Intent intent = new Intent(ManageIdentities.this, EditIdentity.class);
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.new_identity:
Intent intent = new Intent(ManageIdentities.this, EditIdentity.class);
intent.putExtra(EditIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_EDIT_IDENTITY);
break;
default:
return super.onOptionsItemSelected(item);
intent.putExtra(EditIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_EDIT_IDENTITY);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.manage_identities_context_menu_title);
getMenuInflater().inflate(R.menu.manage_identities_context, menu);
}
public boolean onContextItemSelected(MenuItem item) {
public boolean onContextItemSelected(MenuItem item)
{
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo();
switch (item.getItemId()) {
case R.id.edit:
editItem(menuInfo.position);
break;
case R.id.up:
if (menuInfo.position > 0) {
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position - 1, identity);
mIdentitiesChanged = true;
refreshView();
}
switch (item.getItemId())
{
case R.id.edit:
editItem(menuInfo.position);
break;
case R.id.up:
if (menuInfo.position > 0)
{
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position - 1, identity);
mIdentitiesChanged = true;
refreshView();
}
break;
case R.id.down:
if (menuInfo.position < identities.size() - 1) {
break;
case R.id.down:
if (menuInfo.position < identities.size() - 1)
{
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position + 1, identity);
mIdentitiesChanged = true;
refreshView();
}
break;
case R.id.top:
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position + 1, identity);
identities.add(0, identity);
mIdentitiesChanged = true;
refreshView();
}
break;
case R.id.top:
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(0, identity);
mIdentitiesChanged = true;
refreshView();
break;
case R.id.remove:
if (identities.size() > 1) {
identities.remove(menuInfo.position);
mIdentitiesChanged = true;
refreshView();
} else {
Toast.makeText(this, getString(R.string.no_removable_identity),
Toast.LENGTH_LONG).show();
}
break;
break;
case R.id.remove:
if (identities.size() > 1)
{
identities.remove(menuInfo.position);
mIdentitiesChanged = true;
refreshView();
}
else
{
Toast.makeText(this, getString(R.string.no_removable_identity),
Toast.LENGTH_LONG).show();
}
break;
}
return true;
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
mAccount.refresh(Preferences.getPreferences(getApplication().getApplicationContext()));
refreshView();
@ -123,15 +140,19 @@ public class ManageIdentities extends ChooseIdentity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveIdentities();
}
return super.onKeyDown(keyCode, event);
}
private void saveIdentities() {
if (mIdentitiesChanged) {
private void saveIdentities()
{
if (mIdentitiesChanged)
{
mAccount.setIdentities(identities);
mAccount.save(Preferences.getPreferences(getApplication().getApplicationContext()));
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,8 @@ import android.content.Context;
/**
* A listener that the user can register for global, persistent progress events.
*/
public interface ProgressListener {
public interface ProgressListener
{
/**
* @param context
* @param title

View file

@ -4,15 +4,20 @@ import android.content.Context;
import com.android.email.R;
public class SizeFormatter {
public static String formatSize(Context context, long size) {
if (size > 1024000000) {
public class SizeFormatter
{
public static String formatSize(Context context, long size)
{
if (size > 1024000000)
{
return ((float)(size / 102400000) / 10) + context.getString(R.string.abbrev_gigabytes);
}
if (size > 1024000) {
if (size > 1024000)
{
return ((float)(size / 102400) / 10) + context.getString(R.string.abbrev_megabytes);
}
if (size > 1024) {
if (size > 1024)
{
return ((float)(size / 102) / 10) + context.getString(R.string.abbrev_kilobytes);
}
return size + context.getString(R.string.abbrev_bytes);

View file

@ -18,9 +18,11 @@ import android.os.Bundle;
* If more than one account is configuref the user is takaen to the Accounts Activity so they
* can select an account.
*/
public class Welcome extends K9Activity {
public class Welcome extends K9Activity
{
@Override
public void onCreate(Bundle icicle) {
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
Accounts.actionLaunch(this);

View file

@ -28,7 +28,8 @@ import com.android.email.activity.ChooseIdentity;
import com.android.email.activity.ManageIdentities;
import com.android.email.mail.Store;
public class AccountSettings extends K9PreferenceActivity {
public class AccountSettings extends K9PreferenceActivity
{
private static final String EXTRA_ACCOUNT = "account";
private static final int SELECT_AUTO_EXPAND_FOLDER = 1;
@ -76,24 +77,29 @@ public class AccountSettings extends K9PreferenceActivity {
private ListPreference mDeletePolicy;
private Preference mAutoExpandFolder;
public static void actionSettings(Context context, Account account) {
public static void actionSettings(Context context, Account account)
{
Intent i = new Intent(context, AccountSettings.class);
i.putExtra(EXTRA_ACCOUNT, account);
context.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
boolean isPushCapable = false;
Store store = null;
try {
try
{
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
isPushCapable = store.isPushCapable();
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
}
@ -105,8 +111,10 @@ public class AccountSettings extends K9PreferenceActivity {
mAccountDescription = (EditTextPreference) findPreference(PREFERENCE_DESCRIPTION);
mAccountDescription.setSummary(mAccount.getDescription());
mAccountDescription.setText(mAccount.getDescription());
mAccountDescription.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mAccountDescription.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
mAccountDescription.setSummary(summary);
mAccountDescription.setText(summary);
@ -118,8 +126,10 @@ public class AccountSettings extends K9PreferenceActivity {
mCheckFrequency = (ListPreference) findPreference(PREFERENCE_FREQUENCY);
mCheckFrequency.setValue(String.valueOf(mAccount.getAutomaticCheckIntervalMinutes()));
mCheckFrequency.setSummary(mCheckFrequency.getEntry());
mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mCheckFrequency.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mCheckFrequency.findIndexOfValue(summary);
mCheckFrequency.setSummary(mCheckFrequency.getEntries()[index]);
@ -131,8 +141,10 @@ public class AccountSettings extends K9PreferenceActivity {
mDisplayMode = (ListPreference) findPreference(PREFERENCE_DISPLAY_MODE);
mDisplayMode.setValue(mAccount.getFolderDisplayMode().name());
mDisplayMode.setSummary(mDisplayMode.getEntry());
mDisplayMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mDisplayMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mDisplayMode.findIndexOfValue(summary);
mDisplayMode.setSummary(mDisplayMode.getEntries()[index]);
@ -144,8 +156,10 @@ public class AccountSettings extends K9PreferenceActivity {
mSyncMode = (ListPreference) findPreference(PREFERENCE_SYNC_MODE);
mSyncMode.setValue(mAccount.getFolderSyncMode().name());
mSyncMode.setSummary(mSyncMode.getEntry());
mSyncMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSyncMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mSyncMode.findIndexOfValue(summary);
mSyncMode.setSummary(mSyncMode.getEntries()[index]);
@ -158,8 +172,10 @@ public class AccountSettings extends K9PreferenceActivity {
mPushMode.setEnabled(isPushCapable);
mPushMode.setValue(mAccount.getFolderPushMode().name());
mPushMode.setSummary(mPushMode.getEntry());
mPushMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mPushMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mPushMode.findIndexOfValue(summary);
mPushMode.setSummary(mPushMode.getEntries()[index]);
@ -171,8 +187,10 @@ public class AccountSettings extends K9PreferenceActivity {
mTargetMode = (ListPreference) findPreference(PREFERENCE_TARGET_MODE);
mTargetMode.setValue(mAccount.getFolderTargetMode().name());
mTargetMode.setSummary(mTargetMode.getEntry());
mTargetMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mTargetMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mTargetMode.findIndexOfValue(summary);
mTargetMode.setSummary(mTargetMode.getEntries()[index]);
@ -184,8 +202,10 @@ public class AccountSettings extends K9PreferenceActivity {
mDeletePolicy = (ListPreference) findPreference(PREFERENCE_DELETE_POLICY);
mDeletePolicy.setValue("" + mAccount.getDeletePolicy());
mDeletePolicy.setSummary(mDeletePolicy.getEntry());
mDeletePolicy.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mDeletePolicy.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mDeletePolicy.findIndexOfValue(summary);
mDeletePolicy.setSummary(mDeletePolicy.getEntries()[index]);
@ -197,8 +217,10 @@ public class AccountSettings extends K9PreferenceActivity {
mDisplayCount = (ListPreference) findPreference(PREFERENCE_DISPLAY_COUNT);
mDisplayCount.setValue(String.valueOf(mAccount.getDisplayCount()));
mDisplayCount.setSummary(mDisplayCount.getEntry());
mDisplayCount.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mDisplayCount.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mDisplayCount.findIndexOfValue(summary);
mDisplayCount.setSummary(mDisplayCount.getEntries()[index]);
@ -214,8 +236,10 @@ public class AccountSettings extends K9PreferenceActivity {
mAccountHideButtons = (ListPreference) findPreference(PREFERENCE_HIDE_BUTTONS);
mAccountHideButtons.setValue("" + mAccount.getHideMessageViewButtons());
mAccountHideButtons.setSummary(mAccountHideButtons.getEntry());
mAccountHideButtons.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mAccountHideButtons.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mAccountHideButtons.findIndexOfValue(summary);
mAccountHideButtons.setSummary(mAccountHideButtons.getEntries()[index]);
@ -226,7 +250,7 @@ public class AccountSettings extends K9PreferenceActivity {
mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
mAccountNotify.setChecked(mAccount.isNotifyNewMail());
mAccountNotifySelf = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY_SELF);
mAccountNotifySelf.setChecked(mAccount.isNotifySelfNewMail());
@ -248,40 +272,50 @@ public class AccountSettings extends K9PreferenceActivity {
mAutoExpandFolder.setSummary(translateFolder(mAccount.getAutoExpandFolderName()));
mAutoExpandFolder.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
new Preference.OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
onChooseAutoExpandFolder();
return false;
}
});
findPreference(PREFERENCE_COMPOSITION).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
new Preference.OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
onCompositionSettings();
return true;
}
});
findPreference(PREFERENCE_MANAGE_IDENTITIES).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
new Preference.OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
onManageIdentities();
return true;
}
});
findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
new Preference.OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
onIncomingSettings();
return true;
}
});
findPreference(PREFERENCE_OUTGOING).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
new Preference.OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
onOutgoingSettings();
return true;
}
@ -289,13 +323,16 @@ public class AccountSettings extends K9PreferenceActivity {
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
mAccount.refresh(Preferences.getPreferences(this));
}
private void saveSettings() {
if (mAccountDefault.isChecked()) {
private void saveSettings()
{
if (mAccountDefault.isChecked())
{
Preferences.getPreferences(this).setDefaultAccount(mAccount);
}
mAccount.setDescription(mAccountDescription.getText());
@ -320,44 +357,54 @@ public class AccountSettings extends K9PreferenceActivity {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case SELECT_AUTO_EXPAND_FOLDER:
mAutoExpandFolder.setSummary(translateFolder(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER)));
break;
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
switch (requestCode)
{
case SELECT_AUTO_EXPAND_FOLDER:
mAutoExpandFolder.setSummary(translateFolder(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER)));
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveSettings();
}
return super.onKeyDown(keyCode, event);
}
private void onCompositionSettings() {
private void onCompositionSettings()
{
AccountSetupComposition.actionEditCompositionSettings(this, mAccount);
}
private void onManageIdentities() {
private void onManageIdentities()
{
Intent intent = new Intent(this, ManageIdentities.class);
intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_MANAGE_IDENTITIES);
}
private void onIncomingSettings() {
private void onIncomingSettings()
{
AccountSetupIncoming.actionEditIncomingSettings(this, mAccount);
}
private void onOutgoingSettings() {
private void onOutgoingSettings()
{
AccountSetupOutgoing.actionEditOutgoingSettings(this, mAccount);
}
public void onChooseAutoExpandFolder() {
public void onChooseAutoExpandFolder()
{
Intent selectIntent = new Intent(this, ChooseFolder.class);
selectIntent.putExtra(ChooseFolder.EXTRA_ACCOUNT, mAccount);
@ -369,20 +416,28 @@ public class AccountSettings extends K9PreferenceActivity {
}
private String translateFolder(String in) {
private String translateFolder(String in)
{
if (Email.INBOX.equalsIgnoreCase(in)) {
if (Email.INBOX.equalsIgnoreCase(in))
{
return getString(R.string.special_mailbox_name_inbox);
} else {
}
else
{
return in;
}
}
private String reverseTranslateFolder(String in) {
private String reverseTranslateFolder(String in)
{
if (getString(R.string.special_mailbox_name_inbox).equals(in)) {
if (getString(R.string.special_mailbox_name_inbox).equals(in))
{
return Email.INBOX;
} else {
}
else
{
return in;
}
}

View file

@ -24,7 +24,8 @@ import com.android.email.activity.SizeFormatter;
* passed in email address, password and makeDefault are then passed on to the
* AccountSetupIncoming activity.
*/
public class AccountSetupAccountType extends K9Activity implements OnClickListener {
public class AccountSetupAccountType extends K9Activity implements OnClickListener
{
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
@ -33,7 +34,8 @@ public class AccountSetupAccountType extends K9Activity implements OnClickListen
private boolean mMakeDefault;
public static void actionSelectAccountType(Context context, Account account, boolean makeDefault) {
public static void actionSelectAccountType(Context context, Account account, boolean makeDefault)
{
Intent i = new Intent(context, AccountSetupAccountType.class);
i.putExtra(EXTRA_ACCOUNT, account);
i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
@ -41,7 +43,8 @@ public class AccountSetupAccountType extends K9Activity implements OnClickListen
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_account_type);
((Button)findViewById(R.id.pop)).setOnClickListener(this);
@ -52,59 +55,74 @@ public class AccountSetupAccountType extends K9Activity implements OnClickListen
mMakeDefault = (boolean)getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
}
private void onPop() {
try {
private void onPop()
{
try
{
URI uri = new URI(mAccount.getStoreUri());
uri = new URI("pop3", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
mAccount.setStoreUri(uri.toString());
AccountSetupIncoming.actionIncomingSettings(this, mAccount, mMakeDefault);
finish();
} catch (Exception use) {
}
catch (Exception use)
{
failure(use);
}
}
private void onImap() {
try {
private void onImap()
{
try
{
URI uri = new URI(mAccount.getStoreUri());
uri = new URI("imap", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
mAccount.setStoreUri(uri.toString());
AccountSetupIncoming.actionIncomingSettings(this, mAccount, mMakeDefault);
finish();
} catch (Exception use) {
}
catch (Exception use)
{
failure(use);
}
}
private void onWebDav() {
try {
private void onWebDav()
{
try
{
URI uri = new URI(mAccount.getStoreUri());
uri = new URI("webdav", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
mAccount.setStoreUri(uri.toString());
AccountSetupIncoming.actionIncomingSettings(this, mAccount, mMakeDefault);
finish();
} catch (Exception use) {
}
catch (Exception use)
{
failure(use);
}
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.pop:
onPop();
break;
case R.id.imap:
onImap();
break;
case R.id.webdav:
onWebDav();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.pop:
onPop();
break;
case R.id.imap:
onImap();
break;
case R.id.webdav:
onWebDav();
break;
}
}
private void failure(Exception use) {
private void failure(Exception use)
{
Log.e(Email.LOG_TAG, "Failure", use);
String toastText = getString(R.string.account_setup_bad_uri, use.getMessage());

View file

@ -42,7 +42,8 @@ import com.android.email.Utility;
* AccountSetupAccountType activity.
*/
public class AccountSetupBasics extends K9Activity
implements OnClickListener, TextWatcher {
implements OnClickListener, TextWatcher
{
private final static String EXTRA_ACCOUNT = "com.android.email.AccountSetupBasics.account";
private final static int DIALOG_NOTE = 1;
private final static String STATE_KEY_PROVIDER =
@ -59,13 +60,15 @@ public class AccountSetupBasics extends K9Activity
private EmailAddressValidator mEmailValidator = new EmailAddressValidator();
public static void actionNewAccount(Context context) {
public static void actionNewAccount(Context context)
{
Intent i = new Intent(context, AccountSetupBasics.class);
context.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_basics);
mPrefs = Preferences.getPreferences(this);
@ -81,45 +84,55 @@ public class AccountSetupBasics extends K9Activity
mEmailView.addTextChangedListener(this);
mPasswordView.addTextChangedListener(this);
if (mPrefs.getAccounts().length > 0) {
if (mPrefs.getAccounts().length > 0)
{
mDefaultView.setVisibility(View.VISIBLE);
}
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT))
{
mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT);
}
if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) {
if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER))
{
mProvider = (Provider)savedInstanceState.getSerializable(STATE_KEY_PROVIDER);
}
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
validateFields();
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_ACCOUNT, mAccount);
if (mProvider != null) {
if (mProvider != null)
{
outState.putSerializable(STATE_KEY_PROVIDER, mProvider);
}
}
public void afterTextChanged(Editable s) {
public void afterTextChanged(Editable s)
{
validateFields();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
private void validateFields() {
private void validateFields()
{
String email = mEmailView.getText().toString();
boolean valid = Utility.requiredFieldValid(mEmailView)
&& Utility.requiredFieldValid(mPasswordView)
@ -135,56 +148,74 @@ public class AccountSetupBasics extends K9Activity
Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128);
}
private String getOwnerName() {
private String getOwnerName()
{
String name = null;
try {
String projection[] = {
try
{
String projection[] =
{
ContactMethods.NAME
};
Cursor c = getContentResolver().query(
// TODO: For Android 2.0, needs to change to ContactsContract.People...
Uri.withAppendedPath(Contacts.People.CONTENT_URI, "owner"), projection, null, null,
null);
if (c.getCount() > 0) {
if (c.getCount() > 0)
{
c.moveToFirst();
name = c.getString(0);
c.close();
}
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get owner name, using default account name", e);
}
if (name == null || name.length() == 0) {
try {
if (name == null || name.length() == 0)
{
try
{
name = getDefaultAccountName();
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get default account name", e);
}
}
if (name == null) {
if (name == null)
{
name = "";
}
return name;
}
private String getDefaultAccountName() {
private String getDefaultAccountName()
{
String name = null;
Account account = Preferences.getPreferences(this).getDefaultAccount();
if (account != null) {
if (account != null)
{
name = account.getName();
}
return name;
}
@Override
public Dialog onCreateDialog(int id) {
if (id == DIALOG_NOTE) {
if (mProvider != null && mProvider.note != null) {
public Dialog onCreateDialog(int id)
{
if (id == DIALOG_NOTE)
{
if (mProvider != null && mProvider.note != null)
{
return new AlertDialog.Builder(this)
.setMessage(mProvider.note)
.setPositiveButton(
getString(R.string.okay_action),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
finishAutoSetup();
}
})
@ -197,7 +228,8 @@ public class AccountSetupBasics extends K9Activity
return null;
}
private void finishAutoSetup() {
private void finishAutoSetup()
{
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
String[] emailParts = splitEmail(email);
@ -205,7 +237,8 @@ public class AccountSetupBasics extends K9Activity
String domain = emailParts[1];
URI incomingUri = null;
URI outgoingUri = null;
try {
try
{
String incomingUsername = mProvider.incomingUsernameTemplate;
incomingUsername = incomingUsername.replaceAll("\\$email", email);
incomingUsername = incomingUsername.replaceAll("\\$user", user);
@ -225,7 +258,9 @@ public class AccountSetupBasics extends K9Activity
outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
+ password, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
null, null);
} catch (URISyntaxException use) {
}
catch (URISyntaxException use)
{
/*
* If there is some problem with the URI we give up and go on to
* manual setup.
@ -246,14 +281,16 @@ public class AccountSetupBasics extends K9Activity
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, true);
}
private void onNext() {
private void onNext()
{
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
String[] emailParts = splitEmail(email);
String user = emailParts[0];
String domain = emailParts[1];
mProvider = findProviderForDomain(domain);
if (mProvider == null) {
if (mProvider == null)
{
/*
* We don't have default settings for this account, start the manual
* setup process.
@ -262,19 +299,25 @@ public class AccountSetupBasics extends K9Activity
return;
}
if (mProvider.note != null) {
if (mProvider.note != null)
{
showDialog(DIALOG_NOTE);
} else {
}
else
{
finishAutoSetup();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
mAccount.setDescription(mAccount.getEmail());
mAccount.save(Preferences.getPreferences(this));
if (mDefaultView.isChecked()) {
if (mDefaultView.isChecked())
{
Preferences.getPreferences(this).setDefaultAccount(mAccount);
}
Email.setServicesEnabled(this);
@ -283,7 +326,8 @@ public class AccountSetupBasics extends K9Activity
}
}
private void onManualSetup() {
private void onManualSetup()
{
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
String[] emailParts = splitEmail(email);
@ -293,12 +337,15 @@ public class AccountSetupBasics extends K9Activity
mAccount = new Account(this);
mAccount.setName(getOwnerName());
mAccount.setEmail(email);
try {
try
{
URI uri = new URI("placeholder", user + ":" + password, "mail." + domain, -1, null,
null, null);
mAccount.setStoreUri(uri.toString());
mAccount.setTransportUri(uri.toString());
} catch (URISyntaxException use) {
}
catch (URISyntaxException use)
{
/*
* If we can't set up the URL we just continue. It's only for
* convenience.
@ -313,14 +360,16 @@ public class AccountSetupBasics extends K9Activity
finish();
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.next:
onNext();
break;
case R.id.manual_setup:
onManualSetup();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.next:
onNext();
break;
case R.id.manual_setup:
onManualSetup();
break;
}
}
@ -331,60 +380,78 @@ public class AccountSetupBasics extends K9Activity
* @param name
* @return
*/
private String getXmlAttribute(XmlResourceParser xml, String name) {
private String getXmlAttribute(XmlResourceParser xml, String name)
{
int resId = xml.getAttributeResourceValue(null, name, 0);
if (resId == 0) {
if (resId == 0)
{
return xml.getAttributeValue(null, name);
} else {
}
else
{
return getString(resId);
}
}
private Provider findProviderForDomain(String domain) {
try {
private Provider findProviderForDomain(String domain)
{
try
{
XmlResourceParser xml = getResources().getXml(R.xml.providers);
int xmlEventType;
Provider provider = null;
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT)
{
if (xmlEventType == XmlResourceParser.START_TAG
&& "provider".equals(xml.getName())
&& domain.equalsIgnoreCase(getXmlAttribute(xml, "domain"))) {
&& domain.equalsIgnoreCase(getXmlAttribute(xml, "domain")))
{
provider = new Provider();
provider.id = getXmlAttribute(xml, "id");
provider.label = getXmlAttribute(xml, "label");
provider.domain = getXmlAttribute(xml, "domain");
provider.note = getXmlAttribute(xml, "note");
} else if (xmlEventType == XmlResourceParser.START_TAG
&& "incoming".equals(xml.getName())
&& provider != null) {
}
else if (xmlEventType == XmlResourceParser.START_TAG
&& "incoming".equals(xml.getName())
&& provider != null)
{
provider.incomingUriTemplate = new URI(getXmlAttribute(xml, "uri"));
provider.incomingUsernameTemplate = getXmlAttribute(xml, "username");
} else if (xmlEventType == XmlResourceParser.START_TAG
&& "outgoing".equals(xml.getName())
&& provider != null) {
}
else if (xmlEventType == XmlResourceParser.START_TAG
&& "outgoing".equals(xml.getName())
&& provider != null)
{
provider.outgoingUriTemplate = new URI(getXmlAttribute(xml, "uri"));
provider.outgoingUsernameTemplate = getXmlAttribute(xml, "username");
} else if (xmlEventType == XmlResourceParser.END_TAG
&& "provider".equals(xml.getName())
&& provider != null) {
}
else if (xmlEventType == XmlResourceParser.END_TAG
&& "provider".equals(xml.getName())
&& provider != null)
{
return provider;
}
}
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Error while trying to load provider settings.", e);
}
return null;
}
private String[] splitEmail(String email) {
private String[] splitEmail(String email)
{
String[] retParts = new String[2];
String[] emailParts = email.split("@");
retParts[0] = (emailParts.length > 0 ) ? emailParts[0] : "";
retParts[1] = (emailParts.length > 1 ) ? emailParts[1] : "";
retParts[0] = (emailParts.length > 0) ? emailParts[0] : "";
retParts[1] = (emailParts.length > 1) ? emailParts[1] : "";
return retParts;
}
static class Provider implements Serializable {
static class Provider implements Serializable
{
private static final long serialVersionUID = 8511656164616538989L;
public String id;

View file

@ -38,7 +38,8 @@ import com.android.email.mail.store.TrustManagerFactory;
* XXX NOTE: The manifest for this app has it ignore config changes, because
* it doesn't correctly deal with restarting while its thread is running.
*/
public class AccountSetupCheckSettings extends K9Activity implements OnClickListener {
public class AccountSetupCheckSettings extends K9Activity implements OnClickListener
{
public static final int ACTIVITY_REQUEST_CODE = 1;
@ -65,7 +66,8 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
private boolean mDestroyed;
public static void actionCheckSettings(Activity context, Account account,
boolean checkIncoming, boolean checkOutgoing) {
boolean checkIncoming, boolean checkOutgoing)
{
Intent i = new Intent(context, AccountSetupCheckSettings.class);
i.putExtra(EXTRA_ACCOUNT, account);
i.putExtra(EXTRA_CHECK_INCOMING, checkIncoming);
@ -74,7 +76,8 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_check_settings);
mMessageView = (TextView)findViewById(R.id.message);
@ -88,61 +91,78 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
mCheckIncoming = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_INCOMING, false);
mCheckOutgoing = (boolean)getIntent().getBooleanExtra(EXTRA_CHECK_OUTGOING, false);
new Thread() {
public void run() {
new Thread()
{
public void run()
{
Store store = null;
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
if (mDestroyed) {
try
{
if (mDestroyed)
{
return;
}
if (mCanceled) {
if (mCanceled)
{
finish();
return;
}
if (mCheckIncoming) {
if (mCheckIncoming)
{
setMessage(R.string.account_setup_check_settings_check_incoming_msg);
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
store.checkSettings();
MessagingController.getInstance(getApplication()).listFolders(mAccount, true, null);
MessagingController.getInstance(getApplication()).synchronizeMailbox( mAccount, Email.INBOX , null);
MessagingController.getInstance(getApplication()).synchronizeMailbox(mAccount, Email.INBOX , null);
}
if (mDestroyed) {
if (mDestroyed)
{
return;
}
if (mCanceled) {
if (mCanceled)
{
finish();
return;
}
if (mCheckOutgoing) {
if (mCheckOutgoing)
{
setMessage(R.string.account_setup_check_settings_check_outgoing_msg);
Transport transport = Transport.getInstance(mAccount.getTransportUri());
transport.close();
transport.open();
transport.close();
}
if (mDestroyed) {
if (mDestroyed)
{
return;
}
if (mCanceled) {
if (mCanceled)
{
finish();
return;
}
setResult(RESULT_OK);
finish();
} catch (final AuthenticationFailedException afe) {
}
catch (final AuthenticationFailedException afe)
{
Log.e(Email.LOG_TAG, "Error while testing settings", afe);
showErrorDialog(
R.string.account_setup_failed_dlg_auth_message_fmt,
afe.getMessage() == null ? "" : afe.getMessage());
} catch (final CertificateValidationException cve) {
}
catch (final CertificateValidationException cve)
{
Log.e(Email.LOG_TAG, "Error while testing settings", cve);
acceptKeyDialog(
R.string.account_setup_failed_dlg_certificate_message_fmt,
cve);
} catch (final Throwable t) {
}
catch (final Throwable t)
{
Log.e(Email.LOG_TAG, "Error while testing settings", t);
showErrorDialog(
R.string.account_setup_failed_dlg_server_message_fmt,
@ -156,16 +176,21 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
}
@Override
public void onDestroy() {
public void onDestroy()
{
super.onDestroy();
mDestroyed = true;
mCanceled = true;
}
private void setMessage(final int resId) {
mHandler.post(new Runnable() {
public void run() {
if (mDestroyed) {
private void setMessage(final int resId)
{
mHandler.post(new Runnable()
{
public void run()
{
if (mDestroyed)
{
return;
}
mMessageView.setText(getString(resId));
@ -173,10 +198,14 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
});
}
private void showErrorDialog(final int msgResId, final Object... args) {
mHandler.post(new Runnable() {
public void run() {
if (mDestroyed) {
private void showErrorDialog(final int msgResId, final Object... args)
{
mHandler.post(new Runnable()
{
public void run()
{
if (mDestroyed)
{
return;
}
mProgressBar.setIndeterminate(false);
@ -187,8 +216,10 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
.setNegativeButton(
getString(R.string.account_setup_failed_dlg_continue_action),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
mCanceled=false;
setResult(RESULT_OK);
finish();
@ -196,8 +227,10 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
})
.setPositiveButton(
getString(R.string.account_setup_failed_dlg_edit_details_action),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
finish();
}
})
@ -205,32 +238,44 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
}
});
}
private void acceptKeyDialog(final int msgResId, final Object... args) {
mHandler.post(new Runnable() {
public void run() {
if (mDestroyed) {
private void acceptKeyDialog(final int msgResId, final Object... args)
{
mHandler.post(new Runnable()
{
public void run()
{
if (mDestroyed)
{
return;
}
final X509Certificate[] chain = TrustManagerFactory.getLastCertChain();
String exMessage = "Unknown Error";
Exception ex = ((Exception)args[0]);
if (ex != null) {
if (ex.getCause() != null) {
if (ex.getCause().getCause() != null) {
if (ex != null)
{
if (ex.getCause() != null)
{
if (ex.getCause().getCause() != null)
{
exMessage = ex.getCause().getCause().getMessage();
} else {
}
else
{
exMessage = ex.getCause().getMessage();
}
} else {
}
else
{
exMessage = ex.getMessage();
}
}
mProgressBar.setIndeterminate(false);
StringBuffer chainInfo = new StringBuffer(100);
for (int i = 0; i < chain.length; i++) {
for (int i = 0; i < chain.length; i++)
{
// display certificate chain information
chainInfo.append("Certificate chain[" + i + "]:\n");
chainInfo.append("Subject: " + chain[i].getSubjectDN().toString() + "\n");
@ -246,18 +291,25 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
.setCancelable(true)
.setPositiveButton(
getString(R.string.account_setup_failed_dlg_invalid_certificate_accept),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
try
{
String alias = mAccount.getUuid();
if (mCheckIncoming) {
if (mCheckIncoming)
{
alias = alias + ".incoming";
}
if (mCheckOutgoing) {
if (mCheckOutgoing)
{
alias = alias + ".outgoing";
}
TrustManagerFactory.addCertificateChain(alias, chain);
} catch (CertificateException e) {
}
catch (CertificateException e)
{
showErrorDialog(
R.string.account_setup_failed_dlg_certificate_message_fmt,
e.getMessage() == null ? "" : e.getMessage());
@ -268,8 +320,10 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
})
.setNegativeButton(
getString(R.string.account_setup_failed_dlg_invalid_certificate_reject),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
finish();
}
})
@ -278,22 +332,26 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
});
}
public void onActivityResult(int reqCode, int resCode, Intent data) {
public void onActivityResult(int reqCode, int resCode, Intent data)
{
setResult(resCode);
finish();
}
private void onCancel() {
private void onCancel()
{
mCanceled = true;
setMessage(R.string.account_setup_check_settings_canceling_msg);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.cancel:
onCancel();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.cancel:
onCancel();
break;
}
}
}

View file

@ -13,7 +13,8 @@ import com.android.email.Email;
import com.android.email.Preferences;
import com.android.email.R;
public class AccountSetupComposition extends K9Activity {
public class AccountSetupComposition extends K9Activity
{
private static final String EXTRA_ACCOUNT = "account";
@ -27,7 +28,8 @@ public class AccountSetupComposition extends K9Activity {
private RadioButton mAccountSignatureAfterLocation;
public static void actionEditCompositionSettings(Activity context, Account account) {
public static void actionEditCompositionSettings(Activity context, Account account)
{
Intent i = new Intent(context, AccountSetupComposition.class);
i.setAction(Intent.ACTION_EDIT);
i.putExtra(EXTRA_ACCOUNT, account);
@ -36,7 +38,8 @@ public class AccountSetupComposition extends K9Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
@ -47,7 +50,8 @@ public class AccountSetupComposition extends K9Activity {
* If we're being reloaded we override the original account with the one
* we saved
*/
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT))
{
mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT);
}
@ -71,12 +75,14 @@ public class AccountSetupComposition extends K9Activity {
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
mAccount.refresh(Preferences.getPreferences(this));
}
private void saveSettings() {
private void saveSettings()
{
mAccount.setEmail(mAccountEmail.getText().toString());
mAccount.setAlwaysBcc(mAccountAlwaysBcc.getText().toString());
mAccount.setName(mAccountName.getText().toString());
@ -88,21 +94,25 @@ public class AccountSetupComposition extends K9Activity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveSettings();
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_ACCOUNT, mAccount);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
mAccount.save(Preferences.getPreferences(this));
finish();
}

View file

@ -30,7 +30,8 @@ import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.ChooseFolder;
public class AccountSetupIncoming extends K9Activity implements OnClickListener {
public class AccountSetupIncoming extends K9Activity implements OnClickListener
{
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
@ -39,22 +40,28 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
private static final int SELECT_TRASH_FOLDER = 102;
private static final int SELECT_OUTBOX_FOLDER = 103;
private static final int popPorts[] = {
private static final int popPorts[] =
{
110, 995, 995, 110, 110
};
private static final String popSchemes[] = {
private static final String popSchemes[] =
{
"pop3", "pop3+ssl", "pop3+ssl+", "pop3+tls", "pop3+tls+"
};
private static final int imapPorts[] = {
private static final int imapPorts[] =
{
143, 993, 993, 143, 143
};
private static final String imapSchemes[] = {
private static final String imapSchemes[] =
{
"imap", "imap+ssl", "imap+ssl+", "imap+tls", "imap+tls+"
};
private static final int webdavPorts[] = {
private static final int webdavPorts[] =
{
80, 443, 443, 443, 443
};
private static final String webdavSchemes[] = {
private static final String webdavSchemes[] =
{
"webdav", "webdav+ssl", "webdav+ssl+", "webdav+tls", "webdav+tls+"
};
@ -77,14 +84,16 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
private Account mAccount;
private boolean mMakeDefault;
public static void actionIncomingSettings(Activity context, Account account, boolean makeDefault) {
public static void actionIncomingSettings(Activity context, Account account, boolean makeDefault)
{
Intent i = new Intent(context, AccountSetupIncoming.class);
i.putExtra(EXTRA_ACCOUNT, account);
i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
context.startActivity(i);
}
public static void actionEditIncomingSettings(Activity context, Account account) {
public static void actionEditIncomingSettings(Activity context, Account account)
{
Intent i = new Intent(context, AccountSetupIncoming.class);
i.setAction(Intent.ACTION_EDIT);
i.putExtra(EXTRA_ACCOUNT, account);
@ -92,7 +101,8 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_incoming);
@ -118,7 +128,8 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mImapFolderOutbox.setOnClickListener(this);
mNextButton.setOnClickListener(this);
SpinnerOption securityTypes[] = {
SpinnerOption securityTypes[] =
{
new SpinnerOption(0, getString(R.string.account_setup_incoming_security_none_label)),
new SpinnerOption(1,
getString(R.string.account_setup_incoming_security_ssl_optional_label)),
@ -137,12 +148,15 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
* Updates the port when the user changes the security type. This allows
* us to show a reasonable default which the user can change.
*/
mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {
mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3)
{
updatePortFromSecurityType();
}
public void onNothingSelected(AdapterView<?> arg0) {
public void onNothingSelected(AdapterView<?> arg0)
{
}
});
@ -150,15 +164,19 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
* Calls validateFields() which enables or disables the Next button
* based on the fields' validity.
*/
TextWatcher validationTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
TextWatcher validationTextWatcher = new TextWatcher()
{
public void afterTextChanged(Editable s)
{
validateFields();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
};
mUsernameView.addTextChangedListener(validationTextWatcher);
@ -178,27 +196,33 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
* If we're being reloaded we override the original account with the one
* we saved
*/
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT))
{
mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT);
}
try {
try
{
URI uri = new URI(mAccount.getStoreUri());
String username = null;
String password = null;
if (uri.getUserInfo() != null) {
if (uri.getUserInfo() != null)
{
String[] userInfoParts = uri.getUserInfo().split(":", 2);
username = userInfoParts[0];
if (userInfoParts.length > 1) {
if (userInfoParts.length > 1)
{
password = userInfoParts[1];
}
}
if (username != null) {
if (username != null)
{
mUsernameView.setText(username);
}
if (password != null) {
if (password != null)
{
mPasswordView.setText(password);
}
@ -207,7 +231,8 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mImapFolderTrash.setText(mAccount.getTrashFolderName());
mImapFolderOutbox.setText(mAccount.getOutboxFolderName());
if (uri.getScheme().startsWith("pop3")) {
if (uri.getScheme().startsWith("pop3"))
{
serverLabelView.setText(R.string.account_setup_incoming_pop_server_label);
mAccountPorts = popPorts;
mAccountSchemes = popSchemes;
@ -219,23 +244,29 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER);
} else if (uri.getScheme().startsWith("imap")) {
}
else if (uri.getScheme().startsWith("imap"))
{
serverLabelView.setText(R.string.account_setup_incoming_imap_server_label);
mAccountPorts = imapPorts;
mAccountSchemes = imapSchemes;
if (uri.getPath() != null && uri.getPath().length() > 0) {
if (uri.getPath() != null && uri.getPath().length() > 0)
{
mImapPathPrefixView.setText(uri.getPath().substring(1));
}
findViewById(R.id.webdav_path_prefix_section).setVisibility(View.GONE);
findViewById(R.id.webdav_path_debug_section).setVisibility(View.GONE);
mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE);
if (! Intent.ACTION_EDIT.equals(getIntent().getAction())) {
if (! Intent.ACTION_EDIT.equals(getIntent().getAction()))
{
findViewById(R.id.imap_folder_setup_section).setVisibility(View.GONE);
}
} else if (uri.getScheme().startsWith("webdav")) {
}
else if (uri.getScheme().startsWith("webdav"))
{
serverLabelView.setText(R.string.account_setup_incoming_webdav_server_label);
mAccountPorts = webdavPorts;
mAccountSchemes = webdavSchemes;
@ -243,63 +274,85 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
/** Hide the unnecessary fields */
findViewById(R.id.imap_path_prefix_section).setVisibility(View.GONE);
findViewById(R.id.imap_folder_setup_section).setVisibility(View.GONE);
if (uri.getPath() != null && uri.getPath().length() > 0) {
if (uri.getPath() != null && uri.getPath().length() > 0)
{
String[] pathParts = uri.getPath().split("\\|");
for (int i = 0, count = pathParts.length; i < count; i++) {
if (i == 0) {
for (int i = 0, count = pathParts.length; i < count; i++)
{
if (i == 0)
{
if (pathParts[0] != null &&
pathParts[0].length() > 1) {
pathParts[0].length() > 1)
{
mWebdavPathPrefixView.setText(pathParts[0].substring(1));
}
} else if (i == 1) {
}
else if (i == 1)
{
if (pathParts[1] != null &&
pathParts[1].length() > 1) {
pathParts[1].length() > 1)
{
mWebdavAuthPathView.setText(pathParts[1]);
}
} else if (i == 2) {
}
else if (i == 2)
{
if (pathParts[2] != null &&
pathParts[2].length() > 1) {
pathParts[2].length() > 1)
{
mWebdavMailboxPathView.setText(pathParts[2]);
}
}
}
}
mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE);
} else {
}
else
{
throw new Exception("Unknown account type: " + mAccount.getStoreUri());
}
for (int i = 0; i < mAccountSchemes.length; i++) {
if (mAccountSchemes[i].equals(uri.getScheme())) {
for (int i = 0; i < mAccountSchemes.length; i++)
{
if (mAccountSchemes[i].equals(uri.getScheme()))
{
SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i);
}
}
if (uri.getHost() != null) {
if (uri.getHost() != null)
{
mServerView.setText(uri.getHost());
}
if (uri.getPort() != -1) {
if (uri.getPort() != -1)
{
mPortView.setText(Integer.toString(uri.getPort()));
} else {
}
else
{
updatePortFromSecurityType();
}
validateFields();
} catch (Exception e) {
}
catch (Exception e)
{
failure(e);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_ACCOUNT, mAccount);
}
private void validateFields() {
private void validateFields()
{
mNextButton
.setEnabled(Utility.requiredFieldValid(mUsernameView)
&& Utility.requiredFieldValid(mPasswordView)
@ -308,39 +361,48 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128);
}
private void updatePortFromSecurityType() {
if (mAccountPorts != null) {
private void updatePortFromSecurityType()
{
if (mAccountPorts != null)
{
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
mPortView.setText(Integer.toString(mAccountPorts[securityType]));
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case SELECT_DRAFT_FOLDER:
mImapFolderDrafts.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_SENT_FOLDER:
mImapFolderSent.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_TRASH_FOLDER:
mImapFolderTrash.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_OUTBOX_FOLDER:
mImapFolderOutbox.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
switch (requestCode)
{
case SELECT_DRAFT_FOLDER:
mImapFolderDrafts.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_SENT_FOLDER:
mImapFolderSent.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_TRASH_FOLDER:
mImapFolderTrash.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
case SELECT_OUTBOX_FOLDER:
mImapFolderOutbox.setText(data.getStringExtra(ChooseFolder.EXTRA_NEW_FOLDER));
return;
}
if (Intent.ACTION_EDIT.equals(getIntent().getAction())) {
if (Intent.ACTION_EDIT.equals(getIntent().getAction()))
{
mAccount.save(Preferences.getPreferences(this));
finish();
} else {
}
else
{
/*
* Set the username and password for the outgoing settings to the username and
* password the user just set for incoming.
*/
try {
try
{
URI oldUri = new URI(mAccount.getTransportUri());
URI uri = new URI(
oldUri.getScheme(),
@ -351,7 +413,9 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
null,
null);
mAccount.setTransportUri(uri.toString());
} catch (URISyntaxException use) {
}
catch (URISyntaxException use)
{
/*
* If we can't set up the URL we just continue. It's only for
* convenience.
@ -365,13 +429,18 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
}
}
private void onNext() {
try {
private void onNext()
{
try
{
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
String path = null;
if (mAccountSchemes[securityType].startsWith("imap")) {
if (mAccountSchemes[securityType].startsWith("imap"))
{
path = "/" + mImapPathPrefixView.getText();
} else if (mAccountSchemes[securityType].startsWith("webdav")) {
}
else if (mAccountSchemes[securityType].startsWith("webdav"))
{
path = "/" + mWebdavPathPrefixView.getText();
path = path + "|" + mWebdavAuthPathView.getText();
path = path + "|" + mWebdavMailboxPathView.getText();
@ -393,54 +462,63 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mAccount.setTrashFolderName(mImapFolderTrash.getText().toString());
mAccount.setOutboxFolderName(mImapFolderOutbox.getText().toString());
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
} catch (Exception e) {
}
catch (Exception e)
{
failure(e);
}
}
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.next:
onNext();
break;
case R.id.account_imap_folder_drafts:
selectImapFolder(SELECT_DRAFT_FOLDER);
break;
case R.id.account_imap_folder_sent:
selectImapFolder(SELECT_SENT_FOLDER);
break;
case R.id.account_imap_folder_trash:
selectImapFolder(SELECT_TRASH_FOLDER);
break;
case R.id.account_imap_folder_outbox:
selectImapFolder(SELECT_OUTBOX_FOLDER);
break;
public void onClick(View v)
{
try
{
switch (v.getId())
{
case R.id.next:
onNext();
break;
case R.id.account_imap_folder_drafts:
selectImapFolder(SELECT_DRAFT_FOLDER);
break;
case R.id.account_imap_folder_sent:
selectImapFolder(SELECT_SENT_FOLDER);
break;
case R.id.account_imap_folder_trash:
selectImapFolder(SELECT_TRASH_FOLDER);
break;
case R.id.account_imap_folder_outbox:
selectImapFolder(SELECT_OUTBOX_FOLDER);
break;
}
} catch (Exception e) {
}
catch (Exception e)
{
failure(e);
}
}
private void selectImapFolder(int activityCode) {
private void selectImapFolder(int activityCode)
{
String curFolder = null;
switch (activityCode) {
case SELECT_DRAFT_FOLDER:
curFolder = mImapFolderDrafts.getText().toString();
break;
case SELECT_SENT_FOLDER:
curFolder = mImapFolderSent.getText().toString();
break;
case SELECT_TRASH_FOLDER:
curFolder = mImapFolderTrash.getText().toString();
break;
case SELECT_OUTBOX_FOLDER:
curFolder = mImapFolderOutbox.getText().toString();
break;
default:
throw new IllegalArgumentException(
"Cannot select folder for: " + activityCode);
switch (activityCode)
{
case SELECT_DRAFT_FOLDER:
curFolder = mImapFolderDrafts.getText().toString();
break;
case SELECT_SENT_FOLDER:
curFolder = mImapFolderSent.getText().toString();
break;
case SELECT_TRASH_FOLDER:
curFolder = mImapFolderTrash.getText().toString();
break;
case SELECT_OUTBOX_FOLDER:
curFolder = mImapFolderOutbox.getText().toString();
break;
default:
throw new IllegalArgumentException(
"Cannot select folder for: " + activityCode);
}
Intent selectIntent = new Intent(this, ChooseFolder.class);
@ -450,7 +528,8 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
startActivityForResult(selectIntent, activityCode);
}
private void failure(Exception use) {
private void failure(Exception use)
{
Log.e(Email.LOG_TAG, "Failure", use);
String toastText = getString(R.string.account_setup_bad_uri, use.getMessage());

View file

@ -21,7 +21,8 @@ import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.FolderList;
public class AccountSetupNames extends K9Activity implements OnClickListener {
public class AccountSetupNames extends K9Activity implements OnClickListener
{
private static final String EXTRA_ACCOUNT = "account";
private EditText mDescription;
@ -32,14 +33,16 @@ public class AccountSetupNames extends K9Activity implements OnClickListener {
private Button mDoneButton;
public static void actionSetNames(Context context, Account account) {
public static void actionSetNames(Context context, Account account)
{
Intent i = new Intent(context, AccountSetupNames.class);
i.putExtra(EXTRA_ACCOUNT, account);
context.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_names);
mDescription = (EditText)findViewById(R.id.account_description);
@ -47,15 +50,19 @@ public class AccountSetupNames extends K9Activity implements OnClickListener {
mDoneButton = (Button)findViewById(R.id.done);
mDoneButton.setOnClickListener(this);
TextWatcher validationTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
TextWatcher validationTextWatcher = new TextWatcher()
{
public void afterTextChanged(Editable s)
{
validateFields();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
};
mName.addTextChangedListener(validationTextWatcher);
@ -70,21 +77,26 @@ public class AccountSetupNames extends K9Activity implements OnClickListener {
* just leave the saved value alone.
*/
// mDescription.setText(mAccount.getDescription());
if (mAccount.getName() != null) {
if (mAccount.getName() != null)
{
mName.setText(mAccount.getName());
}
if (!Utility.requiredFieldValid(mName)) {
if (!Utility.requiredFieldValid(mName))
{
mDoneButton.setEnabled(false);
}
}
private void validateFields() {
private void validateFields()
{
mDoneButton.setEnabled(Utility.requiredFieldValid(mName));
Utility.setCompoundDrawablesAlpha(mDoneButton, mDoneButton.isEnabled() ? 255 : 128);
}
private void onNext() {
if (Utility.requiredFieldValid(mDescription)) {
private void onNext()
{
if (Utility.requiredFieldValid(mDescription))
{
mAccount.setDescription(mDescription.getText().toString());
}
mAccount.setName(mName.getText().toString());
@ -93,11 +105,13 @@ public class AccountSetupNames extends K9Activity implements OnClickListener {
finish();
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.done:
onNext();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.done:
onNext();
break;
}
}
}

View file

@ -18,7 +18,8 @@ import com.android.email.Preferences;
import com.android.email.mail.Store;
import com.android.email.R;
public class AccountSetupOptions extends K9Activity implements OnClickListener {
public class AccountSetupOptions extends K9Activity implements OnClickListener
{
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
@ -34,7 +35,8 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
private Account mAccount;
public static void actionOptions(Context context, Account account, boolean makeDefault) {
public static void actionOptions(Context context, Account account, boolean makeDefault)
{
Intent i = new Intent(context, AccountSetupOptions.class);
i.putExtra(EXTRA_ACCOUNT, account);
i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
@ -42,7 +44,8 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_options);
@ -54,7 +57,8 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
findViewById(R.id.next).setOnClickListener(this);
SpinnerOption checkFrequencies[] = {
SpinnerOption checkFrequencies[] =
{
new SpinnerOption(-1,
getString(R.string.account_setup_options_mail_check_frequency_never)),
new SpinnerOption(1,
@ -88,7 +92,8 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCheckFrequencyView.setAdapter(checkFrequenciesAdapter);
SpinnerOption displayCounts[] = {
SpinnerOption displayCounts[] =
{
new SpinnerOption(10,
getString(R.string.account_setup_options_mail_display_count_10)),
new SpinnerOption(25,
@ -115,24 +120,31 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
boolean isPushCapable = false;
try {
try
{
Store store = Store.getInstance(mAccount.getStoreUri(), getApplication());
isPushCapable = store.isPushCapable();
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
}
if (!isPushCapable) {
if (!isPushCapable)
{
mPushEnable.setVisibility(View.GONE);
} else {
}
else
{
mPushEnable.setChecked(true);
}
}
private void onDone() {
private void onDone()
{
mAccount.setDescription(mAccount.getEmail());
mAccount.setNotifyNewMail(mNotifyView.isChecked());
mAccount.setShowOngoing(mNotifySyncView.isChecked());
@ -141,15 +153,19 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
mAccount.setDisplayCount((Integer)((SpinnerOption)mDisplayCountView
.getSelectedItem()).value);
if (mPushEnable.isChecked()) {
if (mPushEnable.isChecked())
{
mAccount.setFolderPushMode(Account.FolderMode.FIRST_CLASS);
} else {
}
else
{
mAccount.setFolderPushMode(Account.FolderMode.NONE);
}
mAccount.save(Preferences.getPreferences(this));
if (mAccount.equals(Preferences.getPreferences(this).getDefaultAccount()) ||
getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false) ) {
getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false))
{
Preferences.getPreferences(this).setDefaultAccount(mAccount);
}
Email.setServicesEnabled(this);
@ -157,11 +173,13 @@ public class AccountSetupOptions extends K9Activity implements OnClickListener {
finish();
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.next:
onDone();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.next:
onDone();
break;
}
}
}

View file

@ -32,22 +32,27 @@ import com.android.email.R;
import com.android.email.Utility;
public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
OnCheckedChangeListener {
OnCheckedChangeListener
{
private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
private static final int smtpPorts[] = {
private static final int smtpPorts[] =
{
25, 465, 465, 25, 25
};
private static final String smtpSchemes[] = {
private static final String smtpSchemes[] =
{
"smtp", "smtp+ssl", "smtp+ssl+", "smtp+tls", "smtp+tls+"
};
private static final int webdavPorts[] = {
private static final int webdavPorts[] =
{
80, 443, 443, 443, 443
};
private static final String webdavSchemes[] = {
private static final String webdavSchemes[] =
{
"webdav", "webdav+ssl", "webdav+ssl+", "webdav+tls", "webdav+tls+"
};
@ -62,14 +67,16 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
private Account mAccount;
private boolean mMakeDefault;
public static void actionOutgoingSettings(Context context, Account account, boolean makeDefault) {
public static void actionOutgoingSettings(Context context, Account account, boolean makeDefault)
{
Intent i = new Intent(context, AccountSetupOutgoing.class);
i.putExtra(EXTRA_ACCOUNT, account);
i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
context.startActivity(i);
}
public static void actionEditOutgoingSettings(Context context, Account account) {
public static void actionEditOutgoingSettings(Context context, Account account)
{
Intent i = new Intent(context, AccountSetupOutgoing.class);
i.setAction(Intent.ACTION_EDIT);
i.putExtra(EXTRA_ACCOUNT, account);
@ -77,18 +84,23 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.account_setup_outgoing);
mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
try {
if (new URI(mAccount.getStoreUri()).getScheme().startsWith("webdav")) {
try
{
if (new URI(mAccount.getStoreUri()).getScheme().startsWith("webdav"))
{
mAccount.setTransportUri(mAccount.getStoreUri());
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true);
}
} catch (URISyntaxException e) {
}
catch (URISyntaxException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
@ -106,7 +118,8 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
mNextButton.setOnClickListener(this);
mRequireLoginView.setOnCheckedChangeListener(this);
SpinnerOption securityTypes[] = {
SpinnerOption securityTypes[] =
{
new SpinnerOption(0, getString(R.string.account_setup_incoming_security_none_label)),
new SpinnerOption(1,
getString(R.string.account_setup_incoming_security_ssl_optional_label)),
@ -125,12 +138,15 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
* Updates the port when the user changes the security type. This allows
* us to show a reasonable default which the user can change.
*/
mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {
mSecurityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3)
{
updatePortFromSecurityType();
}
public void onNothingSelected(AdapterView<?> arg0) {
public void onNothingSelected(AdapterView<?> arg0)
{
}
});
@ -138,15 +154,19 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
* Calls validateFields() which enables or disables the Next button
* based on the fields' validity.
*/
TextWatcher validationTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
TextWatcher validationTextWatcher = new TextWatcher()
{
public void afterTextChanged(Editable s)
{
validateFields();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
};
mUsernameView.addTextChangedListener(validationTextWatcher);
@ -166,49 +186,63 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
* If we're being reloaded we override the original account with the one
* we saved
*/
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT))
{
mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT);
}
try {
try
{
URI uri = new URI(mAccount.getTransportUri());
String username = null;
String password = null;
if (uri.getUserInfo() != null) {
if (uri.getUserInfo() != null)
{
String[] userInfoParts = uri.getUserInfo().split(":", 2);
username = userInfoParts[0];
if (userInfoParts.length > 1) {
if (userInfoParts.length > 1)
{
password = userInfoParts[1];
}
}
if (username != null) {
if (username != null)
{
mUsernameView.setText(username);
mRequireLoginView.setChecked(true);
}
if (password != null) {
if (password != null)
{
mPasswordView.setText(password);
}
for (int i = 0; i < smtpSchemes.length; i++) {
if (smtpSchemes[i].equals(uri.getScheme())) {
for (int i = 0; i < smtpSchemes.length; i++)
{
if (smtpSchemes[i].equals(uri.getScheme()))
{
SpinnerOption.setSpinnerOptionValue(mSecurityTypeView, i);
}
}
if (uri.getHost() != null) {
if (uri.getHost() != null)
{
mServerView.setText(uri.getHost());
}
if (uri.getPort() != -1) {
if (uri.getPort() != -1)
{
mPortView.setText(Integer.toString(uri.getPort()));
} else {
}
else
{
updatePortFromSecurityType();
}
validateFields();
} catch (Exception e) {
}
catch (Exception e)
{
/*
* We should always be able to parse our own settings.
*/
@ -218,12 +252,14 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
}
@Override
public void onSaveInstanceState(Bundle outState) {
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_ACCOUNT, mAccount);
}
private void validateFields() {
private void validateFields()
{
mNextButton
.setEnabled(
Utility.domainFieldValid(mServerView) &&
@ -234,30 +270,39 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128);
}
private void updatePortFromSecurityType() {
private void updatePortFromSecurityType()
{
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
mPortView.setText(Integer.toString(smtpPorts[securityType]));
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (Intent.ACTION_EDIT.equals(getIntent().getAction())) {
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
if (Intent.ACTION_EDIT.equals(getIntent().getAction()))
{
mAccount.save(Preferences.getPreferences(this));
finish();
} else {
}
else
{
AccountSetupOptions.actionOptions(this, mAccount, mMakeDefault);
finish();
}
}
}
private void onNext() {
private void onNext()
{
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
URI uri;
try {
try
{
String userInfo = null;
if (mRequireLoginView.isChecked()) {
if (mRequireLoginView.isChecked())
{
userInfo = mUsernameView.getText().toString() + ":"
+ mPasswordView.getText().toString();
}
@ -265,7 +310,9 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
Integer.parseInt(mPortView.getText().toString()), null, null, null);
mAccount.setTransportUri(uri.toString());
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true);
} catch (Exception e) {
}
catch (Exception e)
{
/*
* It's unrecoverable if we cannot create a URI from components that
* we validated to be safe.
@ -275,19 +322,23 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.next:
onNext();
break;
public void onClick(View v)
{
switch (v.getId())
{
case R.id.next:
onNext();
break;
}
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
mRequireLoginSettingsView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
validateFields();
}
private void failure(Exception use) {
private void failure(Exception use)
{
Log.e(Email.LOG_TAG, "Failure", use);
String toastText = getString(R.string.account_setup_bad_uri, use.getMessage());

View file

@ -24,7 +24,8 @@ import com.android.email.mail.Store;
import com.android.email.mail.Folder.FolderClass;
import com.android.email.mail.store.LocalStore.LocalFolder;
public class FolderSettings extends K9PreferenceActivity {
public class FolderSettings extends K9PreferenceActivity
{
private static final String EXTRA_FOLDER_NAME = "com.android.email.folderName";
private static final String EXTRA_ACCOUNT = "com.android.email.account";
@ -40,7 +41,8 @@ public class FolderSettings extends K9PreferenceActivity {
private ListPreference mSyncClass;
private ListPreference mPushClass;
public static void actionSettings(Context context, Account account, String folderName) {
public static void actionSettings(Context context, Account account, String folderName)
{
Intent i = new Intent(context, FolderSettings.class);
i.putExtra(EXTRA_FOLDER_NAME, folderName);
i.putExtra(EXTRA_ACCOUNT, account);
@ -48,28 +50,35 @@ public class FolderSettings extends K9PreferenceActivity {
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String folderName = (String)getIntent().getSerializableExtra(EXTRA_FOLDER_NAME);
Account mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
try {
try
{
Store localStore = Store.getInstance(mAccount.getLocalStoreUri(),
getApplication());
mFolder = (LocalFolder) localStore.getFolder(folderName);
mFolder.refresh(Preferences.getPreferences(this));
} catch (MessagingException me) {
}
catch (MessagingException me)
{
Log.e(Email.LOG_TAG, "Unable to edit folder " + folderName + " preferences", me);
return;
}
boolean isPushCapable = false;
Store store = null;
try {
try
{
store = Store.getInstance(mAccount.getStoreUri(), getApplication());
isPushCapable = store.isPushCapable();
} catch (Exception e) {
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
}
@ -81,8 +90,10 @@ public class FolderSettings extends K9PreferenceActivity {
mDisplayClass = (ListPreference) findPreference(PREFERENCE_DISPLAY_CLASS);
mDisplayClass.setValue(mFolder.getDisplayClass().name());
mDisplayClass.setSummary(mDisplayClass.getEntry());
mDisplayClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mDisplayClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mDisplayClass.findIndexOfValue(summary);
mDisplayClass.setSummary(mDisplayClass.getEntries()[index]);
@ -94,8 +105,10 @@ public class FolderSettings extends K9PreferenceActivity {
mSyncClass = (ListPreference) findPreference(PREFERENCE_SYNC_CLASS);
mSyncClass.setValue(mFolder.getRawSyncClass().name());
mSyncClass.setSummary(mSyncClass.getEntry());
mSyncClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSyncClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mSyncClass.findIndexOfValue(summary);
mSyncClass.setSummary(mSyncClass.getEntries()[index]);
@ -108,8 +121,10 @@ public class FolderSettings extends K9PreferenceActivity {
mPushClass.setEnabled(isPushCapable);
mPushClass.setValue(mFolder.getRawPushClass().name());
mPushClass.setSummary(mPushClass.getEntry());
mPushClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mPushClass.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mPushClass.findIndexOfValue(summary);
mPushClass.setSummary(mPushClass.getEntries()[index]);
@ -120,31 +135,41 @@ public class FolderSettings extends K9PreferenceActivity {
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
try {
try
{
mFolder.refresh(Preferences.getPreferences(this));
} catch (MessagingException me) {
}
catch (MessagingException me)
{
Log.e(Email.LOG_TAG, "Could not refresh folder preferences for folder " + mFolder.getName(), me);
}
}
private void saveSettings() {
private void saveSettings()
{
mFolder.setDisplayClass(FolderClass.valueOf(mDisplayClass.getValue()));
mFolder.setSyncClass(FolderClass.valueOf(mSyncClass.getValue()));
mFolder.setPushClass(FolderClass.valueOf(mPushClass.getValue()));
try {
try
{
mFolder.save(Preferences.getPreferences(this));
Email.setServicesEnabled(this);
} catch (MessagingException me) {
}
catch (MessagingException me)
{
Log.e(Email.LOG_TAG, "Could not refresh folder preferences for folder " + mFolder.getName(), me);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveSettings();
}
return super.onKeyDown(keyCode, event);

View file

@ -24,7 +24,8 @@ import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.service.MailService;
public class Prefs extends K9PreferenceActivity {
public class Prefs extends K9PreferenceActivity
{
private static final String PREFERENCE_TOP_CATERGORY = "preferences";
private static final String PREFERENCE_THEME = "theme";
@ -40,13 +41,15 @@ public class Prefs extends K9PreferenceActivity {
private String initBackgroundOps;
public static void actionPrefs(Context context) {
public static void actionPrefs(Context context)
{
Intent i = new Intent(context, Prefs.class);
context.startActivity(i);
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
@ -55,8 +58,10 @@ public class Prefs extends K9PreferenceActivity {
mTheme = (ListPreference) findPreference(PREFERENCE_THEME);
mTheme.setValue(String.valueOf(Email.getK9Theme() == android.R.style.Theme ? "dark" : "light"));
mTheme.setSummary(mTheme.getEntry());
mTheme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mTheme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mTheme.findIndexOfValue(summary);
mTheme.setSummary(mTheme.getEntries()[index]);
@ -69,8 +74,10 @@ public class Prefs extends K9PreferenceActivity {
initBackgroundOps = Email.getBackgroundOps().toString();
mBackgroundOps.setValue(initBackgroundOps);
mBackgroundOps.setSummary(mBackgroundOps.getEntry());
mBackgroundOps.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
mBackgroundOps.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
public boolean onPreferenceChange(Preference preference, Object newValue)
{
final String summary = newValue.toString();
int index = mBackgroundOps.findIndexOfValue(summary);
mBackgroundOps.setSummary(mBackgroundOps.getEntries()[index]);
@ -88,11 +95,13 @@ public class Prefs extends K9PreferenceActivity {
}
@Override
public void onResume() {
public void onResume()
{
super.onResume();
}
private void saveSettings() {
private void saveSettings()
{
SharedPreferences preferences = Preferences.getPreferences(this).getPreferences();
Email.setK9Theme(mTheme.getValue().equals("dark") ? android.R.style.Theme : android.R.style.Theme_Light);
Email.DEBUG = mDebugLogging.isChecked();
@ -100,14 +109,17 @@ public class Prefs extends K9PreferenceActivity {
String newBackgroundOps = mBackgroundOps.getValue();
Email.setBackgroundOps(newBackgroundOps);
Email.save(preferences);
if (newBackgroundOps.equals(initBackgroundOps) == false) {
if (newBackgroundOps.equals(initBackgroundOps) == false)
{
MailService.backgroundDataChanged(this, null);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveSettings();
}
return super.onKeyDown(keyCode, event);

View file

@ -6,28 +6,34 @@ package com.android.email.activity.setup;
import android.widget.Spinner;
public class SpinnerOption {
public class SpinnerOption
{
public Object value;
public String label;
public static void setSpinnerOptionValue(Spinner spinner, Object value) {
for (int i = 0, count = spinner.getCount(); i < count; i++) {
public static void setSpinnerOptionValue(Spinner spinner, Object value)
{
for (int i = 0, count = spinner.getCount(); i < count; i++)
{
SpinnerOption so = (SpinnerOption)spinner.getItemAtPosition(i);
if (so.value.equals(value)) {
if (so.value.equals(value))
{
spinner.setSelection(i, true);
return;
}
}
}
public SpinnerOption(Object value, String label) {
public SpinnerOption(Object value, String label)
{
this.value = value;
this.label = label;
}
@Override
public String toString() {
public String toString()
{
return label;
}
}

View file

@ -38,7 +38,8 @@ import java.math.BigInteger;
* @since 1.0-dev
* @version $Id$
*/
public class Base64 implements BinaryEncoder, BinaryDecoder {
public class Base64 implements BinaryEncoder, BinaryDecoder
{
/**
* Chunk size per RFC 2045 section 6.8.
*
@ -66,12 +67,13 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] intToBase64 = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
private static final byte[] intToBase64 =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
/**
@ -89,14 +91,15 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] base64ToInt = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
private static final byte[] base64ToInt =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
/** Mask used to extract 6 bits, used when encoding */
@ -178,7 +181,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* Default constructor: lineLength is 76, and the lineSeparator is CRLF
* when encoding, and all forms can be decoded.
*/
public Base64() {
public Base64()
{
this(CHUNK_SIZE, CHUNK_SEPARATOR);
}
@ -197,7 +201,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* If lineLength <= 0, then the output will not be divided into lines (chunks).
* Ignored when decoding.
*/
public Base64(int lineLength) {
public Base64(int lineLength)
{
this(lineLength, CHUNK_SEPARATOR);
}
@ -219,21 +224,29 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @throws IllegalArgumentException The provided lineSeparator included
* some base64 characters. That's not going to work!
*/
public Base64(int lineLength, byte[] lineSeparator) {
public Base64(int lineLength, byte[] lineSeparator)
{
this.lineLength = lineLength;
this.lineSeparator = new byte[lineSeparator.length];
System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
if (lineLength > 0) {
if (lineLength > 0)
{
this.encodeSize = 4 + lineSeparator.length;
} else {
}
else
{
this.encodeSize = 4;
}
this.decodeSize = encodeSize - 1;
if (containsBase64Byte(lineSeparator)) {
if (containsBase64Byte(lineSeparator))
{
String sep;
try {
try
{
sep = new String(lineSeparator, "UTF-8");
} catch (UnsupportedEncodingException uee) {
}
catch (UnsupportedEncodingException uee)
{
sep = new String(lineSeparator);
}
throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]");
@ -245,22 +258,32 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
*
* @return true if there is Base64 object still available for reading.
*/
boolean hasData() { return buf != null; }
boolean hasData()
{
return buf != null;
}
/**
* Returns the amount of buffered data available for reading.
*
* @return The amount of buffered data available for reading.
*/
int avail() { return buf != null ? pos - readPos : 0; }
int avail()
{
return buf != null ? pos - readPos : 0;
}
/** Doubles our buffer. */
private void resizeBuf() {
if (buf == null) {
private void resizeBuf()
{
if (buf == null)
{
buf = new byte[8192];
pos = 0;
readPos = 0;
} else {
}
else
{
byte[] b = new byte[buf.length * 2];
System.arraycopy(buf, 0, b, 0, buf.length);
buf = b;
@ -279,22 +302,30 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @return The number of bytes successfully extracted into the provided
* byte[] array.
*/
int readResults(byte[] b, int bPos, int bAvail) {
if (buf != null) {
int readResults(byte[] b, int bPos, int bAvail)
{
if (buf != null)
{
int len = Math.min(avail(), bAvail);
if (buf != b) {
if (buf != b)
{
System.arraycopy(buf, readPos, b, bPos, len);
readPos += len;
if (readPos >= pos) {
if (readPos >= pos)
{
buf = null;
}
} else {
}
else
{
// Re-using the original consumer's output array is only
// allowed for one round.
buf = null;
}
return len;
} else {
}
else
{
return eof ? -1 : 0;
}
}
@ -308,10 +339,12 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param outPos Position to start buffering into.
* @param outAvail Amount of bytes available for direct buffering.
*/
void setInitialBuffer(byte[] out, int outPos, int outAvail) {
void setInitialBuffer(byte[] out, int outPos, int outAvail)
{
// We can re-use consumer's original output array under
// special circumstances, saving on some System.arraycopy().
if (out != null && out.length == outAvail) {
if (out != null && out.length == outAvail)
{
buf = out;
pos = outPos;
readPos = outPos;
@ -334,19 +367,24 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param inPos Position to start reading data from.
* @param inAvail Amount of bytes available from input for encoding.
*/
void encode(byte[] in, int inPos, int inAvail) {
if (eof) {
void encode(byte[] in, int inPos, int inAvail)
{
if (eof)
{
return;
}
// inAvail < 0 is how we're informed of EOF in the underlying data we're
// encoding.
if (inAvail < 0) {
if (inAvail < 0)
{
eof = true;
if (buf == null || buf.length - pos < encodeSize) {
if (buf == null || buf.length - pos < encodeSize)
{
resizeBuf();
}
switch (modulus) {
switch (modulus)
{
case 1:
buf[pos++] = intToBase64[(x >> 2) & MASK_6BITS];
buf[pos++] = intToBase64[(x << 4) & MASK_6BITS];
@ -361,26 +399,36 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
buf[pos++] = PAD;
break;
}
if (lineLength > 0) {
if (lineLength > 0)
{
System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length);
pos += lineSeparator.length;
}
} else {
for (int i = 0; i < inAvail; i++) {
if (buf == null || buf.length - pos < encodeSize) {
}
else
{
for (int i = 0; i < inAvail; i++)
{
if (buf == null || buf.length - pos < encodeSize)
{
resizeBuf();
}
modulus = (++modulus) % 3;
int b = in[inPos++];
if (b < 0) { b += 256; }
if (b < 0)
{
b += 256;
}
x = (x << 8) + b;
if (0 == modulus) {
if (0 == modulus)
{
buf[pos++] = intToBase64[(x >> 18) & MASK_6BITS];
buf[pos++] = intToBase64[(x >> 12) & MASK_6BITS];
buf[pos++] = intToBase64[(x >> 6) & MASK_6BITS];
buf[pos++] = intToBase64[x & MASK_6BITS];
currentLinePos += 4;
if (lineLength > 0 && lineLength <= currentLinePos) {
if (lineLength > 0 && lineLength <= currentLinePos)
{
System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length);
pos += lineSeparator.length;
currentLinePos = 0;
@ -411,43 +459,55 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param inPos Position to start reading data from.
* @param inAvail Amount of bytes available from input for encoding.
*/
void decode(byte[] in, int inPos, int inAvail) {
if (eof) {
void decode(byte[] in, int inPos, int inAvail)
{
if (eof)
{
return;
}
if (inAvail < 0) {
if (inAvail < 0)
{
eof = true;
}
for (int i = 0; i < inAvail; i++) {
if (buf == null || buf.length - pos < decodeSize) {
for (int i = 0; i < inAvail; i++)
{
if (buf == null || buf.length - pos < decodeSize)
{
resizeBuf();
}
byte b = in[inPos++];
if (b == PAD) {
if (b == PAD)
{
x = x << 6;
switch (modulus) {
switch (modulus)
{
case 2:
x = x << 6;
buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
buf[pos++] = (byte)((x >> 16) & MASK_8BITS);
break;
case 3:
buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
buf[pos++] = (byte) ((x >> 8) & MASK_8BITS);
buf[pos++] = (byte)((x >> 16) & MASK_8BITS);
buf[pos++] = (byte)((x >> 8) & MASK_8BITS);
break;
}
// WE'RE DONE!!!!
eof = true;
return;
} else {
if (b >= 0 && b < base64ToInt.length) {
}
else
{
if (b >= 0 && b < base64ToInt.length)
{
int result = base64ToInt[b];
if (result >= 0) {
if (result >= 0)
{
modulus = (++modulus) % 4;
x = (x << 6) + result;
if (modulus == 0) {
buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
buf[pos++] = (byte) ((x >> 8) & MASK_8BITS);
buf[pos++] = (byte) (x & MASK_8BITS);
if (modulus == 0)
{
buf[pos++] = (byte)((x >> 16) & MASK_8BITS);
buf[pos++] = (byte)((x >> 8) & MASK_8BITS);
buf[pos++] = (byte)(x & MASK_8BITS);
}
}
}
@ -462,7 +522,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* The value to test
* @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
*/
public static boolean isBase64(byte octet) {
public static boolean isBase64(byte octet)
{
return octet == PAD || (octet >= 0 && octet < base64ToInt.length && base64ToInt[octet] != -1);
}
@ -475,9 +536,12 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @return <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is
* empty; false, otherwise
*/
public static boolean isArrayByteBase64(byte[] arrayOctet) {
for (int i = 0; i < arrayOctet.length; i++) {
if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
public static boolean isArrayByteBase64(byte[] arrayOctet)
{
for (int i = 0; i < arrayOctet.length; i++)
{
if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i]))
{
return false;
}
}
@ -491,9 +555,12 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* byte array to test
* @return <code>true</code> if any byte is a valid character in the Base64 alphabet; false herwise
*/
private static boolean containsBase64Byte(byte[] arrayOctet) {
for (int i = 0; i < arrayOctet.length; i++) {
if (isBase64(arrayOctet[i])) {
private static boolean containsBase64Byte(byte[] arrayOctet)
{
for (int i = 0; i < arrayOctet.length; i++)
{
if (isBase64(arrayOctet[i]))
{
return true;
}
}
@ -507,7 +574,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* binary data to encode
* @return Base64 characters
*/
public static byte[] encodeBase64(byte[] binaryData) {
public static byte[] encodeBase64(byte[] binaryData)
{
return encodeBase64(binaryData, false);
}
@ -518,7 +586,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* binary data to encode
* @return Base64 characters chunked in 76 character blocks
*/
public static byte[] encodeBase64Chunked(byte[] binaryData) {
public static byte[] encodeBase64Chunked(byte[] binaryData)
{
return encodeBase64(binaryData, true);
}
@ -532,8 +601,10 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @throws DecoderException
* if the parameter supplied is not of type byte[]
*/
public Object decode(Object pObject) throws DecoderException {
if (!(pObject instanceof byte[])) {
public Object decode(Object pObject) throws DecoderException
{
if (!(pObject instanceof byte[]))
{
throw new DecoderException("Parameter supplied to Base64 decode is not a byte[]");
}
return decode((byte[]) pObject);
@ -546,7 +617,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* A byte array containing Base64 character data
* @return a byte array containing binary data
*/
public byte[] decode(byte[] pArray) {
public byte[] decode(byte[] pArray)
{
return decodeBase64(pArray);
}
@ -561,24 +633,29 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @throws IllegalArgumentException
* Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
*/
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
if (binaryData == null || binaryData.length == 0) {
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked)
{
if (binaryData == null || binaryData.length == 0)
{
return binaryData;
}
Base64 b64 = isChunked ? new Base64() : new Base64(0);
long len = (binaryData.length * 4) / 3;
long mod = len % 4;
if (mod != 0) {
if (mod != 0)
{
len += 4 - mod;
}
if (isChunked) {
if (isChunked)
{
len += (1 + (len / CHUNK_SIZE)) * CHUNK_SEPARATOR.length;
}
if (len > Integer.MAX_VALUE) {
if (len > Integer.MAX_VALUE)
{
throw new IllegalArgumentException(
"Input array too big, output array would be bigger than Integer.MAX_VALUE=" + Integer.MAX_VALUE);
"Input array too big, output array would be bigger than Integer.MAX_VALUE=" + Integer.MAX_VALUE);
}
byte[] buf = new byte[(int) len];
b64.setInitialBuffer(buf, 0, buf.length);
@ -586,7 +663,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
b64.encode(binaryData, 0, -1); // Notify encoder of EOF.
// Encoder might have resized, even though it was unnecessary.
if (b64.buf != buf) {
if (b64.buf != buf)
{
b64.readResults(buf, 0, buf.length);
}
return buf;
@ -598,8 +676,10 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param base64Data Byte array containing Base64 data
* @return Array containing decoded data.
*/
public static byte[] decodeBase64(byte[] base64Data) {
if (base64Data == null || base64Data.length == 0) {
public static byte[] decodeBase64(byte[] base64Data)
{
if (base64Data == null || base64Data.length == 0)
{
return base64Data;
}
Base64 b64 = new Base64();
@ -625,12 +705,15 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @return The data, less whitespace (see RFC 2045).
* @deprecated This method is no longer needed
*/
static byte[] discardWhitespace(byte[] data) {
static byte[] discardWhitespace(byte[] data)
{
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
for (int i = 0; i < data.length; i++) {
switch (data[i]) {
for (int i = 0; i < data.length; i++)
{
switch (data[i])
{
case ' ' :
case '\n' :
case '\r' :
@ -655,15 +738,17 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param byteToCheck the byte to check
* @return true if byte is whitespace, false otherwise
*/
private static boolean isWhiteSpace(byte byteToCheck){
switch (byteToCheck) {
case ' ' :
case '\n' :
case '\r' :
case '\t' :
return true;
default :
return false;
private static boolean isWhiteSpace(byte byteToCheck)
{
switch (byteToCheck)
{
case ' ' :
case '\n' :
case '\r' :
case '\t' :
return true;
default :
return false;
}
}
@ -675,12 +760,15 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* The base-64 encoded data to groom
* @return The data, less non-base64 characters (see RFC 2045).
*/
static byte[] discardNonBase64(byte[] data) {
static byte[] discardNonBase64(byte[] data)
{
byte groomedData[] = new byte[data.length];
int bytesCopied = 0;
for (int i = 0; i < data.length; i++) {
if (isBase64(data[i])) {
for (int i = 0; i < data.length; i++)
{
if (isBase64(data[i]))
{
groomedData[bytesCopied++] = data[i];
}
}
@ -704,8 +792,10 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @throws EncoderException
* if the parameter supplied is not of type byte[]
*/
public Object encode(Object pObject) throws EncoderException {
if (!(pObject instanceof byte[])) {
public Object encode(Object pObject) throws EncoderException
{
if (!(pObject instanceof byte[]))
{
throw new EncoderException("Parameter supplied to Base64 encode is not a byte[]");
}
return encode((byte[]) pObject);
@ -718,7 +808,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* a byte array containing binary data
* @return A byte array containing only Base64 character data
*/
public byte[] encode(byte[] pArray) {
public byte[] encode(byte[] pArray)
{
return encodeBase64(pArray, false);
}
@ -730,7 +821,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param pArray a byte array containing base64 character data
* @return A BigInteger
*/
public static BigInteger decodeInteger(byte[] pArray) {
public static BigInteger decodeInteger(byte[] pArray)
{
return new BigInteger(1, decodeBase64(pArray));
}
@ -742,8 +834,10 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @return A byte array containing base64 character data
* @throws NullPointerException if null is passed in
*/
public static byte[] encodeInteger(BigInteger bigInt) {
if(bigInt == null) {
public static byte[] encodeInteger(BigInteger bigInt)
{
if (bigInt == null)
{
throw new NullPointerException("encodeInteger called with null parameter");
}
@ -757,14 +851,16 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
* @param bigInt <code>BigInteger</code> to be converted
* @return a byte array representation of the BigInteger parameter
*/
static byte[] toIntegerBytes(BigInteger bigInt) {
static byte[] toIntegerBytes(BigInteger bigInt)
{
int bitlen = bigInt.bitLength();
// round bitlen
bitlen = ((bitlen + 7) >> 3) << 3;
byte[] bigBytes = bigInt.toByteArray();
if(((bigInt.bitLength() % 8) != 0) &&
(((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
if (((bigInt.bitLength() % 8) != 0) &&
(((bigInt.bitLength() / 8) + 1) == (bitlen / 8)))
{
return bigBytes;
}
@ -773,7 +869,8 @@ public class Base64 implements BinaryEncoder, BinaryDecoder {
int len = bigBytes.length;
// if bigInt is exactly byte-aligned, just skip signbit in copy
if((bigInt.bitLength() % 8) == 0) {
if ((bigInt.bitLength() % 8) == 0)
{
startSrc = 1;
len--;
}

View file

@ -40,7 +40,8 @@ import java.io.OutputStream;
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @since 1.0-dev
*/
public class Base64OutputStream extends FilterOutputStream {
public class Base64OutputStream extends FilterOutputStream
{
private final boolean doEncode;
private final Base64 base64;
private final byte[] singleByte = new byte[1];
@ -51,7 +52,8 @@ public class Base64OutputStream extends FilterOutputStream {
*
* @param out OutputStream to wrap.
*/
public Base64OutputStream(OutputStream out) {
public Base64OutputStream(OutputStream out)
{
this(out, true);
}
@ -63,7 +65,8 @@ public class Base64OutputStream extends FilterOutputStream {
* @param doEncode true if we should encode all data written to us,
* false if we should decode.
*/
public Base64OutputStream(OutputStream out, boolean doEncode) {
public Base64OutputStream(OutputStream out, boolean doEncode)
{
super(out);
this.doEncode = doEncode;
this.base64 = new Base64();
@ -85,7 +88,8 @@ public class Base64OutputStream extends FilterOutputStream {
* If lineLength <= 0, the lineSeparator is not used.
* If doEncode is false lineSeparator is ignored.
*/
public Base64OutputStream(OutputStream out, boolean doEncode, int lineLength, byte[] lineSeparator) {
public Base64OutputStream(OutputStream out, boolean doEncode, int lineLength, byte[] lineSeparator)
{
super(out);
this.doEncode = doEncode;
this.base64 = new Base64(lineLength, lineSeparator);
@ -94,7 +98,8 @@ public class Base64OutputStream extends FilterOutputStream {
/**
* Writes the specified <code>byte</code> to this output stream.
*/
public void write(int i) throws IOException {
public void write(int i) throws IOException
{
singleByte[0] = (byte) i;
write(singleByte, 0, 1);
}
@ -112,17 +117,28 @@ public class Base64OutputStream extends FilterOutputStream {
* @throws NullPointerException if the byte array parameter is null
* @throws IndexOutOfBoundsException if offset, len or buffer size are invalid
*/
public void write(byte b[], int offset, int len) throws IOException {
if (b == null) {
public void write(byte b[], int offset, int len) throws IOException
{
if (b == null)
{
throw new NullPointerException();
} else if (offset < 0 || len < 0 || offset + len < 0) {
}
else if (offset < 0 || len < 0 || offset + len < 0)
{
throw new IndexOutOfBoundsException();
} else if (offset > b.length || offset + len > b.length) {
}
else if (offset > b.length || offset + len > b.length)
{
throw new IndexOutOfBoundsException();
} else if (len > 0) {
if (doEncode) {
}
else if (len > 0)
{
if (doEncode)
{
base64.encode(b, offset, len);
} else {
}
else
{
base64.decode(b, offset, len);
}
flush(false);
@ -138,16 +154,20 @@ public class Base64OutputStream extends FilterOutputStream {
* OutputStream should also be flushed.
* @throws IOException if an I/O error occurs.
*/
private void flush(boolean propogate) throws IOException {
private void flush(boolean propogate) throws IOException
{
int avail = base64.avail();
if (avail > 0) {
if (avail > 0)
{
byte[] buf = new byte[avail];
int c = base64.readResults(buf, 0, avail);
if (c > 0) {
if (c > 0)
{
out.write(buf, 0, c);
}
}
if (propogate) {
if (propogate)
{
out.flush();
}
}
@ -158,7 +178,8 @@ public class Base64OutputStream extends FilterOutputStream {
*
* @throws IOException if an I/O error occurs.
*/
public void flush() throws IOException {
public void flush() throws IOException
{
flush(true);
}
@ -166,11 +187,15 @@ public class Base64OutputStream extends FilterOutputStream {
* Closes this output stream, flushing any remaining bytes that must be encoded. The
* underlying stream is flushed but not closed.
*/
public void close() throws IOException {
public void close() throws IOException
{
// Notify encoder of EOF (-1).
if (doEncode) {
if (doEncode)
{
base64.encode(singleByte, 0, -1);
} else {
}
else
{
base64.decode(singleByte, 0, -1);
}
flush();

View file

@ -19,43 +19,54 @@ import java.util.List;
import java.util.ArrayList;
import org.apache.james.mime4j.codec.EncoderUtil;
public class Address {
public class Address
{
String mAddress;
String mPersonal;
public Address(String address, String personal) {
public Address(String address, String personal)
{
this.mAddress = address;
if ("".equals(personal)) {
if ("".equals(personal))
{
personal = null;
}
if (personal!=null) {
if (personal!=null)
{
personal = personal.trim();
}
this.mPersonal = personal;
}
public Address(String address) {
public Address(String address)
{
this.mAddress = address;
}
public String getAddress() {
public String getAddress()
{
return mAddress;
}
public void setAddress(String address) {
public void setAddress(String address)
{
this.mAddress = address;
}
public String getPersonal() {
public String getPersonal()
{
return mPersonal;
}
public void setPersonal(String personal) {
if ("".equals(personal)) {
public void setPersonal(String personal)
{
if ("".equals(personal))
{
personal = null;
}
if (personal!=null) {
if (personal!=null)
{
personal = personal.trim();
}
this.mPersonal = personal;
@ -64,149 +75,191 @@ public class Address {
/**
* Parse a comma separated list of email addresses in human readable format and return an
* array of Address objects, RFC-822 encoded.
*
*
* @param addressList
* @return An array of 0 or more Addresses.
*/
public static Address[] parseUnencoded(String addressList) {
public static Address[] parseUnencoded(String addressList)
{
List<Address> addresses = new ArrayList<Address>();
if (addressList!=null
&& !"".equals(addressList)) {
&& !"".equals(addressList))
{
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressList);
for (Rfc822Token token : tokens) {
for (Rfc822Token token : tokens)
{
String address = token.getAddress();
if (address!=null
&& !"".equals(address)) {
&& !"".equals(address))
{
addresses.add(new Address(token.getAddress(), token.getName()));
}
}
}
return addresses.toArray(new Address[0]);
}
/**
* Parse a comma separated list of addresses in RFC-822 format and return an
* array of Address objects.
*
*
* @param addressList
* @return An array of 0 or more Addresses.
*/
public static Address[] parse(String addressList) {
public static Address[] parse(String addressList)
{
ArrayList<Address> addresses = new ArrayList<Address>();
if (addressList == null
&& !"".equals(addressList)) {
&& !"".equals(addressList))
{
return new Address[] {};
}
try {
try
{
MailboxList parsedList = AddressList.parse(addressList).flatten();
for (int i = 0, count = parsedList.size(); i < count; i++) {
for (int i = 0, count = parsedList.size(); i < count; i++)
{
org.apache.james.mime4j.field.address.Address address = parsedList.get(i);
if (address instanceof NamedMailbox) {
if (address instanceof NamedMailbox)
{
NamedMailbox namedMailbox = (NamedMailbox)address;
addresses.add(new Address(namedMailbox.getLocalPart() + "@"
+ namedMailbox.getDomain(), namedMailbox.getName()));
} else if (address instanceof Mailbox) {
+ namedMailbox.getDomain(), namedMailbox.getName()));
}
else if (address instanceof Mailbox)
{
Mailbox mailbox = (Mailbox)address;
addresses.add(new Address(mailbox.getLocalPart() + "@" + mailbox.getDomain()));
} else {
}
else
{
Log.e(Email.LOG_TAG, "Unknown address type from Mime4J: "
+ address.getClass().toString());
+ address.getClass().toString());
}
}
} catch (ParseException pe) {
}
catch (ParseException pe)
{
}
return addresses.toArray(new Address[] {});
}
@Override
public boolean equals(Object o) {
if (o instanceof Address) {
public boolean equals(Object o)
{
if (o instanceof Address)
{
return getAddress().equals(((Address) o).getAddress());
}
return super.equals(o);
}
@Override
public String toString() {
if (mPersonal != null) {
public String toString()
{
if (mPersonal != null)
{
return Utility.quoteString(mPersonal) + " <" + mAddress + ">";
} else {
}
else
{
return mAddress;
}
}
public static String toString(Address[] addresses) {
if (addresses == null) {
public static String toString(Address[] addresses)
{
if (addresses == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < addresses.length; i++) {
for (int i = 0; i < addresses.length; i++)
{
sb.append(addresses[i].toString());
if (i < addresses.length - 1) {
if (i < addresses.length - 1)
{
sb.append(',');
}
}
return sb.toString();
}
public String toEncodedString() {
if (mPersonal != null) {
public String toEncodedString()
{
if (mPersonal != null)
{
return EncoderUtil.encodeAddressDisplayName(mPersonal) + " <" + mAddress + ">";
} else {
}
else
{
return mAddress;
}
}
public static String toEncodedString(Address[] addresses) {
if (addresses == null) {
public static String toEncodedString(Address[] addresses)
{
if (addresses == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < addresses.length; i++) {
for (int i = 0; i < addresses.length; i++)
{
sb.append(addresses[i].toEncodedString());
if (i < addresses.length - 1) {
if (i < addresses.length - 1)
{
sb.append(',');
}
}
return sb.toString();
}
/**
* Returns either the personal portion of the Address or the address portion if the personal
* is not available.
* @return
*/
public String toFriendly() {
if (mPersonal != null && mPersonal.length() > 0) {
public String toFriendly()
{
if (mPersonal != null && mPersonal.length() > 0)
{
return mPersonal;
}
else {
else
{
return mAddress;
}
}
public static String toFriendly(Address[] addresses) {
if (addresses == null) {
public static String toFriendly(Address[] addresses)
{
if (addresses == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < addresses.length; i++) {
for (int i = 0; i < addresses.length; i++)
{
sb.append(addresses[i].toFriendly());
if (i < addresses.length - 1) {
if (i < addresses.length - 1)
{
sb.append(',');
}
}
return sb.toString();
}
/**
* Unpacks an address list previously packed with packAddressList()
* @param list
* @return
*/
public static Address[] unpack(String addressList) {
if (addressList == null) {
public static Address[] unpack(String addressList)
{
if (addressList == null)
{
return new Address[] { };
}
ArrayList<Address> addresses = new ArrayList<Address>();
@ -214,18 +267,22 @@ public class Address {
int pairStartIndex = 0;
int pairEndIndex = 0;
int addressEndIndex = 0;
while (pairStartIndex < length) {
while (pairStartIndex < length)
{
pairEndIndex = addressList.indexOf(",\u0000", pairStartIndex);
if (pairEndIndex == -1) {
if (pairEndIndex == -1)
{
pairEndIndex = length;
}
addressEndIndex = addressList.indexOf(";\u0000", pairStartIndex);
String address = null;
String personal = null;
if (addressEndIndex == -1 || addressEndIndex > pairEndIndex) {
if (addressEndIndex == -1 || addressEndIndex > pairEndIndex)
{
address = addressList.substring(pairStartIndex, pairEndIndex);
}
else {
else
{
address = addressList.substring(pairStartIndex, addressEndIndex);
personal =addressList.substring(addressEndIndex + 2, pairEndIndex);
}
@ -234,7 +291,7 @@ public class Address {
}
return addresses.toArray(new Address[] { });
}
/**
* Packs an address list into a String that is very quick to read
* and parse. Packed lists can be unpacked with unpackAddressList()
@ -243,24 +300,29 @@ public class Address {
* @param list
* @return
*/
public static String pack(Address[] addresses) {
if (addresses == null) {
public static String pack(Address[] addresses)
{
if (addresses == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
for (int i = 0, count = addresses.length; i < count; i++) {
for (int i = 0, count = addresses.length; i < count; i++)
{
Address address = addresses[i];
sb.append(address.getAddress());
String personal = address.getPersonal();
if (personal != null) {
sb.append(";\u0000");
// Escape quotes in the address part on the way in
personal.replaceAll("\"","\\\"");
sb.append(personal);
}
if (i < count - 1) {
sb.append(",\u0000");
}
sb.append(address.getAddress());
String personal = address.getPersonal();
if (personal != null)
{
sb.append(";\u0000");
// Escape quotes in the address part on the way in
personal.replaceAll("\"","\\\"");
sb.append(personal);
}
if (i < count - 1)
{
sb.append(",\u0000");
}
}
return sb.toString();
}

View file

@ -1,14 +1,17 @@
package com.android.email.mail;
public class AuthenticationFailedException extends MessagingException {
public class AuthenticationFailedException extends MessagingException
{
public static final long serialVersionUID = -1;
public AuthenticationFailedException(String message) {
public AuthenticationFailedException(String message)
{
super(message);
}
public AuthenticationFailedException(String message, Throwable throwable) {
public AuthenticationFailedException(String message, Throwable throwable)
{
super(message, throwable);
}
}

View file

@ -5,7 +5,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public interface Body {
public interface Body
{
public InputStream getInputStream() throws MessagingException;
public void writeTo(OutputStream out) throws IOException, MessagingException;
}

View file

@ -1,10 +1,12 @@
package com.android.email.mail;
public abstract class BodyPart implements Part {
public abstract class BodyPart implements Part
{
protected Multipart mParent;
public Multipart getParent() {
public Multipart getParent()
{
return mParent;
}
}

View file

@ -1,14 +1,17 @@
package com.android.email.mail;
public class CertificateValidationException extends MessagingException {
public class CertificateValidationException extends MessagingException
{
public static final long serialVersionUID = -1;
public CertificateValidationException(String message) {
public CertificateValidationException(String message)
{
super(message);
}
public CertificateValidationException(String message, Throwable throwable) {
public CertificateValidationException(String message, Throwable throwable)
{
super(message, throwable);
}
}

View file

@ -13,15 +13,17 @@ import java.util.ArrayList;
* Part: Indicates that the given Part should be fetched. The provider
* is expected have previously created the given BodyPart and stored
* any information it needs to download the content.
* </pre>
* </pre>
*/
public class FetchProfile extends ArrayList {
public class FetchProfile extends ArrayList
{
/**
* Default items available for pre-fetching. It should be expected that any
* item fetched by using these items could potentially include all of the
* previous items.
*/
public enum Item {
public enum Item
{
/**
* Download the flags of the message.
*/
@ -39,7 +41,7 @@ public class FetchProfile extends ArrayList {
* The provider should, if possible, fill in a properly formatted MIME structure in
* the message without actually downloading any message data. If the provider is not
* capable of this operation it should specifically set the body of the message to null
* so that upper levels can detect that a full body download is needed.
* so that upper levels can detect that a full body download is needed.
*/
STRUCTURE,
@ -48,7 +50,7 @@ public class FetchProfile extends ArrayList {
* This should generaly be around 50kB.
*/
BODY_SANE,
/**
* The entire message.
*/

View file

@ -4,7 +4,8 @@ package com.android.email.mail;
/**
* Flags that can be applied to Messages.
*/
public enum Flag {
public enum Flag
{
DELETED,
SEEN,
ANSWERED,
@ -49,7 +50,7 @@ public enum Flag {
* This does not include attachments, which are never downloaded fully.
*/
X_DOWNLOADED_PARTIAL,
/**
* Indicates that the copy of a message to the Sent folder has started.
*/

View file

@ -3,19 +3,23 @@ package com.android.email.mail;
import com.android.email.Preferences;
public abstract class Folder {
private String status = null;
private long lastChecked = 0;
private long lastPush = 0;
public enum OpenMode {
public abstract class Folder
{
private String status = null;
private long lastChecked = 0;
private long lastPush = 0;
public enum OpenMode
{
READ_WRITE, READ_ONLY,
}
// NONE is obsolete, it will be translated to NO_CLASS for display and to INHERITED for sync and push
public enum FolderClass {
NONE, NO_CLASS, INHERITED, FIRST_CLASS, SECOND_CLASS;
public enum FolderClass
{
NONE, NO_CLASS, INHERITED, FIRST_CLASS, SECOND_CLASS;
}
public enum FolderType {
public enum FolderType
{
HOLDS_FOLDERS, HOLDS_MESSAGES,
}
@ -51,10 +55,11 @@ public abstract class Folder {
public abstract boolean create(FolderType type) throws MessagingException;
/**
* Create a new folder with a specified display limit. Not abstract to allow
* Create a new folder with a specified display limit. Not abstract to allow
* remote folders to not override or worry about this call if they don't care to.
*/
public boolean create(FolderType type, int displayLimit) throws MessagingException {
public boolean create(FolderType type, int displayLimit) throws MessagingException
{
return create(type);
}
@ -70,7 +75,7 @@ public abstract class Folder {
public abstract Message getMessage(String uid) throws MessagingException;
public abstract Message[] getMessages(int start, int end, MessageRetrievalListener listener)
throws MessagingException;
throws MessagingException;
/**
* Fetches the given list of messages. The specified listener is notified as
@ -82,41 +87,42 @@ public abstract class Folder {
* @param listener
*/
public abstract Message[] getMessages(MessageRetrievalListener listener)
throws MessagingException;
throws MessagingException;
public Message[] getMessages(MessageRetrievalListener listener, boolean includeDeleted) throws MessagingException {
return getMessages(listener);
public Message[] getMessages(MessageRetrievalListener listener, boolean includeDeleted) throws MessagingException
{
return getMessages(listener);
}
public abstract Message[] getMessages(String[] uids, MessageRetrievalListener listener)
throws MessagingException;
throws MessagingException;
public abstract void appendMessages(Message[] messages) throws MessagingException;
public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {} ;
public void moveMessages(Message[] msgs, Folder folder) throws MessagingException {} ;
public abstract void setFlags(Message[] messages, Flag[] flags, boolean value)
throws MessagingException;
public abstract void setFlags(Flag[] flags, boolean value) throws MessagingException;
throws MessagingException;
public abstract void setFlags(Flag[] flags, boolean value) throws MessagingException;
public abstract String getUidFromMessageId(Message message) throws MessagingException;
public abstract Message[] expunge() throws MessagingException;
public abstract void fetch(Message[] messages, FetchProfile fp,
MessageRetrievalListener listener) throws MessagingException;
MessageRetrievalListener listener) throws MessagingException;
public abstract void delete(boolean recurse) throws MessagingException;
public abstract String getName();
public abstract Flag[] getPermanentFlags() throws MessagingException;
/**
*
*
* @param oldPushState
* @param message
* @return empty string to clear the pushState, null to leave the state as-is
@ -126,68 +132,70 @@ public abstract class Folder {
return null;
}
public boolean supportsFetchingFlags() {
public boolean supportsFetchingFlags()
{
return true;
}//isFlagSupported
@Override
public String toString() {
public String toString()
{
return getName();
}
public long getLastChecked()
{
return lastChecked;
}
public long getLastChecked()
{
return lastChecked;
}
public void setLastChecked(long lastChecked) throws MessagingException
{
this.lastChecked = lastChecked;
}
public long getLastPush()
{
return lastPush;
}
public void setLastChecked(long lastChecked) throws MessagingException
{
this.lastChecked = lastChecked;
}
public void setLastPush(long lastCheckedDisplay) throws MessagingException
{
this.lastPush = lastCheckedDisplay;
}
public long getLastUpdate()
{
return Math.max(getLastChecked(), getLastPush());
}
public long getLastPush()
{
return lastPush;
}
public void setLastPush(long lastCheckedDisplay) throws MessagingException
{
this.lastPush = lastCheckedDisplay;
}
public long getLastUpdate()
{
return Math.max(getLastChecked(), getLastPush());
}
public FolderClass getDisplayClass()
{
return FolderClass.NO_CLASS;
}
public FolderClass getSyncClass()
{
return getDisplayClass();
}
public FolderClass getPushClass()
{
return getSyncClass();
}
public FolderClass getDisplayClass()
{
return FolderClass.NO_CLASS;
}
public FolderClass getSyncClass()
{
return getDisplayClass();
}
public FolderClass getPushClass()
{
return getSyncClass();
}
public void refresh(Preferences preferences) throws MessagingException
{
}
public String getStatus()
{
return status;
}
public String getStatus()
{
return status;
}
public void setStatus(String status) throws MessagingException
{
this.status = status;
}
public void setStatus(String status) throws MessagingException
{
this.status = status;
}
}

View file

@ -4,8 +4,10 @@ package com.android.email.mail;
import java.util.Date;
import java.util.HashSet;
public abstract class Message implements Part, Body {
public enum RecipientType {
public abstract class Message implements Part, Body
{
public enum RecipientType
{
TO, CC, BCC,
}
@ -17,15 +19,18 @@ public abstract class Message implements Part, Body {
protected Folder mFolder;
public String getUid() {
public String getUid()
{
return mUid;
}
public void setUid(String uid) {
public void setUid(String uid)
{
this.mUid = uid;
}
public Folder getFolder() {
public Folder getFolder()
{
return mFolder;
}
@ -33,11 +38,13 @@ public abstract class Message implements Part, Body {
public abstract void setSubject(String subject) throws MessagingException;
public Date getInternalDate() {
public Date getInternalDate()
{
return mInternalDate;
}
public void setInternalDate(Date internalDate) {
public void setInternalDate(Date internalDate)
{
this.mInternalDate = internalDate;
}
@ -50,10 +57,12 @@ public abstract class Message implements Part, Body {
public abstract Address[] getRecipients(RecipientType type) throws MessagingException;
public abstract void setRecipients(RecipientType type, Address[] addresses)
throws MessagingException;
throws MessagingException;
public void setRecipient(RecipientType type, Address address) throws MessagingException {
setRecipients(type, new Address[] {
public void setRecipient(RecipientType type, Address address) throws MessagingException
{
setRecipients(type, new Address[]
{
address
});
}
@ -67,13 +76,13 @@ public abstract class Message implements Part, Body {
public abstract void setReplyTo(Address[] from) throws MessagingException;
public abstract String getMessageId() throws MessagingException;
public abstract void setInReplyTo(String inReplyTo) throws MessagingException;
public abstract String[] getReferences() throws MessagingException;
public abstract void setReferences(String references) throws MessagingException;
public abstract Body getBody() throws MessagingException;
public abstract String getContentType() throws MessagingException;
@ -88,23 +97,29 @@ public abstract class Message implements Part, Body {
public abstract void setBody(Body body) throws MessagingException;
public boolean isMimeType(String mimeType) throws MessagingException {
public boolean isMimeType(String mimeType) throws MessagingException
{
return getContentType().startsWith(mimeType);
}
public void delete(String trashFolderName) throws MessagingException {} ;
/*
* TODO Refactor Flags at some point to be able to store user defined flags.
* TODO Refactor Flags at some point to be able to store user defined flags.
*/
public Flag[] getFlags() {
public Flag[] getFlags()
{
return mFlags.toArray(new Flag[] {});
}
public void setFlag(Flag flag, boolean set) throws MessagingException {
if (set) {
public void setFlag(Flag flag, boolean set) throws MessagingException
{
if (set)
{
mFlags.add(flag);
} else {
}
else
{
mFlags.remove(flag);
}
}
@ -114,13 +129,16 @@ public abstract class Message implements Part, Body {
* @param flags
* @param set
*/
public void setFlags(Flag[] flags, boolean set) throws MessagingException {
for (Flag flag : flags) {
public void setFlags(Flag[] flags, boolean set) throws MessagingException
{
for (Flag flag : flags)
{
setFlag(flag, set);
}
}
public boolean isSet(Flag flag) {
public boolean isSet(Flag flag)
{
return mFlags.contains(flag);
}

View file

@ -3,16 +3,25 @@ package com.android.email.mail;
import java.util.Comparator;
public class MessageDateComparator implements Comparator<Message> {
public int compare(Message o1, Message o2) {
try {
if (o1.getSentDate() == null) {
public class MessageDateComparator implements Comparator<Message>
{
public int compare(Message o1, Message o2)
{
try
{
if (o1.getSentDate() == null)
{
return 1;
} else if (o2.getSentDate() == null) {
}
else if (o2.getSentDate() == null)
{
return -1;
} else
}
else
return o2.getSentDate().compareTo(o1.getSentDate());
} catch (Exception e) {
}
catch (Exception e)
{
return 0;
}
}

View file

@ -1,10 +1,11 @@
package com.android.email.mail;
public interface MessageRetrievalListener {
public interface MessageRetrievalListener
{
public void messageStarted(String uid, int number, int ofTotal);
public void messageFinished(Message message, int number, int ofTotal);
public void messagesFinished(int total);
}

View file

@ -1,38 +1,43 @@
package com.android.email.mail;
public class MessagingException extends Exception {
public class MessagingException extends Exception
{
public static final long serialVersionUID = -1;
boolean permanentFailure = false;
public MessagingException(String message) {
public MessagingException(String message)
{
super(message);
}
public MessagingException(String message, boolean perm) {
public MessagingException(String message, boolean perm)
{
super(message);
permanentFailure = perm;
}
public MessagingException(String message, Throwable throwable) {
public MessagingException(String message, Throwable throwable)
{
super(message, throwable);
}
public MessagingException(String message, boolean perm, Throwable throwable) {
public MessagingException(String message, boolean perm, Throwable throwable)
{
super(message, throwable);
permanentFailure = perm;
}
public boolean isPermanentFailure()
{
return permanentFailure;
return permanentFailure;
}
public void setPermanentFailure(boolean permanentFailure)
{
this.permanentFailure = permanentFailure;
this.permanentFailure = permanentFailure;
}
}

View file

@ -3,46 +3,56 @@ package com.android.email.mail;
import java.util.ArrayList;
public abstract class Multipart implements Body {
public abstract class Multipart implements Body
{
protected Part mParent;
protected ArrayList<BodyPart> mParts = new ArrayList<BodyPart>();
protected String mContentType;
public void addBodyPart(BodyPart part) throws MessagingException {
public void addBodyPart(BodyPart part) throws MessagingException
{
mParts.add(part);
}
public void addBodyPart(BodyPart part, int index) throws MessagingException {
public void addBodyPart(BodyPart part, int index) throws MessagingException
{
mParts.add(index, part);
}
public BodyPart getBodyPart(int index) throws MessagingException {
public BodyPart getBodyPart(int index) throws MessagingException
{
return mParts.get(index);
}
public String getContentType() throws MessagingException {
public String getContentType() throws MessagingException
{
return mContentType;
}
public int getCount() throws MessagingException {
public int getCount() throws MessagingException
{
return mParts.size();
}
public boolean removeBodyPart(BodyPart part) throws MessagingException {
public boolean removeBodyPart(BodyPart part) throws MessagingException
{
return mParts.remove(part);
}
public void removeBodyPart(int index) throws MessagingException {
public void removeBodyPart(int index) throws MessagingException
{
mParts.remove(index);
}
public Part getParent() throws MessagingException {
public Part getParent() throws MessagingException
{
return mParent;
}
public void setParent(Part parent) throws MessagingException {
public void setParent(Part parent) throws MessagingException
{
this.mParent = parent;
}
}

View file

@ -1,14 +1,17 @@
package com.android.email.mail;
public class NoSuchProviderException extends MessagingException {
public class NoSuchProviderException extends MessagingException
{
public static final long serialVersionUID = -1;
public NoSuchProviderException(String message) {
public NoSuchProviderException(String message)
{
super(message);
}
public NoSuchProviderException(String message, Throwable throwable) {
public NoSuchProviderException(String message, Throwable throwable)
{
super(message, throwable);
}
}

View file

@ -4,7 +4,8 @@ package com.android.email.mail;
import java.io.IOException;
import java.io.OutputStream;
public interface Part {
public interface Part
{
public void addHeader(String name, String value) throws MessagingException;
public void removeHeader(String name) throws MessagingException;
@ -20,7 +21,7 @@ public interface Part {
public String[] getHeader(String name) throws MessagingException;
public int getSize() throws MessagingException;
public boolean isMimeType(String mimeType) throws MessagingException;
public String getMimeType() throws MessagingException;

View file

@ -7,7 +7,7 @@ public interface Pusher
public void refresh();
public void stop();
/**
*
*
* @return milliseconds of required refresh interval
*/
public int getRefreshInterval();

View file

@ -19,7 +19,8 @@ import com.android.email.mail.store.WebDavStore;
* performance on mobile devices. Implementations of this class should focus on
* making as few network connections as possible.
*/
public abstract class Store {
public abstract class Store
{
/**
* A global suggestion to Store implementors on how much of the body
* should be returned on FetchProfile.Item.BODY_SANE requests.
@ -48,26 +49,37 @@ public abstract class Store {
* @return
* @throws MessagingException
*/
public synchronized static Store getInstance(String uri, Application application) throws MessagingException {
public synchronized static Store getInstance(String uri, Application application) throws MessagingException
{
Store store = mStores.get(uri);
if (store == null) {
if (uri.startsWith("imap")) {
if (store == null)
{
if (uri.startsWith("imap"))
{
store = new ImapStore(uri);
} else if (uri.startsWith("pop3")) {
}
else if (uri.startsWith("pop3"))
{
store = new Pop3Store(uri);
} else if (uri.startsWith("local")) {
}
else if (uri.startsWith("local"))
{
store = new LocalStore(uri, application);
} else if (uri.startsWith("webdav")) {
}
else if (uri.startsWith("webdav"))
{
store = new WebDavStore(uri);
}
if (store != null) {
if (store != null)
{
mStores.put(uri, store);
}
}
if (store == null) {
if (store == null)
{
throw new MessagingException("Unable to locate an applicable Store for " + uri);
}
@ -79,21 +91,24 @@ public abstract class Store {
public abstract Folder[] getPersonalNamespaces() throws MessagingException;
public abstract void checkSettings() throws MessagingException;
public boolean isCopyCapable() {
return false;
public boolean isCopyCapable()
{
return false;
}
public boolean isMoveCapable() {
return false;
public boolean isMoveCapable()
{
return false;
}
public boolean isPushCapable() {
public boolean isPushCapable()
{
return false;
}
public boolean isSendCapable()
{
return false;
}
public void sendMessages(Message[] messages) throws MessagingException
{
}

View file

@ -4,18 +4,25 @@ package com.android.email.mail;
import com.android.email.mail.transport.SmtpTransport;
import com.android.email.mail.transport.WebDavTransport;
public abstract class Transport {
public abstract class Transport
{
protected static final int SOCKET_CONNECT_TIMEOUT = 10000;
// RFC 1047
protected static final int SOCKET_READ_TIMEOUT = 300000;
public synchronized static Transport getInstance(String uri) throws MessagingException {
if (uri.startsWith("smtp")) {
public synchronized static Transport getInstance(String uri) throws MessagingException
{
if (uri.startsWith("smtp"))
{
return new SmtpTransport(uri);
} else if (uri.startsWith("webdav")) {
return new WebDavTransport(uri);
} else {
}
else if (uri.startsWith("webdav"))
{
return new WebDavTransport(uri);
}
else
{
throw new MessagingException("Unable to locate an applicable Transport for " + uri);
}
}

View file

@ -24,38 +24,47 @@ import com.android.email.mail.MessagingException;
* and writeTo one time. After writeTo is called, or the InputStream returned from
* getInputStream is closed the file is deleted and the Body should be considered disposed of.
*/
public class BinaryTempFileBody implements Body {
public class BinaryTempFileBody implements Body
{
private static File mTempDirectory;
private File mFile;
public static void setTempDirectory(File tempDirectory) {
public static void setTempDirectory(File tempDirectory)
{
mTempDirectory = tempDirectory;
}
public BinaryTempFileBody() throws IOException {
if (mTempDirectory == null) {
public BinaryTempFileBody() throws IOException
{
if (mTempDirectory == null)
{
throw new
RuntimeException("setTempDirectory has not been called on BinaryTempFileBody!");
RuntimeException("setTempDirectory has not been called on BinaryTempFileBody!");
}
}
public OutputStream getOutputStream() throws IOException {
public OutputStream getOutputStream() throws IOException
{
mFile = File.createTempFile("body", null, mTempDirectory);
mFile.deleteOnExit();
return new FileOutputStream(mFile);
}
public InputStream getInputStream() throws MessagingException {
try {
public InputStream getInputStream() throws MessagingException
{
try
{
return new BinaryTempFileBodyInputStream(new FileInputStream(mFile));
}
catch (IOException ioe) {
catch (IOException ioe)
{
throw new MessagingException("Unable to open body", ioe);
}
}
public void writeTo(OutputStream out) throws IOException, MessagingException {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
InputStream in = getInputStream();
Base64OutputStream base64Out = new Base64OutputStream(out);
IOUtils.copy(in, base64Out);
@ -63,13 +72,16 @@ public class BinaryTempFileBody implements Body {
mFile.delete();
}
class BinaryTempFileBodyInputStream extends FilterInputStream {
public BinaryTempFileBodyInputStream(InputStream in) {
class BinaryTempFileBodyInputStream extends FilterInputStream
{
public BinaryTempFileBodyInputStream(InputStream in)
{
super(in);
}
@Override
public void close() throws IOException {
public void close() throws IOException
{
super.close();
mFile.delete();
}

View file

@ -14,61 +14,76 @@ import com.android.email.mail.MessagingException;
* TODO this is a close approximation of Message, need to update along with
* Message.
*/
public class MimeBodyPart extends BodyPart {
public class MimeBodyPart extends BodyPart
{
protected MimeHeader mHeader = new MimeHeader();
protected Body mBody;
protected int mSize;
public MimeBodyPart() throws MessagingException {
public MimeBodyPart() throws MessagingException
{
this(null);
}
public MimeBodyPart(Body body) throws MessagingException {
public MimeBodyPart(Body body) throws MessagingException
{
this(body, null);
}
public MimeBodyPart(Body body, String mimeType) throws MessagingException {
if (mimeType != null) {
public MimeBodyPart(Body body, String mimeType) throws MessagingException
{
if (mimeType != null)
{
addHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
}
setBody(body);
}
protected String getFirstHeader(String name) throws MessagingException {
protected String getFirstHeader(String name) throws MessagingException
{
return mHeader.getFirstHeader(name);
}
public void addHeader(String name, String value) throws MessagingException {
public void addHeader(String name, String value) throws MessagingException
{
mHeader.addHeader(name, value);
}
public void setHeader(String name, String value) throws MessagingException {
public void setHeader(String name, String value) throws MessagingException
{
mHeader.setHeader(name, value);
}
public String[] getHeader(String name) throws MessagingException {
public String[] getHeader(String name) throws MessagingException
{
return mHeader.getHeader(name);
}
public void removeHeader(String name) throws MessagingException {
public void removeHeader(String name) throws MessagingException
{
mHeader.removeHeader(name);
}
public Body getBody() throws MessagingException {
public Body getBody() throws MessagingException
{
return mBody;
}
public void setBody(Body body) throws MessagingException {
public void setBody(Body body) throws MessagingException
{
this.mBody = body;
if (body instanceof com.android.email.mail.Multipart) {
if (body instanceof com.android.email.mail.Multipart)
{
com.android.email.mail.Multipart multipart = ((com.android.email.mail.Multipart)body);
multipart.setParent(this);
setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
}
else if (body instanceof TextBody) {
else if (body instanceof TextBody)
{
String contentType = String.format("%s;\n charset=utf-8", getMimeType());
String name = MimeUtility.getHeaderParameter(getContentType(), "name");
if (name != null) {
if (name != null)
{
contentType += String.format(";\n name=\"%s\"", name);
}
setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
@ -80,45 +95,58 @@ public class MimeBodyPart extends BodyPart {
}
}
public String getContentType() throws MessagingException {
public String getContentType() throws MessagingException
{
String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
if (contentType == null) {
if (contentType == null)
{
return "text/plain";
} else {
}
else
{
return contentType.toLowerCase();
}
}
public String getDisposition() throws MessagingException {
public String getDisposition() throws MessagingException
{
String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
if (contentDisposition == null) {
if (contentDisposition == null)
{
return null;
} else {
}
else
{
return contentDisposition;
}
}
public String getMimeType() throws MessagingException {
public String getMimeType() throws MessagingException
{
return MimeUtility.getHeaderParameter(getContentType(), null);
}
public boolean isMimeType(String mimeType) throws MessagingException {
public boolean isMimeType(String mimeType) throws MessagingException
{
return getMimeType().equals(mimeType);
}
public int getSize() throws MessagingException {
public int getSize() throws MessagingException
{
return mSize;
}
/**
* Write the MimeMessage out in MIME format.
*/
public void writeTo(OutputStream out) throws IOException, MessagingException {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
mHeader.writeTo(out);
writer.write("\r\n");
writer.flush();
if (mBody != null) {
if (mBody != null)
{
mBody.writeTo(out);
}
}

View file

@ -13,7 +13,8 @@ import com.android.email.Utility;
import com.android.email.mail.MessagingException;
import org.apache.james.mime4j.codec.EncoderUtil;
public class MimeHeader {
public class MimeHeader
{
/**
* Application specific header that contains Store specific information about an attachment.
* In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later
@ -30,7 +31,8 @@ public class MimeHeader {
/**
* Fields that should be omitted when writing the header using writeTo()
*/
private static final String[] writeOmitFields = {
private static final String[] writeOmitFields =
{
// HEADER_ANDROID_ATTACHMENT_DOWNLOADED,
// HEADER_ANDROID_ATTACHMENT_ID,
HEADER_ANDROID_ATTACHMENT_STORE_DATA
@ -38,24 +40,30 @@ public class MimeHeader {
protected ArrayList<Field> mFields = new ArrayList<Field>();
public void clear() {
public void clear()
{
mFields.clear();
}
public String getFirstHeader(String name) {
public String getFirstHeader(String name)
{
String[] header = getHeader(name);
if (header == null) {
if (header == null)
{
return null;
}
return header[0];
}
public void addHeader(String name, String value) {
public void addHeader(String name, String value)
{
mFields.add(new Field(name, MimeUtility.foldAndEncode(value)));
}
public void setHeader(String name, String value) {
if (name == null || value == null) {
public void setHeader(String name, String value)
{
if (name == null || value == null)
{
return;
}
removeHeader(name);
@ -65,46 +73,58 @@ public class MimeHeader {
public List<String> getHeaderNames()
{
ArrayList<String> names = new ArrayList<String>();
for (Field field : mFields) {
for (Field field : mFields)
{
names.add(field.name);
}
return names;
}
public String[] getHeader(String name) {
public String[] getHeader(String name)
{
ArrayList<String> values = new ArrayList<String>();
for (Field field : mFields) {
if (field.name.equalsIgnoreCase(name)) {
for (Field field : mFields)
{
if (field.name.equalsIgnoreCase(name))
{
values.add(field.value);
}
}
if (values.size() == 0) {
if (values.size() == 0)
{
return null;
}
return values.toArray(new String[] {});
}
public void removeHeader(String name) {
public void removeHeader(String name)
{
ArrayList<Field> removeFields = new ArrayList<Field>();
for (Field field : mFields) {
if (field.name.equalsIgnoreCase(name)) {
for (Field field : mFields)
{
if (field.name.equalsIgnoreCase(name))
{
removeFields.add(field);
}
}
mFields.removeAll(removeFields);
}
public void writeTo(OutputStream out) throws IOException, MessagingException {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
for (Field field : mFields) {
if (!Utility.arrayContains(writeOmitFields, field.name)) {
for (Field field : mFields)
{
if (!Utility.arrayContains(writeOmitFields, field.name))
{
String v = field.value;
if (hasToBeEncoded(v)) {
if (hasToBeEncoded(v))
{
v = EncoderUtil.encodeEncodedWord(
field.value,
EncoderUtil.Usage.WORD_ENTITY
);
field.value,
EncoderUtil.Usage.WORD_ENTITY
);
}
writer.write(field.name + ": " + v + "\r\n");
@ -114,11 +134,15 @@ public class MimeHeader {
}
// encode non printable characters except LF/CR codes.
public boolean hasToBeEncoded(String text) {
for (int i = 0; i < text.length(); i++) {
public boolean hasToBeEncoded(String text)
{
for (int i = 0; i < text.length(); i++)
{
char c = text.charAt(i);
if (c < 0x20 || 0x7e < c) { // non printable
if (c != 0x0a && c != 0x0d) { // non LF/CR
if (c < 0x20 || 0x7e < c) // non printable
{
if (c != 0x0a && c != 0x0d) // non LF/CR
{
return true;
}
}
@ -127,12 +151,14 @@ public class MimeHeader {
return false;
}
class Field {
class Field
{
String name;
String value;
public Field(String name, String value) {
public Field(String name, String value)
{
this.name = name;
this.value = value;
}

View file

@ -33,38 +33,42 @@ import com.android.email.mail.Part;
* An implementation of Message that stores all of it's metadata in RFC 822 and
* RFC 2045 style headers.
*/
public class MimeMessage extends Message {
public class MimeMessage extends Message
{
protected MimeHeader mHeader = new MimeHeader();
protected Address[] mFrom;
protected Address[] mTo;
protected Address[] mCc;
protected Address[] mBcc;
protected Address[] mReplyTo;
protected String mMessageId;
protected String[] mReferences;
protected String[] mInReplyTo;
protected Date mSentDate;
protected SimpleDateFormat mDateFormat;
protected Body mBody;
protected int mSize;
public MimeMessage() {
public MimeMessage()
{
addHeader("Message-ID", generateMessageId());
}
private String generateMessageId() {
private String generateMessageId()
{
StringBuffer sb = new StringBuffer();
sb.append("<");
for (int i = 0; i < 24; i++) {
for (int i = 0; i < 24; i++)
{
sb.append(Integer.toString((int)(Math.random() * 35), 36));
}
sb.append(".");
sb.append(Long.toString(System.currentTimeMillis()));
sb.append("@email.android.com>");
return sb.toString();
}
@ -75,24 +79,26 @@ public class MimeMessage extends Message {
* @throws IOException
* @throws MessagingException
*/
public MimeMessage(InputStream in) throws IOException, MessagingException {
public MimeMessage(InputStream in) throws IOException, MessagingException
{
parse(in);
}
protected void parse(InputStream in) throws IOException, MessagingException {
protected void parse(InputStream in) throws IOException, MessagingException
{
mHeader.clear();
mFrom = null;
mTo = null;
mCc = null;
mBcc = null;
mReplyTo = null;
mMessageId = null;
mReferences = null;
mInReplyTo = null;
mSentDate = null;
mBody = null;
MimeStreamParser parser = new MimeStreamParser();
@ -100,17 +106,23 @@ public class MimeMessage extends Message {
parser.parse(new EOLConvertingInputStream(in));
}
public Date getReceivedDate() throws MessagingException {
public Date getReceivedDate() throws MessagingException
{
return null;
}
public Date getSentDate() throws MessagingException {
if (mSentDate == null) {
try {
public Date getSentDate() throws MessagingException
{
if (mSentDate == null)
{
try
{
DateTimeField field = (DateTimeField)Field.parse("Date: "
+ MimeUtility.unfoldAndDecode(getFirstHeader("Date")));
+ MimeUtility.unfoldAndDecode(getFirstHeader("Date")));
mSentDate = field.getDate();
} catch (Exception e) {
}
catch (Exception e)
{
}
}
@ -125,46 +137,60 @@ public class MimeMessage extends Message {
* @param sentDate
* @throws com.android.email.mail.MessagingException
*/
public void addSentDate(Date sentDate) throws MessagingException {
if (mDateFormat == null) {
public void addSentDate(Date sentDate) throws MessagingException
{
if (mDateFormat == null)
{
mDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
}
addHeader("Date", mDateFormat.format(sentDate));
setInternalSentDate(sentDate);
}
public void setSentDate(Date sentDate) throws MessagingException {
public void setSentDate(Date sentDate) throws MessagingException
{
removeHeader("Date");
addSentDate(sentDate);
}
public void setInternalSentDate(Date sentDate) throws MessagingException {
public void setInternalSentDate(Date sentDate) throws MessagingException
{
this.mSentDate = sentDate;
}
public String getContentType() throws MessagingException {
public String getContentType() throws MessagingException
{
String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
if (contentType == null) {
if (contentType == null)
{
return "text/plain";
} else {
}
else
{
return contentType.toLowerCase();
}
}
public String getDisposition() throws MessagingException {
public String getDisposition() throws MessagingException
{
String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
if (contentDisposition == null) {
if (contentDisposition == null)
{
return null;
} else {
}
else
{
return contentDisposition;
}
}
public String getMimeType() throws MessagingException {
public String getMimeType() throws MessagingException
{
return MimeUtility.getHeaderParameter(getContentType(), null);
}
public int getSize() throws MessagingException {
public int getSize() throws MessagingException
{
return mSize;
}
@ -172,53 +198,81 @@ public class MimeMessage extends Message {
* Returns a list of the given recipient type from this message. If no addresses are
* found the method returns an empty array.
*/
public Address[] getRecipients(RecipientType type) throws MessagingException {
if (type == RecipientType.TO) {
if (mTo == null) {
public Address[] getRecipients(RecipientType type) throws MessagingException
{
if (type == RecipientType.TO)
{
if (mTo == null)
{
mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To")));
}
return mTo;
} else if (type == RecipientType.CC) {
if (mCc == null) {
}
else if (type == RecipientType.CC)
{
if (mCc == null)
{
mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC")));
}
return mCc;
} else if (type == RecipientType.BCC) {
if (mBcc == null) {
}
else if (type == RecipientType.BCC)
{
if (mBcc == null)
{
mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC")));
}
return mBcc;
} else {
}
else
{
throw new MessagingException("Unrecognized recipient type.");
}
}
public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException {
if (type == RecipientType.TO) {
if (addresses == null || addresses.length == 0) {
public void setRecipients(RecipientType type, Address[] addresses) throws MessagingException
{
if (type == RecipientType.TO)
{
if (addresses == null || addresses.length == 0)
{
removeHeader("To");
this.mTo = null;
} else {
}
else
{
setHeader("To", Address.toEncodedString(addresses));
this.mTo = addresses;
}
} else if (type == RecipientType.CC) {
if (addresses == null || addresses.length == 0) {
}
else if (type == RecipientType.CC)
{
if (addresses == null || addresses.length == 0)
{
removeHeader("CC");
this.mCc = null;
} else {
}
else
{
setHeader("CC", Address.toEncodedString(addresses));
this.mCc = addresses;
}
} else if (type == RecipientType.BCC) {
if (addresses == null || addresses.length == 0) {
}
else if (type == RecipientType.BCC)
{
if (addresses == null || addresses.length == 0)
{
removeHeader("BCC");
this.mBcc = null;
} else {
}
else
{
setHeader("BCC", Address.toEncodedString(addresses));
this.mBcc = addresses;
}
} else {
}
else
{
throw new MessagingException("Unrecognized recipient type.");
}
}
@ -226,18 +280,23 @@ public class MimeMessage extends Message {
/**
* Returns the unfolded, decoded value of the Subject header.
*/
public String getSubject() throws MessagingException {
public String getSubject() throws MessagingException
{
return MimeUtility.unfoldAndDecode(getFirstHeader("Subject"));
}
public void setSubject(String subject) throws MessagingException {
public void setSubject(String subject) throws MessagingException
{
setHeader("Subject", subject);
}
public Address[] getFrom() throws MessagingException {
if (mFrom == null) {
public Address[] getFrom() throws MessagingException
{
if (mFrom == null)
{
String list = MimeUtility.unfold(getFirstHeader("From"));
if (list == null || list.length() == 0) {
if (list == null || list.length() == 0)
{
list = MimeUtility.unfold(getFirstHeader("Sender"));
}
mFrom = Address.parse(list);
@ -245,96 +304,123 @@ public class MimeMessage extends Message {
return mFrom;
}
public void setFrom(Address from) throws MessagingException {
if (from != null) {
public void setFrom(Address from) throws MessagingException
{
if (from != null)
{
setHeader("From", from.toEncodedString());
this.mFrom = new Address[] {
from
};
} else {
this.mFrom = new Address[]
{
from
};
}
else
{
this.mFrom = null;
}
}
public Address[] getReplyTo() throws MessagingException {
if (mReplyTo == null) {
public Address[] getReplyTo() throws MessagingException
{
if (mReplyTo == null)
{
mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to")));
}
return mReplyTo;
}
public void setReplyTo(Address[] replyTo) throws MessagingException {
if (replyTo == null || replyTo.length == 0) {
public void setReplyTo(Address[] replyTo) throws MessagingException
{
if (replyTo == null || replyTo.length == 0)
{
removeHeader("Reply-to");
mReplyTo = null;
} else {
}
else
{
setHeader("Reply-to", Address.toEncodedString(replyTo));
mReplyTo = replyTo;
}
}
public String getMessageId() throws MessagingException {
if (mMessageId == null) {
mMessageId = getFirstHeader("Message-ID");
}
return mMessageId;
public String getMessageId() throws MessagingException
{
if (mMessageId == null)
{
mMessageId = getFirstHeader("Message-ID");
}
return mMessageId;
}
public void setInReplyTo(String inReplyTo) throws MessagingException {
setHeader("In-Reply-To", inReplyTo);
public void setInReplyTo(String inReplyTo) throws MessagingException
{
setHeader("In-Reply-To", inReplyTo);
}
public String[] getReferences() throws MessagingException {
if (mReferences == null) {
mReferences = getHeader("References");
}
return mReferences;
public String[] getReferences() throws MessagingException
{
if (mReferences == null)
{
mReferences = getHeader("References");
}
return mReferences;
}
public void setReferences(String references) throws MessagingException {
setHeader("References", references);
public void setReferences(String references) throws MessagingException
{
setHeader("References", references);
}
public void saveChanges() throws MessagingException {
public void saveChanges() throws MessagingException
{
throw new MessagingException("saveChanges not yet implemented");
}
public Body getBody() throws MessagingException {
public Body getBody() throws MessagingException
{
return mBody;
}
public void setBody(Body body) throws MessagingException {
public void setBody(Body body) throws MessagingException
{
this.mBody = body;
if (body instanceof com.android.email.mail.Multipart) {
if (body instanceof com.android.email.mail.Multipart)
{
com.android.email.mail.Multipart multipart = ((com.android.email.mail.Multipart)body);
multipart.setParent(this);
setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
setHeader("MIME-Version", "1.0");
}
else if (body instanceof TextBody) {
else if (body instanceof TextBody)
{
setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8",
getMimeType()));
getMimeType()));
setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
}
}
protected String getFirstHeader(String name) {
protected String getFirstHeader(String name)
{
return mHeader.getFirstHeader(name);
}
public void addHeader(String name, String value) {
public void addHeader(String name, String value)
{
mHeader.addHeader(name, value);
}
public void setHeader(String name, String value) {
public void setHeader(String name, String value)
{
mHeader.setHeader(name, value);
}
public String[] getHeader(String name) {
public String[] getHeader(String name)
{
return mHeader.getHeader(name);
}
public void removeHeader(String name) {
public void removeHeader(String name)
{
mHeader.removeHeader(name);
}
@ -343,140 +429,183 @@ public class MimeMessage extends Message {
return mHeader.getHeaderNames();
}
public void writeTo(OutputStream out) throws IOException, MessagingException {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
mHeader.writeTo(out);
writer.write("\r\n");
writer.flush();
if (mBody != null) {
if (mBody != null)
{
mBody.writeTo(out);
}
}
public InputStream getInputStream() throws MessagingException {
public InputStream getInputStream() throws MessagingException
{
return null;
}
class MimeMessageBuilder implements ContentHandler {
class MimeMessageBuilder implements ContentHandler
{
private Stack stack = new Stack();
public MimeMessageBuilder() {
public MimeMessageBuilder()
{
}
private void expect(Class c) {
if (!c.isInstance(stack.peek())) {
private void expect(Class c)
{
if (!c.isInstance(stack.peek()))
{
throw new IllegalStateException("Internal stack error: " + "Expected '"
+ c.getName() + "' found '" + stack.peek().getClass().getName() + "'");
+ c.getName() + "' found '" + stack.peek().getClass().getName() + "'");
}
}
public void startMessage() {
if (stack.isEmpty()) {
public void startMessage()
{
if (stack.isEmpty())
{
stack.push(MimeMessage.this);
} else {
}
else
{
expect(Part.class);
try {
try
{
MimeMessage m = new MimeMessage();
((Part)stack.peek()).setBody(m);
stack.push(m);
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
}
public void endMessage() {
public void endMessage()
{
expect(MimeMessage.class);
stack.pop();
}
public void startHeader() {
public void startHeader()
{
expect(Part.class);
}
public void field(String fieldData) {
public void field(String fieldData)
{
expect(Part.class);
try {
try
{
String[] tokens = fieldData.split(":", 2);
((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim());
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
public void endHeader() {
public void endHeader()
{
expect(Part.class);
}
public void startMultipart(BodyDescriptor bd) {
public void startMultipart(BodyDescriptor bd)
{
expect(Part.class);
Part e = (Part)stack.peek();
try {
try
{
MimeMultipart multiPart = new MimeMultipart(e.getContentType());
e.setBody(multiPart);
stack.push(multiPart);
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
public void body(BodyDescriptor bd, InputStream in) throws IOException {
public void body(BodyDescriptor bd, InputStream in) throws IOException
{
expect(Part.class);
Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding());
try {
try
{
((Part)stack.peek()).setBody(body);
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
public void endMultipart() {
public void endMultipart()
{
stack.pop();
}
public void startBodyPart() {
public void startBodyPart()
{
expect(MimeMultipart.class);
try {
try
{
MimeBodyPart bodyPart = new MimeBodyPart();
((MimeMultipart)stack.peek()).addBodyPart(bodyPart);
stack.push(bodyPart);
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
public void endBodyPart() {
public void endBodyPart()
{
expect(BodyPart.class);
stack.pop();
}
public void epilogue(InputStream is) throws IOException {
public void epilogue(InputStream is) throws IOException
{
expect(MimeMultipart.class);
StringBuffer sb = new StringBuffer();
int b;
while ((b = is.read()) != -1) {
while ((b = is.read()) != -1)
{
sb.append((char)b);
}
// ((Multipart) stack.peek()).setEpilogue(sb.toString());
}
public void preamble(InputStream is) throws IOException {
public void preamble(InputStream is) throws IOException
{
expect(MimeMultipart.class);
StringBuffer sb = new StringBuffer();
int b;
while ((b = is.read()) != -1) {
while ((b = is.read()) != -1)
{
sb.append((char)b);
}
try {
try
{
((MimeMultipart)stack.peek()).setPreamble(sb.toString());
} catch (MessagingException me) {
}
catch (MessagingException me)
{
throw new Error(me);
}
}
public void raw(InputStream is) throws IOException {
public void raw(InputStream is) throws IOException
{
throw new UnsupportedOperationException("Not supported");
}
}

View file

@ -11,7 +11,8 @@ import com.android.email.mail.BodyPart;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Multipart;
public class MimeMultipart extends Multipart {
public class MimeMultipart extends Multipart
{
protected String mPreamble;
protected String mContentType;
@ -20,76 +21,93 @@ public class MimeMultipart extends Multipart {
protected String mSubType;
public MimeMultipart() throws MessagingException {
public MimeMultipart() throws MessagingException
{
mBoundary = generateBoundary();
setSubType("mixed");
}
public MimeMultipart(String contentType) throws MessagingException {
public MimeMultipart(String contentType) throws MessagingException
{
this.mContentType = contentType;
try {
try
{
mSubType = MimeUtility.getHeaderParameter(contentType, null).split("/")[1];
mBoundary = MimeUtility.getHeaderParameter(contentType, "boundary");
if (mBoundary == null) {
if (mBoundary == null)
{
throw new MessagingException("MultiPart does not contain boundary: " + contentType);
}
} catch (Exception e) {
}
catch (Exception e)
{
throw new MessagingException(
"Invalid MultiPart Content-Type; must contain subtype and boundary. ("
+ contentType + ")", e);
"Invalid MultiPart Content-Type; must contain subtype and boundary. ("
+ contentType + ")", e);
}
}
public String generateBoundary() {
public String generateBoundary()
{
StringBuffer sb = new StringBuffer();
sb.append("----");
for (int i = 0; i < 30; i++) {
for (int i = 0; i < 30; i++)
{
sb.append(Integer.toString((int)(Math.random() * 35), 36));
}
return sb.toString().toUpperCase();
}
public String getPreamble() throws MessagingException {
public String getPreamble() throws MessagingException
{
return mPreamble;
}
public void setPreamble(String preamble) throws MessagingException {
public void setPreamble(String preamble) throws MessagingException
{
this.mPreamble = preamble;
}
public String getContentType() throws MessagingException {
public String getContentType() throws MessagingException
{
return mContentType;
}
public void setSubType(String subType) throws MessagingException {
public void setSubType(String subType) throws MessagingException
{
this.mSubType = subType;
mContentType = String.format("multipart/%s; boundary=\"%s\"", subType, mBoundary);
}
public void writeTo(OutputStream out) throws IOException, MessagingException {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
if (mPreamble != null) {
if (mPreamble != null)
{
writer.write(mPreamble + "\r\n");
}
if(mParts.size() == 0){
if (mParts.size() == 0)
{
writer.write("--" + mBoundary + "\r\n");
}
for (int i = 0, count = mParts.size(); i < count; i++) {
for (int i = 0, count = mParts.size(); i < count; i++)
{
BodyPart bodyPart = (BodyPart)mParts.get(i);
writer.write("--" + mBoundary + "\r\n");
writer.flush();
bodyPart.writeTo(out);
writer.write("\r\n");
}
writer.write("--" + mBoundary + "--\r\n");
writer.flush();
}
public InputStream getInputStream() throws MessagingException {
public InputStream getInputStream() throws MessagingException
{
return null;
}
}

View file

@ -26,29 +26,36 @@ import com.android.email.mail.MessagingException;
import com.android.email.mail.Multipart;
import com.android.email.mail.Part;
public class MimeUtility {
public class MimeUtility
{
public static String unfold(String s) {
if (s == null) {
public static String unfold(String s)
{
if (s == null)
{
return null;
}
return s.replaceAll("\r|\n", "");
}
public static String decode(String s) {
if (s == null) {
public static String decode(String s)
{
if (s == null)
{
return null;
}
return DecoderUtil.decodeEncodedWords(s);
}
public static String unfoldAndDecode(String s) {
public static String unfoldAndDecode(String s)
{
return decode(unfold(s));
}
// TODO implement proper foldAndEncode
public static String foldAndEncode(String s) {
public static String foldAndEncode(String s)
{
return s;
}
@ -63,22 +70,29 @@ public class MimeUtility {
* @param name
* @return
*/
public static String getHeaderParameter(String header, String name) {
if (header == null) {
public static String getHeaderParameter(String header, String name)
{
if (header == null)
{
return null;
}
header = header.replaceAll("\r|\n", "");
String[] parts = header.split(";");
if (name == null) {
if (name == null)
{
return parts[0];
}
for (String part : parts) {
if (part.trim().toLowerCase().startsWith(name.toLowerCase())) {
for (String part : parts)
{
if (part.trim().toLowerCase().startsWith(name.toLowerCase()))
{
String parameter = part.split("=", 2)[1].trim();
if (parameter.startsWith("\"") && parameter.endsWith("\"")) {
if (parameter.startsWith("\"") && parameter.endsWith("\""))
{
return parameter.substring(1, parameter.length() - 1);
}
else {
else
{
return parameter;
}
}
@ -87,38 +101,50 @@ public class MimeUtility {
}
public static Part findFirstPartByMimeType(Part part, String mimeType)
throws MessagingException {
if (part.getBody() instanceof Multipart) {
throws MessagingException
{
if (part.getBody() instanceof Multipart)
{
Multipart multipart = (Multipart)part.getBody();
for (int i = 0, count = multipart.getCount(); i < count; i++) {
for (int i = 0, count = multipart.getCount(); i < count; i++)
{
BodyPart bodyPart = multipart.getBodyPart(i);
Part ret = findFirstPartByMimeType(bodyPart, mimeType);
if (ret != null) {
if (ret != null)
{
return ret;
}
}
}
else if (part.getMimeType().equalsIgnoreCase(mimeType)) {
else if (part.getMimeType().equalsIgnoreCase(mimeType))
{
return part;
}
return null;
}
public static Part findPartByContentId(Part part, String contentId) throws Exception {
if (part.getBody() instanceof Multipart) {
public static Part findPartByContentId(Part part, String contentId) throws Exception
{
if (part.getBody() instanceof Multipart)
{
Multipart multipart = (Multipart)part.getBody();
for (int i = 0, count = multipart.getCount(); i < count; i++) {
for (int i = 0, count = multipart.getCount(); i < count; i++)
{
BodyPart bodyPart = multipart.getBodyPart(i);
Part ret = findPartByContentId(bodyPart, contentId);
if (ret != null) {
if (ret != null)
{
return ret;
}
}
}
String[] header = part.getHeader("Content-ID");
if (header != null) {
for (String s : header) {
if (s.equals(contentId)) {
if (header != null)
{
for (String s : header)
{
if (s.equals(contentId))
{
return part;
}
}
@ -133,19 +159,25 @@ public class MimeUtility {
* @return
* @throws IOException
*/
public static String getTextFromPart(Part part) {
Charset mCharsetConverter;
public static String getTextFromPart(Part part)
{
Charset mCharsetConverter;
try {
if (part != null && part.getBody() != null) {
try
{
if (part != null && part.getBody() != null)
{
Body body = part.getBody();
if (body instanceof TextBody) {
if (body instanceof TextBody)
{
return ((TextBody)body).getText();
}
else {
else
{
InputStream in = part.getBody().getInputStream();
String mimeType = part.getMimeType();
if (mimeType != null && MimeUtility.mimeTypeMatches(mimeType, "text/*")) {
if (mimeType != null && MimeUtility.mimeTypeMatches(mimeType, "text/*"))
{
/*
* Now we read the part into a buffer for further processing. Because
* the stream is now wrapped we'll remove any transfer encoding at this point.
@ -161,20 +193,23 @@ public class MimeUtility {
/*
* We've got a text part, so let's see if it needs to be processed further.
*/
if (charset != null) {
if (charset != null)
{
/*
* See if there is conversion from the MIME charset to the Java one.
*/
mCharsetConverter = Charset.forName(charset);
charset = mCharsetConverter.name();
}
if (charset != null) {
if (charset != null)
{
/*
* We've got a charset encoding, so decode using it.
*/
return new String(bytes, 0, bytes.length, charset);
}
else {
else
{
/*
* No encoding, so use us-ascii, which is the standard.
*/
@ -184,7 +219,8 @@ public class MimeUtility {
}
}//if text body
}
catch (Exception e) {
catch (Exception e)
{
/*
* If we are not able to process the body there's nothing we can do about it. Return
* null and let the upper layers handle the missing content.
@ -201,10 +237,11 @@ public class MimeUtility {
* * /*.
* @return
*/
public static boolean mimeTypeMatches(String mimeType, String matchAgainst) {
Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"),
Pattern.CASE_INSENSITIVE);
return p.matcher(mimeType).matches();
public static boolean mimeTypeMatches(String mimeType, String matchAgainst)
{
Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"),
Pattern.CASE_INSENSITIVE);
return p.matcher(mimeType).matches();
}
/**
@ -214,11 +251,14 @@ public class MimeUtility {
* as image/* or * /*.
* @return
*/
public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst) {
for (String matchType : matchAgainst) {
if (mimeTypeMatches(mimeType, matchType)) {
return true;
}
public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst)
{
for (String matchType : matchAgainst)
{
if (mimeTypeMatches(mimeType, matchType))
{
return true;
}
}
return false;
}
@ -227,17 +267,21 @@ public class MimeUtility {
* Removes any content transfer encoding from the stream and returns a Body.
*/
public static Body decodeBody(InputStream in, String contentTransferEncoding)
throws IOException {
throws IOException
{
/*
* We'll remove any transfer encoding by wrapping the stream.
*/
if (contentTransferEncoding != null) {
if (contentTransferEncoding != null)
{
contentTransferEncoding =
MimeUtility.getHeaderParameter(contentTransferEncoding, null);
if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) {
if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding))
{
in = new QuotedPrintableInputStream(in);
}
else if ("base64".equalsIgnoreCase(contentTransferEncoding)) {
else if ("base64".equalsIgnoreCase(contentTransferEncoding))
{
in = new Base64InputStream(in);
}
}
@ -260,11 +304,13 @@ public class MimeUtility {
* @throws MessagingException
*/
public static void collectParts(Part part, ArrayList<Part> viewables,
ArrayList<Part> attachments) throws MessagingException {
ArrayList<Part> attachments) throws MessagingException
{
String disposition = part.getDisposition();
String dispositionType = null;
String dispositionFilename = null;
if (disposition != null) {
if (disposition != null)
{
dispositionType = MimeUtility.getHeaderParameter(disposition, null);
dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename");
}
@ -273,17 +319,19 @@ public class MimeUtility {
* A best guess that this part is intended to be an attachment and not inline.
*/
boolean attachment = ("attachment".equalsIgnoreCase(dispositionType))
|| (dispositionFilename != null)
&& (!"inline".equalsIgnoreCase(dispositionType));
|| (dispositionFilename != null)
&& (!"inline".equalsIgnoreCase(dispositionType));
/*
* If the part is Multipart but not alternative it's either mixed or
* something we don't know about, which means we treat it as mixed
* per the spec. We just process it's pieces recursively.
*/
if (part.getBody() instanceof Multipart) {
if (part.getBody() instanceof Multipart)
{
Multipart mp = (Multipart)part.getBody();
for (int i = 0; i < mp.getCount(); i++) {
for (int i = 0; i < mp.getCount(); i++)
{
collectParts(mp.getBodyPart(i), viewables, attachments);
}
}
@ -291,7 +339,8 @@ public class MimeUtility {
* If the part is an embedded message we just continue to process
* it, pulling any viewables or attachments into the running list.
*/
else if (part.getBody() instanceof Message) {
else if (part.getBody() instanceof Message)
{
Message message = (Message)part.getBody();
collectParts(message, viewables, attachments);
}
@ -299,20 +348,23 @@ public class MimeUtility {
* If the part is HTML and it got this far it's part of a mixed (et
* al) and should be rendered inline.
*/
else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/html"))) {
else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/html")))
{
viewables.add(part);
}
/*
* If the part is plain text and it got this far it's part of a
* mixed (et al) and should be rendered inline.
*/
else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/plain"))) {
else if ((!attachment) && (part.getMimeType().equalsIgnoreCase("text/plain")))
{
viewables.add(part);
}
/*
* Finally, if it's nothing else we will include it as an attachment.
*/
else {
else
{
attachments.add(part);
}
}

View file

@ -12,43 +12,53 @@ import com.android.email.codec.binary.Base64;
import com.android.email.mail.Body;
import com.android.email.mail.MessagingException;
public class TextBody implements Body {
public class TextBody implements Body
{
String mBody;
public TextBody(String body) {
public TextBody(String body)
{
this.mBody = body;
}
public void writeTo(OutputStream out) throws IOException, MessagingException {
if (mBody!=null) {
public void writeTo(OutputStream out) throws IOException, MessagingException
{
if (mBody!=null)
{
byte[] bytes = mBody.getBytes("UTF-8");
out.write(Base64.encodeBase64Chunked(bytes));
}
}
/**
* Get the text of the body in it's unencoded format.
* Get the text of the body in it's unencoded format.
* @return
*/
public String getText() {
public String getText()
{
return mBody;
}
/**
* Returns an InputStream that reads this body's text in UTF-8 format.
*/
public InputStream getInputStream() throws MessagingException {
try {
public InputStream getInputStream() throws MessagingException
{
try
{
byte[] b;
if (mBody!=null) {
if (mBody!=null)
{
b = mBody.getBytes("UTF-8");
}
else {
else
{
b = new byte[0];
}
return new ByteArrayInputStream(b);
}
catch (UnsupportedEncodingException usee) {
catch (UnsupportedEncodingException usee)
{
return null;
}
}

View file

@ -20,15 +20,17 @@ import com.android.email.FixedLengthInputStream;
import com.android.email.PeekableInputStream;
import com.android.email.mail.MessagingException;
public class ImapResponseParser {
public class ImapResponseParser
{
SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
SimpleDateFormat badDateTimeFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss Z", Locale.US);
PeekableInputStream mIn;
InputStream mActiveLiteral;
public ImapResponseParser(PeekableInputStream in) {
public ImapResponseParser(PeekableInputStream in)
{
this.mIn = in;
}
@ -39,39 +41,51 @@ public class ImapResponseParser {
* @return
* @throws IOException
*/
public ImapResponse readResponse() throws IOException {
public ImapResponse readResponse() throws IOException
{
ImapResponse response = new ImapResponse();
if (mActiveLiteral != null) {
if (mActiveLiteral != null)
{
while (mActiveLiteral.read() != -1)
;
mActiveLiteral = null;
}
int ch = mIn.peek();
if (ch == '*') {
if (ch == '*')
{
parseUntaggedResponse();
readTokens(response);
} else if (ch == '+') {
}
else if (ch == '+')
{
response.mCommandContinuationRequested =
parseCommandContinuationRequest();
parseCommandContinuationRequest();
readTokens(response);
} else {
}
else
{
response.mTag = parseTaggedResponse();
readTokens(response);
}
if (Email.DEBUG) {
if (Email.DEBUG)
{
Log.v(Email.LOG_TAG, "<<< " + response.toString());
}
return response;
}
private void readTokens(ImapResponse response) throws IOException {
private void readTokens(ImapResponse response) throws IOException
{
response.clear();
Object token;
while ((token = readToken()) != null) {
if (response != null) {
while ((token = readToken()) != null)
{
if (response != null)
{
response.add(token);
}
if (mActiveLiteral != null) {
if (mActiveLiteral != null)
{
break;
}
}
@ -89,136 +103,192 @@ public class ImapResponseParser {
* tokens.
* @throws IOException
*/
public Object readToken() throws IOException {
while (true) {
public Object readToken() throws IOException
{
while (true)
{
Object token = parseToken();
if (token == null || !token.equals(")") || !token.equals("]")) {
if (token == null || !token.equals(")") || !token.equals("]"))
{
return token;
}
}
}
private Object parseToken() throws IOException {
if (mActiveLiteral != null) {
private Object parseToken() throws IOException
{
if (mActiveLiteral != null)
{
while (mActiveLiteral.read() != -1)
;
mActiveLiteral = null;
}
while (true) {
while (true)
{
int ch = mIn.peek();
if (ch == '(') {
if (ch == '(')
{
return parseList();
} else if (ch == '[') {
}
else if (ch == '[')
{
return parseSequence();
} else if (ch == ')') {
}
else if (ch == ')')
{
expect(')');
return ")";
} else if (ch == ']') {
expect(']');
return "]";
} else if (ch == '"') {
}
else if (ch == ']')
{
expect(']');
return "]";
}
else if (ch == '"')
{
return parseQuoted();
} else if (ch == '{') {
}
else if (ch == '{')
{
mActiveLiteral = parseLiteral();
return mActiveLiteral;
} else if (ch == ' ') {
}
else if (ch == ' ')
{
expect(' ');
} else if (ch == '\r') {
}
else if (ch == '\r')
{
expect('\r');
expect('\n');
return null;
} else if (ch == '\n') {
}
else if (ch == '\n')
{
expect('\n');
return null;
} else if (ch == '\t') {
expect('\t');
} else {
}
else if (ch == '\t')
{
expect('\t');
}
else
{
return parseAtom();
}
}
}
private boolean parseCommandContinuationRequest() throws IOException {
private boolean parseCommandContinuationRequest() throws IOException
{
expect('+');
expect(' ');
return true;
}
// * OK [UIDNEXT 175] Predicted next UID
private void parseUntaggedResponse() throws IOException {
private void parseUntaggedResponse() throws IOException
{
expect('*');
expect(' ');
}
// 3 OK [READ-WRITE] Select completed.
private String parseTaggedResponse() throws IOException {
private String parseTaggedResponse() throws IOException
{
String tag = readStringUntil(' ');
return tag;
}
private ImapList parseList() throws IOException {
private ImapList parseList() throws IOException
{
expect('(');
ImapList list = new ImapList();
Object token;
while (true) {
while (true)
{
token = parseToken();
if (token == null) {
if (token == null)
{
break;
} else if (token instanceof InputStream) {
list.add(token);
break;
} else if (token.equals(")")) {
break;
} else {
list.add(token);
}
}
return list;
}
private ImapList parseSequence() throws IOException {
expect('[');
ImapList list = new ImapList();
Object token;
while (true) {
token = parseToken();
if (token == null) {
break;
} else if (token instanceof InputStream) {
else if (token instanceof InputStream)
{
list.add(token);
break;
} else if (token.equals("]")) {
}
else if (token.equals(")"))
{
break;
} else {
}
else
{
list.add(token);
}
}
return list;
}
private String parseAtom() throws IOException {
private ImapList parseSequence() throws IOException
{
expect('[');
ImapList list = new ImapList();
Object token;
while (true)
{
token = parseToken();
if (token == null)
{
break;
}
else if (token instanceof InputStream)
{
list.add(token);
break;
}
else if (token.equals("]"))
{
break;
}
else
{
list.add(token);
}
}
return list;
}
private String parseAtom() throws IOException
{
StringBuffer sb = new StringBuffer();
int ch;
while (true) {
while (true)
{
ch = mIn.peek();
if (ch == -1) {
if (ch == -1)
{
throw new IOException("parseAtom(): end of stream reached");
} else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' ||
ch == '[' || ch == ']' ||
// docs claim that flags are \ atom but atom isn't supposed to
// contain
// * and some falgs contain *
// ch == '%' || ch == '*' ||
}
else if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' ||
ch == '[' || ch == ']' ||
// docs claim that flags are \ atom but atom isn't supposed to
// contain
// * and some falgs contain *
// ch == '%' || ch == '*' ||
// ch == '%' ||
// TODO probably should not allow \ and should recognize
// it as a flag instead
// ch == '"' || ch == '\' ||
ch == '"' || (ch >= 0x00 && ch <= 0x1f) || ch == 0x7f) {
if (sb.length() == 0) {
// TODO probably should not allow \ and should recognize
// it as a flag instead
// ch == '"' || ch == '\' ||
ch == '"' || (ch >= 0x00 && ch <= 0x1f) || ch == 0x7f)
{
if (sb.length() == 0)
{
throw new IOException(String.format("parseAtom(): (%04x %c)", (int)ch, ch));
}
return sb.toString();
} else {
}
else
{
sb.append((char)mIn.read());
}
}
@ -231,7 +301,8 @@ public class ImapResponseParser {
* @param mListener
* @throws IOException
*/
private InputStream parseLiteral() throws IOException {
private InputStream parseLiteral() throws IOException
{
expect('{');
int size = Integer.parseInt(readStringUntil('}'));
expect('\r');
@ -247,29 +318,37 @@ public class ImapResponseParser {
* @param mListener
* @throws IOException
*/
private String parseQuoted() throws IOException {
private String parseQuoted() throws IOException
{
expect('"');
return readStringUntil('"');
}
private String readStringUntil(char end) throws IOException {
private String readStringUntil(char end) throws IOException
{
StringBuffer sb = new StringBuffer();
int ch;
while ((ch = mIn.read()) != -1) {
if (ch == end) {
while ((ch = mIn.read()) != -1)
{
if (ch == end)
{
return sb.toString();
} else {
}
else
{
sb.append((char)ch);
}
}
throw new IOException("readQuotedString(): end of stream reached");
}
private int expect(char ch) throws IOException {
private int expect(char ch) throws IOException
{
int d;
if ((d = mIn.read()) != ch) {
if ((d = mIn.read()) != ch)
{
throw new IOException(String.format("Expected %04x (%c) but got %04x (%c)", (int)ch,
ch, d, (char)d));
ch, d, (char)d));
}
return d;
}
@ -278,92 +357,113 @@ public class ImapResponseParser {
* Represents an IMAP LIST response and is also the base class for the
* ImapResponse.
*/
public class ImapList extends ArrayList<Object> {
public ImapList getList(int index) {
public class ImapList extends ArrayList<Object>
{
public ImapList getList(int index)
{
return (ImapList)get(index);
}
public Object getObject(int index)
{
return get(index);
return get(index);
}
public String getString(int index) {
public String getString(int index)
{
return (String)get(index);
}
public InputStream getLiteral(int index) {
public InputStream getLiteral(int index)
{
return (InputStream)get(index);
}
public int getNumber(int index) {
public int getNumber(int index)
{
return Integer.parseInt(getString(index));
}
public Date getDate(int index) throws MessagingException {
try {
public Date getDate(int index) throws MessagingException
{
try
{
return parseDate(getString(index));
} catch (ParseException pe) {
}
catch (ParseException pe)
{
throw new MessagingException("Unable to parse IMAP datetime", pe);
}
}
public Object getKeyedValue(Object key) {
for (int i = 0, count = size(); i < count; i++) {
if (get(i).equals(key)) {
public Object getKeyedValue(Object key)
{
for (int i = 0, count = size(); i < count; i++)
{
if (get(i).equals(key))
{
return get(i + 1);
}
}
return null;
}
public ImapList getKeyedList(Object key) {
public ImapList getKeyedList(Object key)
{
return (ImapList)getKeyedValue(key);
}
public String getKeyedString(Object key) {
public String getKeyedString(Object key)
{
return (String)getKeyedValue(key);
}
public InputStream getKeyedLiteral(Object key) {
public InputStream getKeyedLiteral(Object key)
{
return (InputStream)getKeyedValue(key);
}
public int getKeyedNumber(Object key) {
public int getKeyedNumber(Object key)
{
return Integer.parseInt(getKeyedString(key));
}
public Date getKeyedDate(Object key) throws MessagingException {
try {
public Date getKeyedDate(Object key) throws MessagingException
{
try
{
String value = getKeyedString(key);
if (value == null) {
if (value == null)
{
return null;
}
return parseDate(value);
} catch (ParseException pe) {
}
catch (ParseException pe)
{
throw new MessagingException("Unable to parse IMAP datetime", pe);
}
}
private Date parseDate(String value) throws ParseException
{
try
{
synchronized(mDateTimeFormat)
synchronized (mDateTimeFormat)
{
return mDateTimeFormat.parse(value);
}
}
catch (Exception e)
{
synchronized(badDateTimeFormat)
synchronized (badDateTimeFormat)
{
return badDateTimeFormat.parse(value);
}
}
}
}
/**
@ -375,34 +475,43 @@ public class ImapResponseParser {
* does not contain the entire response the caller must call more() to
* continue reading the response until more returns false.
*/
public class ImapResponse extends ImapList {
public class ImapResponse extends ImapList
{
private boolean mCompleted;
boolean mCommandContinuationRequested;
String mTag;
public boolean more() throws IOException {
if (mCompleted) {
public boolean more() throws IOException
{
if (mCompleted)
{
return false;
}
readTokens(this);
return true;
}
public String getAlertText() {
if (size() > 1 && "[ALERT]".equals(get(1))) {
public String getAlertText()
{
if (size() > 1 && "[ALERT]".equals(get(1)))
{
StringBuffer sb = new StringBuffer();
for (int i = 2, count = size(); i < count; i++) {
for (int i = 2, count = size(); i < count; i++)
{
sb.append(get(i).toString());
sb.append(' ');
}
return sb.toString();
} else {
}
else
{
return null;
}
}
public String toString() {
public String toString()
{
return "#" + mTag + "# " + super.toString();
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -20,114 +20,148 @@ import javax.net.ssl.TrustManager;
import com.android.email.Email;
public final class TrustManagerFactory {
public final class TrustManagerFactory
{
private static final String LOG_TAG = "TrustManagerFactory";
private static X509TrustManager defaultTrustManager;
private static X509TrustManager unsecureTrustManager;
private static X509TrustManager localTrustManager;
private static X509TrustManager localTrustManager;
private static X509Certificate[] lastCertChain = null;
private static File keyStoreFile;
private static KeyStore keyStore;
private static class SimpleX509TrustManager implements X509TrustManager {
private static class SimpleX509TrustManager implements X509TrustManager
{
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throws CertificateException
{
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throws CertificateException
{
}
public X509Certificate[] getAcceptedIssuers() {
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}
private static class SecureX509TrustManager implements X509TrustManager {
private static class SecureX509TrustManager implements X509TrustManager
{
private String mHost;
private static SecureX509TrustManager me;
private SecureX509TrustManager() {
private SecureX509TrustManager()
{
}
public static X509TrustManager getInstance(String host) {
if (me == null) {
me = new SecureX509TrustManager();
}
me.mHost = host;
return me;
}
public static X509TrustManager getInstance(String host)
{
if (me == null)
{
me = new SecureX509TrustManager();
}
me.mHost = host;
return me;
}
public void setHost(String host){
mHost = host;
}
public void setHost(String host)
{
mHost = host;
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throws CertificateException
{
defaultTrustManager.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
TrustManagerFactory.setLastCertChain(chain);
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
localTrustManager.checkServerTrusted(new X509Certificate[] {chain[0]}, authType);
}
if (!DomainNameChecker.match(chain[0], mHost)) {
try {
String dn = chain[0].getSubjectDN().toString();
if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0])))) {
return;
}
} catch (KeyStoreException e) {
throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
}
throw new CertificateException("Certificate domain name does not match "
+ mHost);
}
throws CertificateException
{
TrustManagerFactory.setLastCertChain(chain);
try
{
defaultTrustManager.checkServerTrusted(chain, authType);
}
catch (CertificateException e)
{
localTrustManager.checkServerTrusted(new X509Certificate[] {chain[0]}, authType);
}
if (!DomainNameChecker.match(chain[0], mHost))
{
try
{
String dn = chain[0].getSubjectDN().toString();
if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0]))))
{
return;
}
}
catch (KeyStoreException e)
{
throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
}
throw new CertificateException("Certificate domain name does not match "
+ mHost);
}
}
public X509Certificate[] getAcceptedIssuers() {
public X509Certificate[] getAcceptedIssuers()
{
return defaultTrustManager.getAcceptedIssuers();
}
}
static {
try {
static
{
try
{
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
Application app = Email.app;
keyStoreFile = new File(app.getDir("KeyStore", Context.MODE_PRIVATE) + File.separator + "KeyStore.bks");
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
java.io.FileInputStream fis;
try {
fis = new java.io.FileInputStream(keyStoreFile);
} catch (FileNotFoundException e1) {
fis = null;
}
try {
keyStore.load(fis, "".toCharArray());
//if (fis != null) {
// fis.close();
//}
} catch (IOException e) {
java.io.FileInputStream fis;
try
{
fis = new java.io.FileInputStream(keyStoreFile);
}
catch (FileNotFoundException e1)
{
fis = null;
}
try
{
keyStore.load(fis, "".toCharArray());
//if (fis != null) {
// fis.close();
//}
}
catch (IOException e)
{
Log.e(LOG_TAG, "KeyStore IOException while initializing TrustManagerFactory ", e);
keyStore = null;
} catch (CertificateException e) {
keyStore = null;
}
catch (CertificateException e)
{
Log.e(LOG_TAG, "KeyStore CertificateException while initializing TrustManagerFactory ", e);
keyStore = null;
}
keyStore = null;
}
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
if (tms != null)
{
for (TrustManager tm : tms)
{
if (tm instanceof X509TrustManager)
{
localTrustManager = (X509TrustManager)tm;
break;
}
@ -136,78 +170,106 @@ public final class TrustManagerFactory {
tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore)null);
tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
if (tms != null)
{
for (TrustManager tm : tms)
{
if (tm instanceof X509TrustManager)
{
defaultTrustManager = (X509TrustManager) tm;
break;
}
}
}
} catch (NoSuchAlgorithmException e) {
}
catch (NoSuchAlgorithmException e)
{
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
} catch (KeyStoreException e) {
}
catch (KeyStoreException e)
{
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
}
unsecureTrustManager = new SimpleX509TrustManager();
}
private TrustManagerFactory() {
private TrustManagerFactory()
{
}
public static X509TrustManager get(String host, boolean secure) {
public static X509TrustManager get(String host, boolean secure)
{
return secure ? SecureX509TrustManager.getInstance(host) :
unsecureTrustManager;
unsecureTrustManager;
}
public static KeyStore getKeyStore() {
return keyStore;
public static KeyStore getKeyStore()
{
return keyStore;
}
public static void setLastCertChain(X509Certificate[] chain) {
lastCertChain = chain;
}
public static X509Certificate[] getLastCertChain() {
return lastCertChain;
}
public static void setLastCertChain(X509Certificate[] chain)
{
lastCertChain = chain;
}
public static X509Certificate[] getLastCertChain()
{
return lastCertChain;
}
public static void addCertificateChain(String alias, X509Certificate[] chain) throws CertificateException {
try {
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
for (int i = 0; i < chain.length; i++)
public static void addCertificateChain(String alias, X509Certificate[] chain) throws CertificateException
{
try
{
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
for (int i = 0; i < chain.length; i++)
{
keyStore.setCertificateEntry
(chain[i].getSubjectDN().toString(), chain[i]);
(chain[i].getSubjectDN().toString(), chain[i]);
}
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
localTrustManager = (X509TrustManager) tm;
break;
}
}
}
java.io.FileOutputStream keyStoreStream;
try {
keyStoreStream = new java.io.FileOutputStream(keyStoreFile);
keyStore.store(keyStoreStream, "".toCharArray());
keyStoreStream.close();
} catch (FileNotFoundException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
} catch (CertificateException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
} catch (IOException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
}
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
if (tms != null)
{
for (TrustManager tm : tms)
{
if (tm instanceof X509TrustManager)
{
localTrustManager = (X509TrustManager) tm;
break;
}
}
}
java.io.FileOutputStream keyStoreStream;
try
{
keyStoreStream = new java.io.FileOutputStream(keyStoreFile);
keyStore.store(keyStoreStream, "".toCharArray());
keyStoreStream.close();
}
catch (FileNotFoundException e)
{
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
}
catch (CertificateException e)
{
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
}
catch (IOException e)
{
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
}
} catch (NoSuchAlgorithmException e) {
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
} catch (KeyStoreException e) {
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
}
}
}
catch (NoSuchAlgorithmException e)
{
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
}
catch (KeyStoreException e)
{
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -7,18 +7,22 @@ import java.io.OutputStream;
* A simple OutputStream that does nothing but count how many bytes are written to it and
* makes that count available to callers.
*/
public class CountingOutputStream extends OutputStream {
public class CountingOutputStream extends OutputStream
{
private long mCount;
public CountingOutputStream() {
public CountingOutputStream()
{
}
public long getCount() {
public long getCount()
{
return mCount;
}
@Override
public void write(int oneByte) throws IOException {
public void write(int oneByte) throws IOException
{
mCount++;
}
}

View file

@ -4,17 +4,22 @@ import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class EOLConvertingOutputStream extends FilterOutputStream {
public class EOLConvertingOutputStream extends FilterOutputStream
{
int lastChar;
public EOLConvertingOutputStream(OutputStream out) {
public EOLConvertingOutputStream(OutputStream out)
{
super(out);
}
@Override
public void write(int oneByte) throws IOException {
if (oneByte == '\n') {
if (lastChar != '\r') {
public void write(int oneByte) throws IOException
{
if (oneByte == '\n')
{
if (lastChar != '\r')
{
super.write('\r');
}
}
@ -23,8 +28,10 @@ public class EOLConvertingOutputStream extends FilterOutputStream {
}
@Override
public void flush() throws IOException {
if (lastChar == '\r') {
public void flush() throws IOException
{
if (lastChar == '\r')
{
super.write('\n');
lastChar = '\n';
}

View file

@ -36,7 +36,8 @@ import com.android.email.mail.CertificateValidationException;
import com.android.email.mail.Message.RecipientType;
import com.android.email.mail.store.TrustManagerFactory;
public class SmtpTransport extends Transport {
public class SmtpTransport extends Transport
{
public static final int CONNECTION_SECURITY_NONE = 0;
public static final int CONNECTION_SECURITY_TLS_OPTIONAL = 1;
@ -74,70 +75,94 @@ public class SmtpTransport extends Transport {
*
* @param _uri
*/
public SmtpTransport(String _uri) throws MessagingException {
public SmtpTransport(String _uri) throws MessagingException
{
URI uri;
try {
try
{
uri = new URI(_uri);
} catch (URISyntaxException use) {
}
catch (URISyntaxException use)
{
throw new MessagingException("Invalid SmtpTransport URI", use);
}
String scheme = uri.getScheme();
if (scheme.equals("smtp")) {
if (scheme.equals("smtp"))
{
mConnectionSecurity = CONNECTION_SECURITY_NONE;
mPort = 25;
} else if (scheme.equals("smtp+tls")) {
}
else if (scheme.equals("smtp+tls"))
{
mConnectionSecurity = CONNECTION_SECURITY_TLS_OPTIONAL;
mPort = 25;
} else if (scheme.equals("smtp+tls+")) {
}
else if (scheme.equals("smtp+tls+"))
{
mConnectionSecurity = CONNECTION_SECURITY_TLS_REQUIRED;
mPort = 25;
} else if (scheme.equals("smtp+ssl+")) {
}
else if (scheme.equals("smtp+ssl+"))
{
mConnectionSecurity = CONNECTION_SECURITY_SSL_REQUIRED;
mPort = 465;
} else if (scheme.equals("smtp+ssl")) {
}
else if (scheme.equals("smtp+ssl"))
{
mConnectionSecurity = CONNECTION_SECURITY_SSL_OPTIONAL;
mPort = 465;
} else {
}
else
{
throw new MessagingException("Unsupported protocol");
}
mHost = uri.getHost();
if (uri.getPort() != -1) {
if (uri.getPort() != -1)
{
mPort = uri.getPort();
}
if (uri.getUserInfo() != null) {
if (uri.getUserInfo() != null)
{
String[] userInfoParts = uri.getUserInfo().split(":", 2);
mUsername = userInfoParts[0];
if (userInfoParts.length > 1) {
if (userInfoParts.length > 1)
{
mPassword = userInfoParts[1];
}
}
}
public void open() throws MessagingException {
try {
public void open() throws MessagingException
{
try
{
SocketAddress socketAddress = new InetSocketAddress(mHost, mPort);
if (mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED ||
mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) {
mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL)
{
SSLContext sslContext = SSLContext.getInstance("TLS");
boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED;
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(mHost, secure)
sslContext.init(null, new TrustManager[]
{
TrustManagerFactory.get(mHost, secure)
}, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket();
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
mSecure = true;
} else {
}
else
{
mSocket = new Socket();
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
}
// RFC 1047
mSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), 1024));
mOut = mSocket.getOutputStream();
@ -145,17 +170,22 @@ public class SmtpTransport extends Transport {
executeSimpleCommand(null);
String localHost = "localhost.localdomain";
try {
try
{
InetAddress localAddress = InetAddress.getLocalHost();
if (! localAddress.isLoopbackAddress()) {
if (! localAddress.isLoopbackAddress())
{
// The loopback address will resolve to 'localhost'
// some mail servers only accept qualified hostnames, so make sure
// some mail servers only accept qualified hostnames, so make sure
// never to override "localhost.localdomain" with "localhost"
// TODO - this is a hack. but a better hack than what was there before
localHost = localAddress.getHostName();
}
} catch (Exception e) {
if (Email.DEBUG) {
}
catch (Exception e)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Unable to look up localhost");
}
}
@ -171,19 +201,22 @@ public class SmtpTransport extends Transport {
* if not.
*/
if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL
|| mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
if (results.contains("STARTTLS")) {
|| mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED)
{
if (results.contains("STARTTLS"))
{
executeSimpleCommand("STARTTLS");
SSLContext sslContext = SSLContext.getInstance("TLS");
boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED;
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(mHost, secure)
sslContext.init(null, new TrustManager[]
{
TrustManagerFactory.get(mHost, secure)
}, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(mSocket, mHost, mPort,
true);
true);
mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(),
1024));
1024));
mOut = mSocket.getOutputStream();
mSecure = true;
/*
@ -191,7 +224,9 @@ public class SmtpTransport extends Transport {
* Exim.
*/
results = executeSimpleCommand("EHLO " + localHost);
} else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
}
else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED)
{
throw new MessagingException("TLS not supported but required");
}
}
@ -200,7 +235,7 @@ public class SmtpTransport extends Transport {
* result contains the results of the EHLO in concatenated form
*/
boolean authLoginSupported = false;
boolean authPlainSupported = false;
boolean authPlainSupported = false;
for (String result : results)
{
if (result.matches(".*AUTH.*LOGIN.*$") == true)
@ -214,80 +249,107 @@ public class SmtpTransport extends Transport {
}
if (mUsername != null && mUsername.length() > 0 && mPassword != null
&& mPassword.length() > 0) {
if (authPlainSupported) {
&& mPassword.length() > 0)
{
if (authPlainSupported)
{
saslAuthPlain(mUsername, mPassword);
}
else if (authLoginSupported) {
else if (authLoginSupported)
{
saslAuthLogin(mUsername, mPassword);
}
else {
else
{
throw new MessagingException("No valid authentication mechanism found.");
}
}
} catch (SSLException e) {
}
catch (SSLException e)
{
throw new CertificateValidationException(e.getMessage(), e);
} catch (GeneralSecurityException gse) {
}
catch (GeneralSecurityException gse)
{
throw new MessagingException(
"Unable to open connection to SMTP server due to security error.", gse);
} catch (IOException ioe) {
"Unable to open connection to SMTP server due to security error.", gse);
}
catch (IOException ioe)
{
throw new MessagingException("Unable to open connection to SMTP server.", ioe);
}
}
public void sendMessage(Message message) throws MessagingException {
public void sendMessage(Message message) throws MessagingException
{
close();
open();
Address[] from = message.getFrom();
boolean possibleSend = false;
try {
try
{
executeSimpleCommand("MAIL FROM: " + "<" + from[0].getAddress() + ">");
for (Address address : message.getRecipients(RecipientType.TO)) {
for (Address address : message.getRecipients(RecipientType.TO))
{
executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">");
}
for (Address address : message.getRecipients(RecipientType.CC)) {
for (Address address : message.getRecipients(RecipientType.CC))
{
executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">");
}
for (Address address : message.getRecipients(RecipientType.BCC)) {
for (Address address : message.getRecipients(RecipientType.BCC))
{
executeSimpleCommand("RCPT TO: " + "<" + address.getAddress() + ">");
}
message.setRecipients(RecipientType.BCC, null);
executeSimpleCommand("DATA");
// TODO byte stuffing
message.writeTo(
new EOLConvertingOutputStream(
new BufferedOutputStream(mOut, 1024)));
new EOLConvertingOutputStream(
new BufferedOutputStream(mOut, 1024)));
possibleSend = true; // After the "\r\n." is attempted, we may have sent the message
executeSimpleCommand("\r\n.");
} catch (Exception e) {
MessagingException me = new MessagingException("Unable to send message", e);
me.setPermanentFailure(possibleSend);
throw me;
}
catch (Exception e)
{
MessagingException me = new MessagingException("Unable to send message", e);
me.setPermanentFailure(possibleSend);
throw me;
}
finally
{
close();
close();
}
}
public void close() {
try {
public void close()
{
try
{
mIn.close();
} catch (Exception e) {
}
catch (Exception e)
{
}
try {
try
{
mOut.close();
} catch (Exception e) {
}
catch (Exception e)
{
}
try {
try
{
mSocket.close();
} catch (Exception e) {
}
catch (Exception e)
{
}
mIn = null;
@ -295,28 +357,38 @@ public class SmtpTransport extends Transport {
mSocket = null;
}
private String readLine() throws IOException {
private String readLine() throws IOException
{
StringBuffer sb = new StringBuffer();
int d;
while ((d = mIn.read()) != -1) {
if (((char)d) == '\r') {
while ((d = mIn.read()) != -1)
{
if (((char)d) == '\r')
{
continue;
} else if (((char)d) == '\n') {
}
else if (((char)d) == '\n')
{
break;
} else {
}
else
{
sb.append((char)d);
}
}
String ret = sb.toString();
if (Email.DEBUG) {
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "SMTP <<< " + ret);
}
return ret;
}
private void writeLine(String s) throws IOException {
if (Email.DEBUG) {
private void writeLine(String s) throws IOException
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "SMTP >>> " + s);
}
mOut.write(s.getBytes());
@ -327,22 +399,25 @@ public class SmtpTransport extends Transport {
private void checkLine(String line) throws MessagingException
{
if (line.length() < 1)
{
throw new MessagingException("SMTP response is 0 length");
}
if (line.length() < 1)
{
throw new MessagingException("SMTP response is 0 length");
}
char c = line.charAt(0);
if ((c == '4') || (c == '5')) {
if ((c == '4') || (c == '5'))
{
throw new MessagingException(line);
}
}
private List<String> executeSimpleCommand(String command) throws IOException, MessagingException {
private List<String> executeSimpleCommand(String command) throws IOException, MessagingException
{
List<String> results = new ArrayList<String>();
if (command != null) {
if (command != null)
{
writeLine(command);
}
boolean cont = false;
do
{
@ -360,7 +435,8 @@ public class SmtpTransport extends Transport {
cont = false;
}
}
} while (cont);
}
while (cont);
return results;
}
@ -384,32 +460,40 @@ public class SmtpTransport extends Transport {
// S: 235 2.0.0 OK Authenticated
private void saslAuthLogin(String username, String password) throws MessagingException,
AuthenticationFailedException, IOException {
try {
AuthenticationFailedException, IOException
{
try
{
executeSimpleCommand("AUTH LOGIN");
executeSimpleCommand(new String(Base64.encodeBase64(username.getBytes())));
executeSimpleCommand(new String(Base64.encodeBase64(password.getBytes())));
}
catch (MessagingException me) {
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') {
catch (MessagingException me)
{
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3')
{
throw new AuthenticationFailedException("AUTH LOGIN failed (" + me.getMessage()
+ ")");
+ ")");
}
throw me;
}
}
private void saslAuthPlain(String username, String password) throws MessagingException,
AuthenticationFailedException, IOException {
AuthenticationFailedException, IOException
{
byte[] data = ("\000" + username + "\000" + password).getBytes();
data = new Base64().encode(data);
try {
try
{
executeSimpleCommand("AUTH PLAIN " + new String(data));
}
catch (MessagingException me) {
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3') {
catch (MessagingException me)
{
if (me.getMessage().length() > 1 && me.getMessage().charAt(1) == '3')
{
throw new AuthenticationFailedException("AUTH PLAIN failed (" + me.getMessage()
+ ")");
+ ")");
}
throw me;
}

View file

@ -9,19 +9,24 @@ import com.android.email.Email;
import android.util.Config;
import android.util.Log;
public class StatusOutputStream extends FilterOutputStream {
public class StatusOutputStream extends FilterOutputStream
{
private long mCount = 0;
public StatusOutputStream(OutputStream out) {
public StatusOutputStream(OutputStream out)
{
super(out);
}
@Override
public void write(int oneByte) throws IOException {
public void write(int oneByte) throws IOException
{
super.write(oneByte);
mCount++;
if (Config.LOGV) {
if (mCount % 1024 == 0) {
if (Config.LOGV)
{
if (mCount % 1024 == 0)
{
Log.v(Email.LOG_TAG, "# " + mCount);
}
}

View file

@ -19,47 +19,55 @@ import org.apache.http.params.HttpParams;
import com.android.email.mail.store.TrustManagerFactory;
public class TrustedSocketFactory implements LayeredSocketFactory {
private SSLSocketFactory mSocketFactory;
private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory;
public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException{
public class TrustedSocketFactory implements LayeredSocketFactory
{
private SSLSocketFactory mSocketFactory;
private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory;
public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException
{
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(host, secure)
sslContext.init(null, new TrustManager[]
{
TrustManagerFactory.get(host, secure)
}, new SecureRandom());
mSocketFactory = sslContext.getSocketFactory();
mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory();
mSchemeSocketFactory.setHostnameVerifier(
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params);
}
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException
{
return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params);
}
public Socket createSocket() throws IOException {
return mSocketFactory.createSocket();
}
public Socket createSocket() throws IOException
{
return mSocketFactory.createSocket();
}
public boolean isSecure(Socket sock) throws IllegalArgumentException {
return mSchemeSocketFactory.isSecure(sock);
}
public Socket createSocket(
final Socket socket,
final String host,
final int port,
final boolean autoClose
) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket(
socket,
host,
port,
autoClose
);
//hostnameVerifier.verify(host, sslSocket);
// verifyHostName() didn't blowup - good!
return sslSocket;
}}
public boolean isSecure(Socket sock) throws IllegalArgumentException
{
return mSchemeSocketFactory.isSecure(sock);
}
public Socket createSocket(
final Socket socket,
final String host,
final int port,
final boolean autoClose
) throws IOException, UnknownHostException
{
SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket(
socket,
host,
port,
autoClose
);
//hostnameVerifier.verify(host, sslSocket);
// verifyHostName() didn't blowup - good!
return sslSocket;
}
}

View file

@ -57,7 +57,8 @@ import com.android.email.mail.store.WebDavStore.HttpGeneric;
import com.android.email.mail.store.WebDavStore.DataSet;
import com.android.email.mail.store.WebDavStore.WebDavHandler;
public class WebDavTransport extends Transport {
public class WebDavTransport extends Transport
{
public static final int CONNECTION_SECURITY_NONE = 0;
public static final int CONNECTION_SECURITY_TLS_OPTIONAL = 1;
public static final int CONNECTION_SECURITY_TLS_REQUIRED = 2;
@ -75,7 +76,7 @@ public class WebDavTransport extends Transport {
Socket mSocket;
PeekableInputStream mIn;
OutputStream mOut;
private WebDavStore store;
private WebDavStore store;
/**
* webdav://user:password@server:port CONNECTION_SECURITY_NONE
@ -86,24 +87,28 @@ public class WebDavTransport extends Transport {
*
* @param _uri
*/
public WebDavTransport(String _uri) throws MessagingException {
store = new WebDavStore(_uri);
public WebDavTransport(String _uri) throws MessagingException
{
store = new WebDavStore(_uri);
Log.d(Email.LOG_TAG, ">>> New WebDavTransport creation complete");
}
public void open() throws MessagingException {
public void open() throws MessagingException
{
Log.d(Email.LOG_TAG, ">>> open called on WebDavTransport ");
store.getHttpClient();
}
public void close() {
public void close()
{
}
public void sendMessage(Message message) throws MessagingException {
public void sendMessage(Message message) throws MessagingException
{
store.sendMessages(new Message[] { message });
}
}

View file

@ -11,151 +11,152 @@ import android.util.Log;
public class Editor implements android.content.SharedPreferences.Editor
{
private Storage storage;
private HashMap<String, String> changes = new HashMap<String, String>();
private ArrayList<String> removals = new ArrayList<String>();
private boolean removeAll = false;
Map<String, String> snapshot = new HashMap<String, String>();
protected Editor(Storage storage)
{
this.storage = storage;
snapshot.putAll(storage.getAll());
}
public void copy(android.content.SharedPreferences input)
{
Map<String, ?> oldVals = input.getAll();
for (Entry<String, ?> entry : oldVals.entrySet())
private Storage storage;
private HashMap<String, String> changes = new HashMap<String, String>();
private ArrayList<String> removals = new ArrayList<String>();
private boolean removeAll = false;
Map<String, String> snapshot = new HashMap<String, String>();
protected Editor(Storage storage)
{
String key = entry.getKey();
Object value = entry.getValue();
if (key != null && value != null)
{
if (Email.DEBUG)
this.storage = storage;
snapshot.putAll(storage.getAll());
}
public void copy(android.content.SharedPreferences input)
{
Map<String, ?> oldVals = input.getAll();
for (Entry<String, ?> entry : oldVals.entrySet())
{
Log.d(Email.LOG_TAG, "Copying key '" + key + "', value '" + value + "'");
String key = entry.getKey();
Object value = entry.getValue();
if (key != null && value != null)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Copying key '" + key + "', value '" + value + "'");
}
changes.put(key, "" + value);
}
else
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Skipping copying key '" + key + "', value '" + value + "'");
}
}
}
}
//@Override
public android.content.SharedPreferences.Editor clear()
{
removeAll = true;
return this;
}
/* This method is poorly defined. It should throw an Exception on failure */
//@Override
public boolean commit()
{
try
{
commitChanges();
return true;
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Failed to save preferences", e);
return false;
}
}
public void commitChanges() throws Exception
{
long startTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Committing preference changes");
Runnable committer = new Runnable()
{
public void run()
{
if (removeAll)
{
storage.removeAll();
}
for (String removeKey : removals)
{
storage.remove(removeKey);
}
for (Entry<String, String> entry : changes.entrySet())
{
String key = entry.getKey();
String newValue = entry.getValue();
String oldValue = snapshot.get(key);
if (removeAll || removals.contains(key) || newValue.equals(oldValue) != true)
{
storage.put(key, newValue);
}
}
}
};
storage.doInTransaction(committer);
long endTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Preferences commit took " + (endTime - startTime) + "ms");
}
//@Override
public android.content.SharedPreferences.Editor putBoolean(String key,
boolean value)
{
changes.put(key, "" + value);
}
else
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Skipping copying key '" + key + "', value '" + value + "'");
}
}
return this;
}
}
//@Override
public android.content.SharedPreferences.Editor clear()
{
removeAll = true;
return this;
}
/* This method is poorly defined. It should throw an Exception on failure */
//@Override
public boolean commit()
{
try
//@Override
public android.content.SharedPreferences.Editor putFloat(String key,
float value)
{
commitChanges();
return true;
changes.put(key, "" + value);
return this;
}
catch (Exception e)
//@Override
public android.content.SharedPreferences.Editor putInt(String key, int value)
{
Log.e(Email.LOG_TAG, "Failed to save preferences", e);
return false;
changes.put(key, "" + value);
return this;
}
}
public void commitChanges() throws Exception
{
long startTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Committing preference changes");
Runnable committer = new Runnable() {
public void run()
{
if (removeAll)
{
storage.removeAll();
}
for (String removeKey : removals)
{
storage.remove(removeKey);
}
for (Entry<String, String> entry : changes.entrySet())
{
String key = entry.getKey();
String newValue = entry.getValue();
String oldValue = snapshot.get(key);
if (removeAll || removals.contains(key) || newValue.equals(oldValue) != true)
{
storage.put(key, newValue);
}
}
}
};
storage.doInTransaction(committer);
long endTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Preferences commit took " + (endTime - startTime) + "ms");
}
//@Override
public android.content.SharedPreferences.Editor putBoolean(String key,
boolean value)
{
changes.put(key, "" + value);
return this;
}
//@Override
public android.content.SharedPreferences.Editor putFloat(String key,
float value)
{
changes.put(key, "" + value);
return this;
}
//@Override
public android.content.SharedPreferences.Editor putInt(String key, int value)
{
changes.put(key, "" + value);
return this;
}
//@Override
public android.content.SharedPreferences.Editor putLong(String key, long value)
{
changes.put(key, "" + value);
return this;
}
//@Override
public android.content.SharedPreferences.Editor putString(String key,
String value)
{
if (value == null)
//@Override
public android.content.SharedPreferences.Editor putLong(String key, long value)
{
remove(key);
changes.put(key, "" + value);
return this;
}
else
{
changes.put(key, value);
}
return this;
}
//@Override
public android.content.SharedPreferences.Editor remove(String key)
{
removals.add(key);
return this;
}
//@Override
public android.content.SharedPreferences.Editor putString(String key,
String value)
{
if (value == null)
{
remove(key);
}
else
{
changes.put(key, value);
}
return this;
}
//@Override
public android.content.SharedPreferences.Editor remove(String key)
{
removals.add(key);
return this;
}
}

View file

@ -16,285 +16,289 @@ import android.util.Log;
public class Storage implements SharedPreferences
{
private static ConcurrentHashMap<Context, Storage> storages =
new ConcurrentHashMap<Context, Storage>();
private volatile ConcurrentHashMap<String, String> storage = new ConcurrentHashMap<String, String>();
private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> listeners =
new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
private int DB_VERSION = 1; // CHANGING THIS WILL DESTROY ALL USER PREFERENCES!
private String DB_NAME = "preferences_storage";
private ThreadLocal<ConcurrentHashMap<String, String>> workingStorage
private static ConcurrentHashMap<Context, Storage> storages =
new ConcurrentHashMap<Context, Storage>();
private volatile ConcurrentHashMap<String, String> storage = new ConcurrentHashMap<String, String>();
private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> listeners =
new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
private int DB_VERSION = 1; // CHANGING THIS WILL DESTROY ALL USER PREFERENCES!
private String DB_NAME = "preferences_storage";
private ThreadLocal<ConcurrentHashMap<String, String>> workingStorage
= new ThreadLocal<ConcurrentHashMap<String, String>>();
private ThreadLocal<SQLiteDatabase> workingDB =
new ThreadLocal<SQLiteDatabase>();
private ThreadLocal<ArrayList<String>> workingChangedKeys = new ThreadLocal<ArrayList<String>>();
private Context context = null;
private SQLiteDatabase openDB()
{
SQLiteDatabase mDb = context.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
if (mDb.getVersion() != DB_VERSION)
private ThreadLocal<SQLiteDatabase> workingDB =
new ThreadLocal<SQLiteDatabase>();
private ThreadLocal<ArrayList<String>> workingChangedKeys = new ThreadLocal<ArrayList<String>>();
private Context context = null;
private SQLiteDatabase openDB()
{
Log.i(Email.LOG_TAG, "Creating Storage database");
mDb.execSQL("DROP TABLE IF EXISTS preferences_storage");
mDb.execSQL("CREATE TABLE preferences_storage " +
"(primkey TEXT PRIMARY KEY ON CONFLICT REPLACE, value TEXT)");
mDb.setVersion(DB_VERSION);
}
return mDb;
}
public static Storage getStorage(Context context)
{
Storage tmpStorage = storages.get(context);
if (tmpStorage != null)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Returning already existing Storage");
}
return tmpStorage;
}
else
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Creating provisional storage");
}
tmpStorage = new Storage(context);
Storage oldStorage = storages.putIfAbsent(context, tmpStorage);
if (oldStorage != null)
{
if (Email.DEBUG)
SQLiteDatabase mDb = context.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
if (mDb.getVersion() != DB_VERSION)
{
Log.d(Email.LOG_TAG, "Another thread beat us to creating the Storage, returning that one");
Log.i(Email.LOG_TAG, "Creating Storage database");
mDb.execSQL("DROP TABLE IF EXISTS preferences_storage");
mDb.execSQL("CREATE TABLE preferences_storage " +
"(primkey TEXT PRIMARY KEY ON CONFLICT REPLACE, value TEXT)");
mDb.setVersion(DB_VERSION);
}
return oldStorage;
}
else
{
if (Email.DEBUG)
return mDb;
}
public static Storage getStorage(Context context)
{
Storage tmpStorage = storages.get(context);
if (tmpStorage != null)
{
Log.d(Email.LOG_TAG, "Returning the Storage we created");
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Returning already existing Storage");
}
return tmpStorage;
}
return tmpStorage;
}
}
}
private void loadValues()
{
long startTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Loading preferences from DB into Storage");
Cursor cursor = null;
SQLiteDatabase mDb = null;
try {
mDb = openDB();
cursor = mDb.rawQuery("SELECT primkey, value FROM preferences_storage", null);
while (cursor.moveToNext()) {
String key = cursor.getString(0);
String value = cursor.getString(1);
if (Email.DEBUG)
else
{
Log.d(Email.LOG_TAG, "Loading key '" + key + "', value = '" + value + "'");
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Creating provisional storage");
}
tmpStorage = new Storage(context);
Storage oldStorage = storages.putIfAbsent(context, tmpStorage);
if (oldStorage != null)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Another thread beat us to creating the Storage, returning that one");
}
return oldStorage;
}
else
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Returning the Storage we created");
}
return tmpStorage;
}
}
storage.put(key, value);
}
}
finally {
if (cursor != null) {
cursor.close();
}
if (mDb != null)
{
mDb.close();
}
long endTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Preferences load took " + (endTime - startTime) + "ms");
}
}
private Storage(Context context)
{
this.context = context;
loadValues();
}
private void keyChange(String key)
{
ArrayList<String> changedKeys = workingChangedKeys.get();
if (changedKeys.contains(key) == false)
{
changedKeys.add(key);
}
}
protected void put(String key, String value)
{
ContentValues cv = new ContentValues();
cv.put("primkey", key);
cv.put("value", value);
workingDB.get().insert("preferences_storage", "primkey", cv);
workingStorage.get().put(key, value);
keyChange(key);
}
protected void remove(String key)
{
workingDB.get().delete("preferences_storage", "primkey = ?", new String[] { key });
workingStorage.get().remove(key);
keyChange(key);
}
protected void removeAll()
{
for (String key : workingStorage.get().keySet())
private void loadValues()
{
keyChange(key);
}
workingDB.get().execSQL("DELETE FROM preferences_storage");
workingStorage.get().clear();
}
protected void doInTransaction(Runnable dbWork)
{
ConcurrentHashMap<String, String> newStorage = new ConcurrentHashMap<String, String>();
newStorage.putAll(storage);
workingStorage.set(newStorage);
SQLiteDatabase mDb = openDB();
workingDB.set(mDb);
ArrayList<String> changedKeys = new ArrayList<String>();
workingChangedKeys.set(changedKeys);
mDb.beginTransaction();
try
{
dbWork.run();
mDb.setTransactionSuccessful();
storage = newStorage;
for (String changedKey : changedKeys)
{
for (OnSharedPreferenceChangeListener listener : listeners)
long startTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Loading preferences from DB into Storage");
Cursor cursor = null;
SQLiteDatabase mDb = null;
try
{
listener.onSharedPreferenceChanged(this, changedKey);
mDb = openDB();
cursor = mDb.rawQuery("SELECT primkey, value FROM preferences_storage", null);
while (cursor.moveToNext())
{
String key = cursor.getString(0);
String value = cursor.getString(1);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Loading key '" + key + "', value = '" + value + "'");
}
storage.put(key, value);
}
}
finally
{
if (cursor != null)
{
cursor.close();
}
if (mDb != null)
{
mDb.close();
}
long endTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "Preferences load took " + (endTime - startTime) + "ms");
}
}
}
finally
private Storage(Context context)
{
workingDB.remove();
workingStorage.remove();
workingChangedKeys.remove();
mDb.endTransaction();
if (mDb != null)
{
mDb.close();
}
this.context = context;
loadValues();
}
}
public long size()
{
return storage.size();
}
//@Override
public boolean contains(String key)
{
return storage.contains(key);
}
//@Override
public com.android.email.preferences.Editor edit()
{
return new com.android.email.preferences.Editor(this);
}
//@Override
public Map<String, String> getAll()
{
return storage;
}
//@Override
public boolean getBoolean(String key, boolean defValue)
{
String val = storage.get(key);
if (val == null)
private void keyChange(String key)
{
return defValue;
ArrayList<String> changedKeys = workingChangedKeys.get();
if (changedKeys.contains(key) == false)
{
changedKeys.add(key);
}
}
return Boolean.parseBoolean(val);
}
//@Override
public float getFloat(String key, float defValue)
{
String val = storage.get(key);
if (val == null)
protected void put(String key, String value)
{
return defValue;
}
return Float.parseFloat(val);
}
ContentValues cv = new ContentValues();
cv.put("primkey", key);
cv.put("value", value);
workingDB.get().insert("preferences_storage", "primkey", cv);
workingStorage.get().put(key, value);
//@Override
public int getInt(String key, int defValue)
{
String val = storage.get(key);
if (val == null)
keyChange(key);
}
protected void remove(String key)
{
return defValue;
}
return Integer.parseInt(val);
}
workingDB.get().delete("preferences_storage", "primkey = ?", new String[] { key });
workingStorage.get().remove(key);
//@Override
public long getLong(String key, long defValue)
{
String val = storage.get(key);
if (val == null)
keyChange(key);
}
protected void removeAll()
{
return defValue;
for (String key : workingStorage.get().keySet())
{
keyChange(key);
}
workingDB.get().execSQL("DELETE FROM preferences_storage");
workingStorage.get().clear();
}
return Long.parseLong(val);
}
//@Override
public String getString(String key, String defValue)
{
String val = storage.get(key);
if (val == null)
protected void doInTransaction(Runnable dbWork)
{
return defValue;
ConcurrentHashMap<String, String> newStorage = new ConcurrentHashMap<String, String>();
newStorage.putAll(storage);
workingStorage.set(newStorage);
SQLiteDatabase mDb = openDB();
workingDB.set(mDb);
ArrayList<String> changedKeys = new ArrayList<String>();
workingChangedKeys.set(changedKeys);
mDb.beginTransaction();
try
{
dbWork.run();
mDb.setTransactionSuccessful();
storage = newStorage;
for (String changedKey : changedKeys)
{
for (OnSharedPreferenceChangeListener listener : listeners)
{
listener.onSharedPreferenceChanged(this, changedKey);
}
}
}
finally
{
workingDB.remove();
workingStorage.remove();
workingChangedKeys.remove();
mDb.endTransaction();
if (mDb != null)
{
mDb.close();
}
}
}
return val;
}
//@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener)
{
listeners.addIfAbsent(listener);
}
public long size()
{
return storage.size();
}
//@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener)
{
listeners.remove(listener);
}
//@Override
public boolean contains(String key)
{
return storage.contains(key);
}
//@Override
public com.android.email.preferences.Editor edit()
{
return new com.android.email.preferences.Editor(this);
}
//@Override
public Map<String, String> getAll()
{
return storage;
}
//@Override
public boolean getBoolean(String key, boolean defValue)
{
String val = storage.get(key);
if (val == null)
{
return defValue;
}
return Boolean.parseBoolean(val);
}
//@Override
public float getFloat(String key, float defValue)
{
String val = storage.get(key);
if (val == null)
{
return defValue;
}
return Float.parseFloat(val);
}
//@Override
public int getInt(String key, int defValue)
{
String val = storage.get(key);
if (val == null)
{
return defValue;
}
return Integer.parseInt(val);
}
//@Override
public long getLong(String key, long defValue)
{
String val = storage.get(key);
if (val == null)
{
return defValue;
}
return Long.parseLong(val);
}
//@Override
public String getString(String key, String defValue)
{
String val = storage.get(key);
if (val == null)
{
return defValue;
}
return val;
}
//@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener)
{
listeners.addIfAbsent(listener);
}
//@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener)
{
listeners.remove(listener);
}
}

View file

@ -30,98 +30,113 @@ import com.android.email.mail.internet.MimeUtility;
/*
* A simple ContentProvider that allows file access to Email's attachments.
*/
public class AttachmentProvider extends ContentProvider {
public static final Uri CONTENT_URI = Uri.parse( "content://com.fsck.k9.attachmentprovider");
public class AttachmentProvider extends ContentProvider
{
public static final Uri CONTENT_URI = Uri.parse("content://com.fsck.k9.attachmentprovider");
private static final String FORMAT_RAW = "RAW";
private static final String FORMAT_THUMBNAIL = "THUMBNAIL";
public static class AttachmentProviderColumns {
public static class AttachmentProviderColumns
{
public static final String _ID = "_id";
public static final String DATA = "_data";
public static final String DISPLAY_NAME = "_display_name";
public static final String SIZE = "_size";
}
public static Uri getAttachmentUri(Account account, long id) {
public static Uri getAttachmentUri(Account account, long id)
{
return CONTENT_URI.buildUpon()
.appendPath(account.getUuid() + ".db")
.appendPath(Long.toString(id))
.appendPath(FORMAT_RAW)
.build();
.appendPath(account.getUuid() + ".db")
.appendPath(Long.toString(id))
.appendPath(FORMAT_RAW)
.build();
}
public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height) {
public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height)
{
return CONTENT_URI.buildUpon()
.appendPath(account.getUuid() + ".db")
.appendPath(Long.toString(id))
.appendPath(FORMAT_THUMBNAIL)
.appendPath(Integer.toString(width))
.appendPath(Integer.toString(height))
.build();
.appendPath(account.getUuid() + ".db")
.appendPath(Long.toString(id))
.appendPath(FORMAT_THUMBNAIL)
.appendPath(Integer.toString(width))
.appendPath(Integer.toString(height))
.build();
}
public static Uri getAttachmentUri(String db, long id) {
public static Uri getAttachmentUri(String db, long id)
{
return CONTENT_URI.buildUpon()
.appendPath(db)
.appendPath(Long.toString(id))
.appendPath(FORMAT_RAW)
.build();
.appendPath(db)
.appendPath(Long.toString(id))
.appendPath(FORMAT_RAW)
.build();
}
@Override
public boolean onCreate() {
public boolean onCreate()
{
/*
* We use the cache dir as a temporary directory (since Android doesn't give us one) so
* on startup we'll clean up any .tmp files from the last run.
*/
File[] files = getContext().getCacheDir().listFiles();
for (File file : files) {
if (file.getName().endsWith(".tmp")) {
for (File file : files)
{
if (file.getName().endsWith(".tmp"))
{
file.delete();
}
}
return true;
}
public static void clear(Context lContext) {
/*
* We use the cache dir as a temporary directory (since Android doesn't give us one) so
* on startup we'll clean up any .tmp files from the last run.
*/
File[] files = lContext.getCacheDir().listFiles();
for (File file : files) {
try {
Log.d(Email.LOG_TAG, "Deleting file " + file.getCanonicalPath());
public static void clear(Context lContext)
{
/*
* We use the cache dir as a temporary directory (since Android doesn't give us one) so
* on startup we'll clean up any .tmp files from the last run.
*/
File[] files = lContext.getCacheDir().listFiles();
for (File file : files)
{
try
{
Log.d(Email.LOG_TAG, "Deleting file " + file.getCanonicalPath());
}
catch (IOException ioe) {} // No need to log failure to log
file.delete();
}
catch (IOException ioe) {} // No need to log failure to log
file.delete();
}
}
}
@Override
public String getType(Uri uri) {
public String getType(Uri uri)
{
List<String> segments = uri.getPathSegments();
String dbName = segments.get(0);
String id = segments.get(1);
String format = segments.get(2);
if (FORMAT_THUMBNAIL.equals(format)) {
if (FORMAT_THUMBNAIL.equals(format))
{
return "image/png";
}
else {
else
{
String path = getContext().getDatabasePath(dbName).getAbsolutePath();
SQLiteDatabase db = null;
Cursor cursor = null;
try {
try
{
db = SQLiteDatabase.openDatabase(path, null, 0);
cursor = db.query(
"attachments",
new String[] { "mime_type" },
"id = ?",
new String[] { id },
null,
null,
null);
"attachments",
new String[] { "mime_type" },
"id = ?",
new String[] { id },
null,
null,
null);
cursor.moveToFirst();
String type = cursor.getString(0);
cursor.close();
@ -129,11 +144,14 @@ public class AttachmentProvider extends ContentProvider {
return type;
}
finally {
if (cursor != null) {
finally
{
if (cursor != null)
{
cursor.close();
}
if (db != null) {
if (db != null)
{
db.close();
}
@ -142,23 +160,27 @@ public class AttachmentProvider extends ContentProvider {
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
{
List<String> segments = uri.getPathSegments();
String dbName = segments.get(0);
String id = segments.get(1);
String format = segments.get(2);
if (FORMAT_THUMBNAIL.equals(format)) {
if (FORMAT_THUMBNAIL.equals(format))
{
int width = Integer.parseInt(segments.get(3));
int height = Integer.parseInt(segments.get(4));
String filename = "thmb_" + dbName + "_" + id;
File dir = getContext().getCacheDir();
File file = new File(dir, filename);
if (!file.exists()) {
if (!file.exists())
{
Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id));
String type = getType(attachmentUri);
try {
try
{
FileInputStream in = new FileInputStream(
new File(getContext().getDatabasePath(dbName + "_att"), id));
new File(getContext().getDatabasePath(dbName + "_att"), id));
Bitmap thumbnail = createThumbnail(type, in);
thumbnail = thumbnail.createScaledBitmap(thumbnail, width, height, true);
FileOutputStream out = new FileOutputStream(file);
@ -166,38 +188,45 @@ public class AttachmentProvider extends ContentProvider {
out.close();
in.close();
}
catch (IOException ioe) {
catch (IOException ioe)
{
return null;
}
}
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
else {
else
{
return ParcelFileDescriptor.open(
new File(getContext().getDatabasePath(dbName + "_att"), id),
ParcelFileDescriptor.MODE_READ_ONLY);
new File(getContext().getDatabasePath(dbName + "_att"), id),
ParcelFileDescriptor.MODE_READ_ONLY);
}
}
@Override
public int delete(Uri uri, String arg1, String[] arg2) {
public int delete(Uri uri, String arg1, String[] arg2)
{
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
if (projection == null) {
String sortOrder)
{
if (projection == null)
{
projection =
new String[] {
AttachmentProviderColumns._ID,
AttachmentProviderColumns.DATA,
};
new String[]
{
AttachmentProviderColumns._ID,
AttachmentProviderColumns.DATA,
};
}
List<String> segments = uri.getPathSegments();
@ -209,45 +238,55 @@ public class AttachmentProvider extends ContentProvider {
int size = -1;
SQLiteDatabase db = null;
Cursor cursor = null;
try {
try
{
db = SQLiteDatabase.openDatabase(path, null, 0);
cursor = db.query(
"attachments",
new String[] { "name", "size" },
"id = ?",
new String[] { id },
null,
null,
null);
if (!cursor.moveToFirst()) {
"attachments",
new String[] { "name", "size" },
"id = ?",
new String[] { id },
null,
null,
null);
if (!cursor.moveToFirst())
{
return null;
}
name = cursor.getString(0);
size = cursor.getInt(1);
}
finally {
if (cursor != null) {
finally
{
if (cursor != null)
{
cursor.close();
}
if (db != null) {
if (db != null)
{
db.close();
}
}
MatrixCursor ret = new MatrixCursor(projection);
Object[] values = new Object[projection.length];
for (int i = 0, count = projection.length; i < count; i++) {
for (int i = 0, count = projection.length; i < count; i++)
{
String column = projection[i];
if (AttachmentProviderColumns._ID.equals(column)) {
if (AttachmentProviderColumns._ID.equals(column))
{
values[i] = id;
}
else if (AttachmentProviderColumns.DATA.equals(column)) {
else if (AttachmentProviderColumns.DATA.equals(column))
{
values[i] = uri.toString();
}
else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) {
else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column))
{
values[i] = name;
}
else if (AttachmentProviderColumns.SIZE.equals(column)) {
else if (AttachmentProviderColumns.SIZE.equals(column))
{
values[i] = size;
}
}
@ -256,23 +295,29 @@ public class AttachmentProvider extends ContentProvider {
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
{
return 0;
}
private Bitmap createThumbnail(String type, InputStream data) {
if(MimeUtility.mimeTypeMatches(type, "image/*")) {
private Bitmap createThumbnail(String type, InputStream data)
{
if (MimeUtility.mimeTypeMatches(type, "image/*"))
{
return createImageThumbnail(data);
}
return null;
}
private Bitmap createImageThumbnail(InputStream data) {
try {
private Bitmap createImageThumbnail(InputStream data)
{
try
{
Bitmap bitmap = BitmapFactory.decodeStream(data);
return bitmap;
}
catch (OutOfMemoryError oome) {
catch (OutOfMemoryError oome)
{
/*
* Improperly downloaded images, corrupt bitmaps and the like can commonly
* cause OOME due to invalid allocation sizes. We're happy with a null bitmap in
@ -281,7 +326,8 @@ public class AttachmentProvider extends ContentProvider {
*/
return null;
}
catch (Exception e) {
catch (Exception e)
{
return null;
}
}

View file

@ -18,8 +18,9 @@ import android.util.Log;
import com.android.email.Email;
public class BootReceiver extends BroadcastReceiver {
public class BootReceiver extends BroadcastReceiver
{
public static String WAKE_LOCK_RELEASE = "com.android.email.service.BroadcastReceiver.wakeLockRelease";
public static String FIRE_INTENT = "com.android.email.service.BroadcastReceiver.fireIntent";
public static String SCHEDULE_INTENT = "com.android.email.service.BroadcastReceiver.scheduleIntent";
@ -28,10 +29,10 @@ public class BootReceiver extends BroadcastReceiver {
public static String WAKE_LOCK_ID = "com.android.email.service.BroadcastReceiver.wakeLockId";
public static String ALARMED_INTENT = "com.android.email.service.BroadcastReceiver.pendingIntent";
public static String AT_TIME = "com.android.email.service.BroadcastReceiver.atTime";
private static ConcurrentHashMap<Integer, WakeLock> wakeLocks = new ConcurrentHashMap<Integer, WakeLock>();
private static AtomicInteger wakeLockSeq = new AtomicInteger(0);
private Integer getWakeLock(Context context)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@ -42,7 +43,7 @@ public class BootReceiver extends BroadcastReceiver {
wakeLocks.put(tmpWakeLockId, wakeLock);
return tmpWakeLockId;
}
private void releaseWakeLock(Integer wakeLockId)
{
if (wakeLockId != null)
@ -58,31 +59,37 @@ public class BootReceiver extends BroadcastReceiver {
}
}
}
public void onReceive(Context context, Intent intent) {
public void onReceive(Context context, Intent intent)
{
Integer tmpWakeLockId = getWakeLock(context);
try
{
Log.i(Email.LOG_TAG, "BootReceiver.onReceive" + intent);
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Email.setServicesEnabled(context, tmpWakeLockId);
tmpWakeLockId = null;
Log.i(Email.LOG_TAG, "BootReceiver.onReceive" + intent);
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()))
{
Email.setServicesEnabled(context, tmpWakeLockId);
tmpWakeLockId = null;
}
else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(intent.getAction())) {
else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(intent.getAction()))
{
MailService.actionCancel(context, tmpWakeLockId);
tmpWakeLockId = null;
}
else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction())) {
else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(intent.getAction()))
{
MailService.actionReschedule(context, tmpWakeLockId);
tmpWakeLockId = null;
}
else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
{
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
MailService.connectivityChange(context, !noConnectivity, tmpWakeLockId);
tmpWakeLockId = null;
}
else if (ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED.equals(intent.getAction())) {
else if (ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED.equals(intent.getAction()))
{
MailService.backgroundDataChanged(context, tmpWakeLockId);
tmpWakeLockId = null;
}
@ -90,7 +97,7 @@ public class BootReceiver extends BroadcastReceiver {
{
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
String alarmedAction = alarmedIntent.getAction();
Log.i(Email.LOG_TAG, "BootReceiver Got alarm to fire alarmedIntent " + alarmedAction);
alarmedIntent.putExtra(WAKE_LOCK_ID, tmpWakeLockId);
tmpWakeLockId = null;
@ -104,21 +111,21 @@ public class BootReceiver extends BroadcastReceiver {
long atTime = intent.getLongExtra(AT_TIME, -1);
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
Log.i(Email.LOG_TAG,"BootReceiver Scheduling intent " + alarmedIntent + " for " + new Date(atTime));
PendingIntent pi = buildPendingIntent(context, intent);
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.set(AlarmManager.RTC_WAKEUP, atTime, pi);
alarmMgr.set(AlarmManager.RTC_WAKEUP, atTime, pi);
}
else if (CANCEL_INTENT.equals(intent.getAction()))
{
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
Log.i(Email.LOG_TAG, "BootReceiver Canceling alarmedIntent " + alarmedIntent);
PendingIntent pi = buildPendingIntent(context, intent);
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.cancel(pi);
alarmMgr.cancel(pi);
}
else if (BootReceiver.WAKE_LOCK_RELEASE.equals(intent.getAction()))
{
@ -135,7 +142,7 @@ public class BootReceiver extends BroadcastReceiver {
releaseWakeLock(tmpWakeLockId);
}
}
private PendingIntent buildPendingIntent(Context context, Intent intent)
{
Intent alarmedIntent = intent.getParcelableExtra(ALARMED_INTENT);
@ -149,7 +156,7 @@ public class BootReceiver extends BroadcastReceiver {
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
return pi;
}
public static void scheduleIntent(Context context, long atTime, Intent alarmedIntent)
{
Log.i(Email.LOG_TAG, "BootReceiver Got request to schedule alarmedIntent " + alarmedIntent.getAction());
@ -160,7 +167,7 @@ public class BootReceiver extends BroadcastReceiver {
i.putExtra(AT_TIME, atTime);
context.sendBroadcast(i);
}
public static void cancelIntent(Context context, Intent alarmedIntent)
{
Log.i(Email.LOG_TAG, "BootReceiver Got request to cancel alarmedIntent " + alarmedIntent.getAction());
@ -170,7 +177,7 @@ public class BootReceiver extends BroadcastReceiver {
i.putExtra(ALARMED_INTENT, alarmedIntent);
context.sendBroadcast(i);
}
public static void releaseWakeLock(Context context, int wakeLockId)
{
Log.i(Email.LOG_TAG, "BootReceiver Got request to release wakeLock " + wakeLockId);

View file

@ -12,7 +12,7 @@ import android.util.Log;
public abstract class CoreService extends Service
{
protected static void addWakeLockId(Intent i, Integer wakeLockId)
{
if (wakeLockId != null)
@ -20,23 +20,24 @@ public abstract class CoreService extends Service
i.putExtra(BootReceiver.WAKE_LOCK_ID, wakeLockId);
}
}
@Override
public void onStart(Intent intent, int startId) {
public void onStart(Intent intent, int startId)
{
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
wakeLock.setReferenceCounted(false);
wakeLock.acquire(Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT);
Log.i(Email.LOG_TAG, "CoreService: " + this.getClass().getName() + ".onStart(" + intent + ", " + startId);
int wakeLockId = intent.getIntExtra(BootReceiver.WAKE_LOCK_ID, -1);
if (wakeLockId != -1)
{
BootReceiver.releaseWakeLock(this, wakeLockId);
}
try
{
super.onStart(intent, startId);
@ -49,23 +50,24 @@ public abstract class CoreService extends Service
wakeLock.release();
}
}
}
public abstract void startService(Intent intent, int startId);
@Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void onDestroy() {
Log.i(Email.LOG_TAG, "CoreService: " + this.getClass().getName() + ".onDestroy()");
public void onDestroy()
{
Log.i(Email.LOG_TAG, "CoreService: " + this.getClass().getName() + ".onDestroy()");
super.onDestroy();
// MessagingController.getInstance(getApplication()).removeListener(mListener);
// MessagingController.getInstance(getApplication()).removeListener(mListener);
}
}

View file

@ -33,7 +33,8 @@ import com.android.email.mail.Pusher;
/**
*/
public class MailService extends CoreService {
public class MailService extends CoreService
{
private static final String ACTION_CHECK_MAIL = "com.android.email.intent.action.MAIL_SERVICE_WAKEUP";
private static final String ACTION_RESCHEDULE = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE";
private static final String ACTION_RESCHEDULE_CHECK = "com.android.email.intent.action.MAIL_SERVICE_RESCHEDULE_CHECK";
@ -42,37 +43,41 @@ public class MailService extends CoreService {
private static final String CONNECTIVITY_CHANGE = "com.android.email.intent.action.MAIL_SERVICE_CONNECTIVITY_CHANGE";
private static final String BACKGROUND_DATA_CHANGED = "com.android.email.intent.action.MAIL_SERVICE_BACKGROUND_DATA_CHANGED";
private static final String CANCEL_CONNECTIVITY_NOTICE = "com.android.email.intent.action.MAIL_SERVICE_CANCEL_CONNECTIVITY_NOTICE";
private static final String HAS_CONNECTIVITY = "com.android.email.intent.action.MAIL_SERVICE_HAS_CONNECTIVITY";
private final ExecutorService threadPool = Executors.newFixedThreadPool(1); // Must be single threaded
public static void actionReschedule(Context context, Integer wakeLockId) {
public static void actionReschedule(Context context, Integer wakeLockId)
{
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_RESCHEDULE);
addWakeLockId(i, wakeLockId);
context.startService(i);
}
public static void rescheduleCheck(Context context, Integer wakeLockId) {
public static void rescheduleCheck(Context context, Integer wakeLockId)
{
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_RESCHEDULE_CHECK);
addWakeLockId(i, wakeLockId);
context.startService(i);
}
public static void actionCancel(Context context, Integer wakeLockId) {
public static void actionCancel(Context context, Integer wakeLockId)
{
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.ACTION_CANCEL);
addWakeLockId(i, wakeLockId);
context.startService(i);
}
public static void connectivityChange(Context context, boolean hasConnectivity, Integer wakeLockId) {
public static void connectivityChange(Context context, boolean hasConnectivity, Integer wakeLockId)
{
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.CONNECTIVITY_CHANGE);
@ -80,8 +85,9 @@ public class MailService extends CoreService {
addWakeLockId(i, wakeLockId);
context.startService(i);
}
public static void backgroundDataChanged(Context context, Integer wakeLockId) {
public static void backgroundDataChanged(Context context, Integer wakeLockId)
{
Intent i = new Intent();
i.setClass(context, MailService.class);
i.setAction(MailService.BACKGROUND_DATA_CHANGED);
@ -90,13 +96,15 @@ public class MailService extends CoreService {
}
@Override
public void onCreate() {
super.onCreate();
Log.v(Email.LOG_TAG, "***** MailService *****: onCreate");
public void onCreate()
{
super.onCreate();
Log.v(Email.LOG_TAG, "***** MailService *****: onCreate");
}
@Override
public void startService(Intent intent, int startId) {
public void startService(Intent intent, int startId)
{
Integer startIdObj = startId;
long startTime = System.currentTimeMillis();
try
@ -104,7 +112,7 @@ public class MailService extends CoreService {
ConnectivityManager connectivityManager = (ConnectivityManager)getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
boolean doBackground = true;
boolean hasConnectivity = false;
if (connectivityManager != null)
{
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
@ -114,54 +122,61 @@ public class MailService extends CoreService {
hasConnectivity = state == State.CONNECTED;
}
boolean backgroundData = connectivityManager.getBackgroundDataSetting();
Email.BACKGROUND_OPS bOps = Email.getBackgroundOps();
doBackground = (backgroundData == true && bOps != Email.BACKGROUND_OPS.NEVER)
| (backgroundData == false && bOps == Email.BACKGROUND_OPS.ALWAYS);
doBackground = (backgroundData == true && bOps != Email.BACKGROUND_OPS.NEVER)
| (backgroundData == false && bOps == Email.BACKGROUND_OPS.ALWAYS);
}
setForeground(true); // if it gets killed once, it'll never restart
Log.i(Email.LOG_TAG, "MailService.onStart(" + intent + ", " + startId
+ "), hasConnectivity = " + hasConnectivity + ", doBackground = " + doBackground);
// MessagingController.getInstance(getApplication()).addListener(mListener);
if (ACTION_CHECK_MAIL.equals(intent.getAction())) {
Log.i(Email.LOG_TAG, "***** MailService *****: checking mail");
setForeground(true); // if it gets killed once, it'll never restart
Log.i(Email.LOG_TAG, "MailService.onStart(" + intent + ", " + startId
+ "), hasConnectivity = " + hasConnectivity + ", doBackground = " + doBackground);
// MessagingController.getInstance(getApplication()).addListener(mListener);
if (ACTION_CHECK_MAIL.equals(intent.getAction()))
{
Log.i(Email.LOG_TAG, "***** MailService *****: checking mail");
if (hasConnectivity && doBackground)
{
PollService.startService(this);
}
reschedule(startIdObj);
startIdObj = null;
}
else if (ACTION_CANCEL.equals(intent.getAction())) {
if (Config.LOGV) {
else if (ACTION_CANCEL.equals(intent.getAction()))
{
if (Config.LOGV)
{
Log.v(Email.LOG_TAG, "***** MailService *****: cancel");
}
MessagingController.getInstance(getApplication()).log("***** MailService *****: cancel");
cancel();
}
else if (ACTION_RESCHEDULE.equals(intent.getAction())) {
if (Config.LOGV) {
else if (ACTION_RESCHEDULE.equals(intent.getAction()))
{
if (Config.LOGV)
{
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule");
}
rescheduleAll(hasConnectivity, doBackground, startIdObj);
startIdObj = null;
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule");
}
else if (ACTION_RESCHEDULE_CHECK.equals(intent.getAction())) {
if (Config.LOGV) {
else if (ACTION_RESCHEDULE_CHECK.equals(intent.getAction()))
{
if (Config.LOGV)
{
Log.v(Email.LOG_TAG, "***** MailService *****: reschedule check");
}
reschedule(startIdObj);
startIdObj = null;
MessagingController.getInstance(getApplication()).log("***** MailService *****: reschedule");
}
else if (ACTION_REFRESH_PUSHERS.equals(intent.getAction()))
{
@ -173,7 +188,7 @@ public class MailService extends CoreService {
}
}
else if (CONNECTIVITY_CHANGE.equals(intent.getAction()) ||
BACKGROUND_DATA_CHANGED.equals(intent.getAction()))
BACKGROUND_DATA_CHANGED.equals(intent.getAction()))
{
notifyConnectionStatus(hasConnectivity);
rescheduleAll(hasConnectivity, doBackground, startIdObj);
@ -195,13 +210,13 @@ public class MailService extends CoreService {
long endTime = System.currentTimeMillis();
Log.i(Email.LOG_TAG, "MailService.onStart took " + (endTime - startTime) + "ms");
}
private void rescheduleAll(final boolean hasConnectivity, final boolean doBackground, final Integer startId)
{
if (hasConnectivity && doBackground)
{
reschedule(null);
reschedulePushers(startId);
reschedule(null);
reschedulePushers(startId);
}
else
{
@ -218,21 +233,21 @@ public class MailService extends CoreService {
{
String notice = getApplication().getString(R.string.no_connection_alert);
String header = getApplication().getString(R.string.alert_header);
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
header, System.currentTimeMillis());
header, System.currentTimeMillis());
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(MailService.CANCEL_CONNECTIVITY_NOTICE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
notif.setLatestEventInfo(getApplication(), header, notice, pi);
notif.flags = Notification.FLAG_ONGOING_EVENT;
notifMgr.notify(Email.CONNECTIVITY_ID, notif);
notifMgr.notify(Email.CONNECTIVITY_ID, notif);
}
else
{
@ -241,100 +256,110 @@ public class MailService extends CoreService {
}
@Override
public void onDestroy() {
Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()");
public void onDestroy()
{
Log.v(Email.LOG_TAG, "***** MailService *****: onDestroy()");
super.onDestroy();
// MessagingController.getInstance(getApplication()).removeListener(mListener);
// MessagingController.getInstance(getApplication()).removeListener(mListener);
}
private void cancel() {
private void cancel()
{
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL);
BootReceiver.cancelIntent(this, i);
}
private void reschedule(Integer startId) {
execute(getApplication(), new Runnable()
private void reschedule(Integer startId)
{
execute(getApplication(), new Runnable()
{
public void run()
{
int shortestInterval = -1;
for (Account account : Preferences.getPreferences(MailService.this).getAccounts()) {
for (Account account : Preferences.getPreferences(MailService.this).getAccounts())
{
if (account.getAutomaticCheckIntervalMinutes() != -1
&& (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1)) {
&& (account.getAutomaticCheckIntervalMinutes() < shortestInterval || shortestInterval == -1))
{
shortestInterval = account.getAutomaticCheckIntervalMinutes();
}
}
if (shortestInterval == -1) {
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
cancel();
if (shortestInterval == -1)
{
Log.v(Email.LOG_TAG, "No next check scheduled for package " + getApplication().getPackageName());
cancel();
}
else
{
long delay = (shortestInterval * (60 * 1000));
long nextTime = System.currentTimeMillis() + delay;
try
{
String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime);
Log.i(Email.LOG_TAG, checkString);
MessagingController.getInstance(getApplication()).log(checkString);
}
catch (Exception e)
{
// I once got a NullPointerException deep in new Date();
Log.e(Email.LOG_TAG, "Exception while logging", e);
}
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL);
long delay = (shortestInterval * (60 * 1000));
long nextTime = System.currentTimeMillis() + delay;
try
{
String checkString = "Next check for package " + getApplication().getPackageName() + " scheduled for " + new Date(nextTime);
Log.i(Email.LOG_TAG, checkString);
MessagingController.getInstance(getApplication()).log(checkString);
}
catch (Exception e)
{
// I once got a NullPointerException deep in new Date();
Log.e(Email.LOG_TAG, "Exception while logging", e);
}
Intent i = new Intent();
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_CHECK_MAIL);
BootReceiver.scheduleIntent(MailService.this, nextTime, i);
}
}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
private void stopPushers(final Integer startId)
{
execute(getApplication(), new Runnable()
execute(getApplication(), new Runnable()
{
public void run()
{
MessagingController.getInstance(getApplication()).stopAllPushing();
PushService.stopService(MailService.this);
}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId );
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
private void reschedulePushers(final Integer startId)
{
execute(getApplication(), new Runnable()
execute(getApplication(), new Runnable()
{
public void run()
{
Log.i(Email.LOG_TAG, "Rescheduling pushers");
stopPushers(null);
setupPushers(null);
schedulePushers(startId);
}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, null );
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, null);
}
private void setupPushers(final Integer startId)
{
execute(getApplication(), new Runnable()
execute(getApplication(), new Runnable()
{
public void run()
{
boolean pushing = false;
for (Account account : Preferences.getPreferences(MailService.this).getAccounts()) {
for (Account account : Preferences.getPreferences(MailService.this).getAccounts())
{
Log.i(Email.LOG_TAG, "Setting up pushers for account " + account.getDescription());
Pusher pusher = MessagingController.getInstance(getApplication()).setupPushing(account);
if (pusher != null)
@ -343,18 +368,19 @@ public class MailService extends CoreService {
Log.i(Email.LOG_TAG, "Starting configured pusher for account " + account.getDescription());
pusher.start();
}
}
}
if (pushing)
{
PushService.startService(MailService.this);
}
}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
private void refreshPushers(final Integer startId)
{
execute(getApplication(), new Runnable()
execute(getApplication(), new Runnable()
{
public void run()
{
@ -372,17 +398,18 @@ public class MailService extends CoreService {
Log.e(Email.LOG_TAG, "Exception while refreshing pushers", e);
}
}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId );
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
private void schedulePushers(final Integer startId)
{
execute(getApplication(), new Runnable()
execute(getApplication(), new Runnable()
{
public void run()
{
int minInterval = -1;
Collection<Pusher> pushers = MessagingController.getInstance(getApplication()).getPushers();
for (Pusher pusher : pushers)
{
@ -408,10 +435,12 @@ public class MailService extends CoreService {
i.setClassName(getApplication().getPackageName(), "com.android.email.service.MailService");
i.setAction(ACTION_REFRESH_PUSHERS);
BootReceiver.scheduleIntent(MailService.this, nextTime, i);
}}
}, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
}
}
, Email.MAIL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
public void execute(Context context, final Runnable runner, int wakeLockTime, final Integer startId)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@ -439,15 +468,16 @@ public class MailService extends CoreService {
}
}
}
};
threadPool.execute(myRunner);
}
public IBinder onBind(Intent intent) {
public IBinder onBind(Intent intent)
{
return null;
}
}

View file

@ -22,43 +22,45 @@ public class PollService extends CoreService
private static String STOP_SERVICE = "com.android.email.service.PollService.stopService";
private Listener mListener = new Listener();
public static void startService(Context context) {
public static void startService(Context context)
{
Intent i = new Intent();
i.setClass(context, PollService.class);
i.setAction(PollService.START_SERVICE);
context.startService(i);
}
public static void stopService(Context context) {
public static void stopService(Context context)
{
Intent i = new Intent();
i.setClass(context, PollService.class);
i.setAction(PollService.STOP_SERVICE);
context.startService(i);
}
@Override
public void startService(Intent intent, int startId)
{
if (START_SERVICE.equals(intent.getAction()))
if (START_SERVICE.equals(intent.getAction()))
{
Log.i(Email.LOG_TAG, "PollService started with startId = " + startId);
MessagingController controller = MessagingController.getInstance(getApplication());
Listener listener = (Listener)controller.getCheckMailListener();
if (listener == null)
{
MessagingController.getInstance(getApplication()).log("***** PollService *****: starting new check");
mListener.setStartId(startId);
mListener.wakeLockAcquire();
controller.setCheckMailListener(mListener);
controller.checkMail(this, null, false, false, mListener);
MessagingController.getInstance(getApplication()).log("***** PollService *****: starting new check");
mListener.setStartId(startId);
mListener.wakeLockAcquire();
controller.setCheckMailListener(mListener);
controller.checkMail(this, null, false, false, mListener);
}
else
{
MessagingController.getInstance(getApplication()).log("***** PollService *****: renewing WakeLock");
listener.setStartId(startId);
listener.wakeLockAcquire();
MessagingController.getInstance(getApplication()).log("***** PollService *****: renewing WakeLock");
listener.setStartId(startId);
listener.wakeLockAcquire();
}
}
else if (STOP_SERVICE.equals(intent.getAction()))
@ -66,16 +68,17 @@ public class PollService extends CoreService
Log.i(Email.LOG_TAG, "PollService stopping");
stopSelf();
}
}
@Override
public IBinder onBind(Intent arg0)
{
return null;
}
class Listener extends MessagingListener {
class Listener extends MessagingListener
{
HashMap<String, Integer> accountsChecked = new HashMap<String, Integer>();
private WakeLock wakeLock = null;
private int startId = -1;
@ -84,7 +87,7 @@ public class PollService extends CoreService
// don't want to take the chance of running wild
public synchronized void wakeLockAcquire()
{
WakeLock oldWakeLock = wakeLock;
WakeLock oldWakeLock = wakeLock;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
@ -93,7 +96,7 @@ public class PollService extends CoreService
if (oldWakeLock != null)
{
oldWakeLock.release();
oldWakeLock.release();
}
}
@ -106,28 +109,32 @@ public class PollService extends CoreService
}
}
@Override
public void checkMailStarted(Context context, Account account) {
public void checkMailStarted(Context context, Account account)
{
accountsChecked.clear();
}
@Override
public void checkMailFailed(Context context, Account account, String reason) {
public void checkMailFailed(Context context, Account account, String reason)
{
release();
}
@Override
public void synchronizeMailboxFinished(
Account account,
String folder,
int totalMessagesInMailbox,
int numNewMessages) {
if (account.isNotifyNewMail()) {
Integer existingNewMessages = accountsChecked.get(account.getUuid());
if (existingNewMessages == null)
{
existingNewMessages = 0;
}
accountsChecked.put(account.getUuid(), existingNewMessages + numNewMessages);
Account account,
String folder,
int totalMessagesInMailbox,
int numNewMessages)
{
if (account.isNotifyNewMail())
{
Integer existingNewMessages = accountsChecked.get(account.getUuid());
if (existingNewMessages == null)
{
existingNewMessages = 0;
}
accountsChecked.put(account.getUuid(), existingNewMessages + numNewMessages);
}
}
@ -138,40 +145,42 @@ public class PollService extends CoreService
return;
}
for (Account thisAccount : Preferences.getPreferences(context).getAccounts()) {
for (Account thisAccount : Preferences.getPreferences(context).getAccounts())
{
Integer newMailCount = accountsChecked.get(thisAccount.getUuid());
if (newMailCount != null)
{
try
{
int unreadMessageCount = thisAccount.getUnreadMessageCount(context, getApplication());
MessagingController.getInstance(getApplication()).notifyAccount(context, thisAccount,
MessagingController.getInstance(getApplication()).notifyAccount(context, thisAccount,
newMailCount, unreadMessageCount);
}
catch (MessagingException me)
{
Log.e(Email.LOG_TAG, "***** PollService *****: couldn't get unread count for account " +
thisAccount.getDescription(), me);
thisAccount.getDescription(), me);
}
}
}//for accounts
}//checkMailDone
private void release()
{
MessagingController controller = MessagingController.getInstance(getApplication());
controller.setCheckMailListener(null);
MailService.rescheduleCheck(PollService.this, null);
wakeLockRelease();
Log.i(Email.LOG_TAG, "PollService stopping with startId = " + startId);
stopSelf(startId);
MessagingController controller = MessagingController.getInstance(getApplication());
controller.setCheckMailListener(null);
MailService.rescheduleCheck(PollService.this, null);
wakeLockRelease();
Log.i(Email.LOG_TAG, "PollService stopping with startId = " + startId);
stopSelf(startId);
}
@Override
public void checkMailFinished(Context context, Account account) {
public void checkMailFinished(Context context, Account account)
{
Log.v(Email.LOG_TAG, "***** PollService *****: checkMailFinished");
try
@ -180,7 +189,7 @@ public class PollService extends CoreService
}
finally
{
release();
release();
}
}
public int getStartId()
@ -192,5 +201,5 @@ public class PollService extends CoreService
this.startId = startId;
}
}
}

View file

@ -11,21 +11,23 @@ public class PushService extends CoreService
{
private static String START_SERVICE = "com.android.email.service.PushService.startService";
private static String STOP_SERVICE = "com.android.email.service.PushService.stopService";
public static void startService(Context context) {
public static void startService(Context context)
{
Intent i = new Intent();
i.setClass(context, PushService.class);
i.setAction(PushService.START_SERVICE);
context.startService(i);
}
public static void stopService(Context context) {
public static void stopService(Context context)
{
Intent i = new Intent();
i.setClass(context, PushService.class);
i.setAction(PushService.STOP_SERVICE);
context.startService(i);
}
@Override
public void startService(Intent intent, int startId)
{
@ -38,9 +40,9 @@ public class PushService extends CoreService
Log.i(Email.LOG_TAG, "PushService stopping with startId = " + startId);
stopSelf(startId);
}
}
@Override
public IBinder onBind(Intent arg0)
{

View file

@ -14,15 +14,15 @@ import com.android.email.Email;
public class SleepService extends CoreService
{
private static String ALARM_FIRED = "com.android.email.service.SleepService.ALARM_FIRED";
private static String LATCH_ID = "com.android.email.service.SleepService.LATCH_ID_EXTRA";
private static ConcurrentHashMap<Integer, SleepDatum> sleepData = new ConcurrentHashMap<Integer, SleepDatum>();
private static AtomicInteger latchId = new AtomicInteger();
public static void sleep(Context context, long sleepTime, WakeLock wakeLock, long wakeLockTimeout)
{
Integer id = latchId.getAndIncrement();
@ -34,7 +34,7 @@ public class SleepService extends CoreService
CountDownLatch latch = new CountDownLatch(1);
sleepDatum.latch = latch;
sleepData.put(id, sleepDatum);
Intent i = new Intent();
i.setClassName(context.getPackageName(), "com.android.email.service.SleepService");
i.putExtra(LATCH_ID, id);
@ -57,7 +57,7 @@ public class SleepService extends CoreService
{
Log.d(Email.LOG_TAG, "SleepService latch timed out for id = " + id + ", thread " + Thread.currentThread().getName());
}
// don't call endSleep here or remove the sleepDatum here, instead of the following block.
// don't call endSleep here or remove the sleepDatum here, instead of the following block.
// We might not get the wakeLock before
// falling asleep again, so we have to get the wakeLock *first* The alarmed version will
// already be running in a WakeLock due to the nature of AlarmManager
@ -68,7 +68,7 @@ public class SleepService extends CoreService
// OK, we have the wakeLock, now we can remove the sleepDatum
sleepData.remove(id);
}
}
}
catch (InterruptedException ie)
@ -86,7 +86,7 @@ public class SleepService extends CoreService
Log.w(Email.LOG_TAG, "SleepService sleep time too short: requested was " + sleepTime + ", actual was " + actualSleep);
}
}
private static void endSleep(Integer id)
{
if (id != -1)
@ -118,13 +118,13 @@ public class SleepService extends CoreService
}
}
}
private static void reacquireWakeLock(SleepDatum sleepDatum)
{
WakeLock wakeLock = sleepDatum.wakeLock;
if (wakeLock != null)
{
synchronized(wakeLock)
synchronized (wakeLock)
{
long timeout = sleepDatum.timeout;
if (Email.DEBUG)
@ -139,13 +139,14 @@ public class SleepService extends CoreService
@Override
public void startService(Intent intent, int startId)
{
if (intent.getAction().startsWith(ALARM_FIRED)) {
if (intent.getAction().startsWith(ALARM_FIRED))
{
Integer id = intent.getIntExtra(LATCH_ID, -1);
endSleep(id);
}
stopSelf(startId);
}
private static class SleepDatum
{
CountDownLatch latch;