Merge the 2019-01-01 SPL branch from AOSP-Partner
* security-aosp-nyc-mr2-release:
AOSP/Email - Second part of the Security Vulnerability fix - Email App: Malicious app is able to compose message with hidden attachments and bypass attachments path checks attaching private files from /data/data/com.android.email/*
Change-Id: Ief952cec19ee7fd07d89da363d80ad2c414989e7
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
old mode 100644
new mode 100755
index ae13064..5b3ad9c
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -47,7 +47,7 @@
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<!-- This needs to be present when we are doing unbundled releases. -->
- <uses-sdk android:targetSdkVersion="21" android:minSdkVersion="14" />
+ <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="14" />
<!-- additional uses -->
@@ -241,7 +241,7 @@
android:label="@string/app_name"
android:name="com.android.email2.ui.MailActivityEmail"
android:theme="@style/MailActivityTheme"
- android:windowSoftInputMode="stateAlwaysHidden">
+ android:windowSoftInputMode="stateAlwaysHidden|adjustPan">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -293,7 +293,7 @@
<activity
android:name=".activity.setup.EmailPreferenceActivity"
android:label="@string/activity_preferences"
- android:exported="false" >
+ android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
@@ -331,12 +331,13 @@
Incoming Account Settings fragment -->
<activity
android:name=".activity.setup.HeadlessAccountSettingsLoader"
- android:theme="@android:style/Theme.NoDisplay"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="com.android.email.ACCOUNT_SETTINGS" />
+ <data android:host="com.android.email.ACCOUNT_SECURITY" />
<data android:scheme="auth"/>
</intent-filter>
</activity>
@@ -374,7 +375,7 @@
<activity
android:name="com.android.mail.browse.EmlViewerActivity"
android:label="@string/app_name"
- android:theme="@style/UnifiedEmailTheme" >
+ android:theme="@style/EmlViewerTheme.Appcompat" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -393,6 +394,11 @@
android:label="@string/open_source_licenses">
</activity>
+ <activity android:name="com.android.email.activity.RequestPermissionsActivity" >
+ </activity>
+ <activity android:name="com.android.email.activity.RequestPermissionsActivityBase" >
+ </activity>
+
<!-- additional activities -->
<provider
@@ -485,6 +491,42 @@
android:host="36245" />
</intent-filter>
</receiver>
+ <receiver
+ android:name=".service.BluetoothEmailBroadcastReceiver"
+ android:enabled="true"
+ android:permission="com.android.email.permission.ACCESS_PROVIDER">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
+ <action android:name="android.intent.action.DEVICE_STORAGE_OK" />
+ <action android:name="android.intent.action.LOCALE_CHANGED"/>
+ <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <action android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_WAKEUP" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_DELETE_MESSAGE" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_MOVE_MESSAGE" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_MESSAGE_READ" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_SEND_PENDING" />
+ </intent-filter>
+ <!-- To handle new message notifications -->
+ <intent-filter>
+ <action android:name="com.android.mail.action.update_notification"
+ android:priority="-10" />
+ <data android:mimeType="@string/application_mime_type" />
+ </intent-filter>
+ <!-- To handle secret code to activate the debug screen. -->
+ <intent-filter>
+ <action
+ android:name="android.provider.Telephony.SECRET_CODE" />
+ <!-- "36245" = "email" -->
+ <data
+ android:scheme="android_secret_code"
+ android:host="36245" />
+ </intent-filter>
+ </receiver>
<service
android:name=".service.EmailBroadcastProcessorService" />
@@ -596,6 +638,24 @@
android:name="com.android.email.IMAP_INTENT" />
</intent-filter>
</service>
+ <service
+ android:name=".service.BluetoothImapService"
+ android:enabled="true"
+ android:permission="com.android.email.permission.ACCESS_PROVIDER"
+ >
+ <intent-filter>
+ <action
+ android:name="com.android.email.IMAP_INTENT" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_DELETE_MESSAGE" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_MOVE_MESSAGE" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_MESSAGE_READ" />
+ <action
+ android:name="org.codeaurora.email.intent.action.MAIL_SERVICE_SEND_PENDING" />
+ </intent-filter>
+ </service>
<service
android:name=".service.Pop3Service"
@@ -607,6 +667,16 @@
android:name="com.android.email.POP3_INTENT" />
</intent-filter>
</service>
+ <service
+ android:name=".service.BluetoothPop3Service"
+ android:enabled="true"
+ android:permission="com.android.email.permission.ACCESS_PROVIDER"
+ >
+ <intent-filter>
+ <action
+ android:name="com.android.email.POP3_INTENT" />
+ </intent-filter>
+ </service>
<!--Required stanza to register the EasAuthenticatorService with AccountManager -->
<service
@@ -623,6 +693,307 @@
android:resource="@xml/authenticator_eas"
/>
</service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultFirstAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_first"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultSecondAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_second"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultThirdAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_third"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultFourthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_fourth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultFifthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_fifth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultSixthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_sixth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultSeventhAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_seventh"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultEighthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_eighth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultNinthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_ninth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultTenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_tenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultEleventhAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_eleventh"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultTwelfthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_twelfth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultThirteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_thirteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultFourteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_fourteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultFifteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_fifteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultSixteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_sixteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultSeventeenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_seventeenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultEighteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_eighteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultNinteenthAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_ninteenth"
+ />
+ </service>
+
+ <service
+ android:name=".service.ExtendAuthenticatorService$DefaultTwentithAuthenticatorService"
+ android:exported="true"
+ android:enabled="true"
+ >
+ <intent-filter>
+ <action
+ android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data
+ android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator_default_twentith"
+ />
+ </service>
+
<!--Required stanza to register the EasTestAuthenticatorService with AccountManager -->
<service
android:name=".service.EasTestAuthenticatorService"
diff --git a/emailcommon/res/values/strings.xml b/emailcommon/res/values/strings.xml
index a13f4c7..fa126bb 100644
--- a/emailcommon/res/values/strings.xml
+++ b/emailcommon/res/values/strings.xml
@@ -41,4 +41,6 @@
<!-- Do Not Translate. This is the authority for the email package name -->
<string name="email_package_name" translatable="false">com.android.email</string>
+
+ <string name="missed_exchange_required_permission">Click Permissions,add Required Permissions</string>
</resources>
diff --git a/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java b/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java
old mode 100644
new mode 100755
index d7486ee..d3fbddf
--- a/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java
+++ b/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java
@@ -282,6 +282,15 @@
"when sending attachment");
throw new MessagingException("Invalid attachment.", ioe);
}
+ finally {
+ try {
+ if (inStream != null) {
+ inStream.close();
+ }
+ } catch (IOException e) {
+ LogUtils.e(TAG, e, "Failed to close stream");
+ }
+ }
}
/**
diff --git a/emailcommon/src/com/android/emailcommon/provider/Account.java b/emailcommon/src/com/android/emailcommon/provider/Account.java
index 5a3ab7f..b13c602 100755
--- a/emailcommon/src/com/android/emailcommon/provider/Account.java
+++ b/emailcommon/src/com/android/emailcommon/provider/Account.java
@@ -31,6 +31,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.utility.Utility;
import com.android.mail.utils.LogUtils;
import com.google.common.annotations.VisibleForTesting;
@@ -150,6 +151,10 @@
public transient HostAuth mHostAuthSend;
public transient Policy mPolicy;
+ // To save the sync size of this account.
+ public int mSetSyncSizeEnabled;
+ public int mSyncSize;
+
// Marks this account as being a temporary entry, so we know to use it directly and not go
// through the database or any caches
private transient boolean mTemporary;
@@ -171,6 +176,8 @@
public static final int CONTENT_POLICY_KEY_COLUMN = 14;
public static final int CONTENT_PING_DURATION_COLUMN = 15;
public static final int CONTENT_MAX_ATTACHMENT_SIZE_COLUMN = 16;
+ public static final int CONTENT_SET_SYNC_SIZE_ENABLED_COLUMN = 17;
+ public static final int CONTENT_SYNC_SIZE_COLUMN = 18;
public static final String[] CONTENT_PROJECTION = {
AttachmentColumns._ID, AccountColumns.DISPLAY_NAME,
@@ -181,7 +188,8 @@
AccountColumns.RINGTONE_URI, AccountColumns.PROTOCOL_VERSION,
AccountColumns.SECURITY_SYNC_KEY,
AccountColumns.SIGNATURE, AccountColumns.POLICY_KEY, AccountColumns.PING_DURATION,
- AccountColumns.MAX_ATTACHMENT_SIZE
+ AccountColumns.MAX_ATTACHMENT_SIZE, AccountColumns.SET_SYNC_SIZE_ENABLED,
+ AccountColumns.SYNC_SIZE
};
public static final int ACCOUNT_FLAGS_COLUMN_ID = 0;
@@ -204,6 +212,8 @@
mSyncInterval = -1;
mSyncLookback = -1;
mFlags = 0;
+ mSetSyncSizeEnabled = SyncSize.ENABLED_DEFAULT_VALUE;
+ mSyncSize = SyncSize.SYNC_SIZE_ENTIRE_MAIL;
}
public static Account restoreAccountWithId(Context context, long id) {
@@ -279,6 +289,8 @@
mSignature = cursor.getString(CONTENT_SIGNATURE_COLUMN);
mPolicyKey = cursor.getLong(CONTENT_POLICY_KEY_COLUMN);
mPingDuration = cursor.getLong(CONTENT_PING_DURATION_COLUMN);
+ mSetSyncSizeEnabled = cursor.getInt(CONTENT_SET_SYNC_SIZE_ENABLED_COLUMN);
+ mSyncSize = cursor.getInt(CONTENT_SYNC_SIZE_COLUMN);
}
public boolean isTemporary() {
@@ -403,6 +415,39 @@
}
/**
+ * @return If this account enabled the sync size function, return true.
+ */
+ public boolean isSetSyncSizeEnabled() {
+ return mSetSyncSizeEnabled == SyncSize.ENABLED ? true : false;
+ }
+
+ /**
+ * Set the sync size function if enabled for this account.
+ * @param enabled the state of sync size function for this account.
+ */
+ public void setSyncSizeEnabled(boolean enabled) {
+ mSetSyncSizeEnabled = enabled ? SyncSize.ENABLED : SyncSize.DISABLED;
+ }
+
+ /**
+ * @return The max size per mail will be sync from service
+ * TODO define the values for "all", "20KB", "100KB", etc. See arrays.xml
+ */
+ public int getSyncSize() {
+ return mSyncSize;
+ }
+
+ /**
+ * Set the max size per mail will be sync from service. Be sure to call save() to
+ * commit to database.
+ * TODO define the values for "all", "20KB", "100KB", etc. See arrays.xml
+ * @param size the max size per mail would be sync from service.
+ */
+ public void setSyncSize(int size) {
+ mSyncSize = size;
+ }
+
+ /**
* @return the flags for this account
*/
public int getFlags() {
@@ -749,6 +794,8 @@
values.put(AccountColumns.SIGNATURE, mSignature);
values.put(AccountColumns.POLICY_KEY, mPolicyKey);
values.put(AccountColumns.PING_DURATION, mPingDuration);
+ values.put(AccountColumns.SET_SYNC_SIZE_ENABLED, mSetSyncSizeEnabled);
+ values.put(AccountColumns.SYNC_SIZE, mSyncSize);
return values;
}
@@ -889,6 +936,8 @@
dest.writeString(mSecuritySyncKey);
dest.writeString(mSignature);
dest.writeLong(mPolicyKey);
+ dest.writeInt(mSetSyncSizeEnabled);
+ dest.writeInt(mSyncSize);
if (mHostAuthRecv != null) {
dest.writeByte((byte)1);
@@ -927,6 +976,8 @@
mSecuritySyncKey = in.readString();
mSignature = in.readString();
mPolicyKey = in.readLong();
+ mSetSyncSizeEnabled = in.readInt();
+ mSyncSize = in.readInt();
mHostAuthRecv = null;
if (in.readByte() == 1) {
diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
index 28826fd..3c6060e 100755
--- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
+++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java
@@ -34,9 +34,11 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.provider.BaseColumns;
+import android.text.TextUtils;
import com.android.emailcommon.Logging;
import com.android.emailcommon.R;
+import com.android.emailcommon.service.SearchParams;
import com.android.emailcommon.utility.TextUtilities;
import com.android.emailcommon.utility.Utility;
import com.android.mail.providers.UIProvider;
@@ -513,8 +515,8 @@
// Assign values for each row.
values.put(BodyColumns.MESSAGE_KEY, mMessageKey);
- values.put(BodyColumns.HTML_CONTENT, mHtmlContent);
- values.put(BodyColumns.TEXT_CONTENT, mTextContent);
+ values.put(BodyColumns.HTML_CONTENT, Utility.compress(mHtmlContent));
+ values.put(BodyColumns.TEXT_CONTENT, Utility.compress(mTextContent));
values.put(BodyColumns.SOURCE_MESSAGE_KEY, mSourceKey);
return values;
}
@@ -827,8 +829,9 @@
*/
public static final String FLAG_LOADED_SELECTION =
MessageColumns.FLAG_LOADED + " IN ("
- + Message.FLAG_LOADED_PARTIAL + "," + Message.FLAG_LOADED_COMPLETE
- + ")";
+ + Message.FLAG_LOADED_PARTIAL + "," + Message.FLAG_LOADED_COMPLETE + ","
+ + Message.FLAG_LOADED_PARTIAL_COMPLETE + ","
+ + Message.FLAG_LOADED_PARTIAL_FETCHING +")";
public static final String ALL_FAVORITE_SELECTION =
MessageColumns.FLAG_FAVORITE + "=1 AND "
@@ -939,8 +942,10 @@
public static final int FLAG_LOADED_UNLOADED = 0;
public static final int FLAG_LOADED_COMPLETE = 1;
public static final int FLAG_LOADED_PARTIAL = 2;
- public static final int FLAG_LOADED_DELETED = 3;
- public static final int FLAG_LOADED_UNKNOWN = 4;
+ public static final int FLAG_LOADED_PARTIAL_COMPLETE = 3;
+ public static final int FLAG_LOADED_PARTIAL_FETCHING = 4;
+ public static final int FLAG_LOADED_DELETED = 5;
+ public static final int FLAG_LOADED_UNKNOWN = 6;
// Bits used in mFlags
// The following three states are mutually exclusive, and indicate whether the message is an
@@ -1163,10 +1168,10 @@
// Create and save the body
ContentValues cv = new ContentValues();
if (mText != null) {
- cv.put(BodyColumns.TEXT_CONTENT, mText);
+ cv.put(BodyColumns.TEXT_CONTENT, Utility.compress(mText));
}
if (mHtml != null) {
- cv.put(BodyColumns.HTML_CONTENT, mHtml);
+ cv.put(BodyColumns.HTML_CONTENT, Utility.compress(mHtml));
}
if (mSourceKey != 0) {
cv.put(BodyColumns.SOURCE_MESSAGE_KEY, mSourceKey);
@@ -1288,6 +1293,65 @@
: Message.FLAG_TYPE_FORWARD;
}
}
+
+
+ public static String buildLocalSearchSelection(Context context, long mailboxId,
+ String queryFilter, String queryFactor) {
+ StringBuilder selection = new StringBuilder();
+ selection.append(" (");
+ queryFilter = queryFilter.replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll("%", "\\\\%")
+ .replaceAll("_", "\\\\_")
+ .replaceAll("'", "''");
+ String[] queryFilters = queryFilter.split(" +");
+
+ boolean isAll = false;
+ if (queryFactor.contains(SearchParams.SEARCH_FACTOR_ALL)) {
+ isAll = true;
+ }
+ if (queryFactor.contains(SearchParams.SEARCH_FACTOR_SUBJECT) || isAll) {
+ selection.append(buildSelectionClause(queryFilters, MessageColumns.SUBJECT));
+ }
+ if (queryFactor.contains(SearchParams.SEARCH_FACTOR_SENDER) || isAll) {
+ selection.append(buildSelectionClause(queryFilters, MessageColumns.FROM_LIST));
+ }
+ if (queryFactor.contains(SearchParams.SEARCH_FACTOR_RECEIVER) || isAll) {
+ selection.append(buildSelectionClause(queryFilters, null));
+ }
+
+ selection.delete(selection.length() - " or ".length(), selection.length());
+ selection.append(")");
+ return selection.toString();
+ }
+
+ private static String buildSelectionClause(String[] queryFilters, String queryFactor) {
+ StringBuilder clause = new StringBuilder();
+ clause.append('(');
+ // if text is null that factor is receiver,otherwish the factor is subject or sender
+ if (TextUtils.isEmpty(queryFactor)) {
+ for (int i = 0; i < queryFilters.length; i++) {
+ clause.append('(');
+ clause.append("lower(").append(MessageColumns.TO_LIST).append(") like \'%")
+ .append(queryFilters[i].toLowerCase()).append("%\' escape \'\\'")
+ .append(" or ").append("lower(")
+ .append(MessageColumns.CC_LIST).append(") like \'%")
+ .append(queryFilters[i].toLowerCase())
+ .append("%\' escape \'\\') and ");
+ }
+ } else {
+ for (int i = 0; i < queryFilters.length; i++) {
+ clause.append("lower(").append(queryFactor).append(") like \'%")
+ .append(queryFilters[i].toLowerCase()).append("%\' escape \'\\'")
+ .append(" and ");
+ }
+ }
+
+ clause.delete(clause.length() - " and ".length(), clause.length());
+ clause.append(')');
+ clause.append(" or ");
+ return clause.toString();
+ }
+
}
public interface AttachmentColumns extends BaseColumns {
@@ -1721,6 +1785,10 @@
public static final String MAX_ATTACHMENT_SIZE = "maxAttachmentSize";
// Current duration of the Exchange ping
public static final String PING_DURATION = "pingDuration";
+ // If the user could set the sync size for this account.
+ public static final String SET_SYNC_SIZE_ENABLED = "setSyncSizeEnabled";
+ // The sync size for each message of this account.
+ public static final String SYNC_SIZE = "syncSize";
}
public interface QuickResponseColumns extends BaseColumns {
diff --git a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
index 36a0d33..2ba5ec1 100644
--- a/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
+++ b/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java
@@ -248,6 +248,22 @@
}
/**
+ * Request the sync adapter to load a complete message; the service MUST give higher priority
+ * to non-background loading.
+ *
+ * @param messageId the id of the message to be loaded
+ */
+ @Override
+ public void loadMore(final long messageId) throws RemoteException {
+ setTask(new ProxyTask() {
+ @Override
+ public void run() throws RemoteException {
+ mService.loadMore(messageId);
+ }
+ }, "loadMore");
+ }
+
+ /**
* Request the service to delete the account's PIM (personal information management) data. This
* data includes any data that is 1) associated with the account and 2) created/stored by the
* service or its sync adapters and 3) not stored in the EmailProvider database (e.g. contact
diff --git a/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl b/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl
index a6f49dc..cd0cf75 100644
--- a/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl
+++ b/emailcommon/src/com/android/emailcommon/service/IEmailService.aidl
@@ -30,6 +30,9 @@
oneway void loadAttachment(IEmailServiceCallback cb, long accountId, long attachmentId,
boolean background);
+ // Used to load uncompleted message.
+ oneway void loadMore(long messageId);
+
void updateFolderList(long accountId);
// TODO: For Eas, sync() will also sync the outbox. We should make IMAP and POP work the same
diff --git a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
index 3669345..b59c4d5 100644
--- a/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
+++ b/emailcommon/src/com/android/emailcommon/service/ServiceProxy.java
@@ -17,20 +17,28 @@
package com.android.emailcommon.service;
+import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
import android.os.AsyncTask;
import android.os.Debug;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
+import android.widget.Toast;
+import com.android.emailcommon.R;
import com.android.emailcommon.provider.EmailContent;
import com.android.mail.utils.LogUtils;
-
/**
* ServiceProxy is a superclass for proxy objects which make a single call to a service. It handles
* connecting to the service, running a task supplied by the subclass when the connection is ready,
@@ -87,6 +95,8 @@
*/
public abstract void onConnected(IBinder binder);
+ private Handler mHandler;
+ private static final int TIPS = 1;
public ServiceProxy(Context _context, Intent _intent) {
mContext = _context;
mIntent = _intent;
@@ -94,6 +104,42 @@
if (Debug.isDebuggerConnected()) {
mTimeout <<= 2;
}
+ mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case TIPS:
+ Toast.makeText(mContext, mContext.getResources()
+ .getString(R.string.missed_exchange_required_permission),
+ Toast.LENGTH_LONG).show();
+ mContext.startActivity(getAppDetailSettingIntent(mContext));
+ break;
+ default:
+ break;
+ }
+ }
+ };
+ }
+
+ private final static String SETTING_ACTION = "android.settings.APPLICATION_DETAILS_SETTINGS";
+ private final static String PACKAGE = "package";
+ private final static String EXCHANGE_PACKAGE_NAME = "com.android.exchange";
+ private final static String SETTING_PACKAGE_NAME = "com.android.settings";
+ private final static String CLASS_INSTALLEDAPPDETAILS = "com.android.settings.InstalledAppDetails";
+ private final static String CLASS_APPLICATIONPKGNAME = "com.android.settings.ApplicationPkgName";
+
+ private Intent getAppDetailSettingIntent(Context context) {
+ Intent localIntent = new Intent();
+ localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (Build.VERSION.SDK_INT >= 9) {
+ localIntent.setAction(SETTING_ACTION);
+ localIntent.setData(Uri.fromParts(PACKAGE, EXCHANGE_PACKAGE_NAME, null));
+ } else if (Build.VERSION.SDK_INT <= 8) {
+ localIntent.setAction(Intent.ACTION_VIEW);
+ localIntent.setClassName(SETTING_PACKAGE_NAME, CLASS_INSTALLEDAPPDETAILS);
+ localIntent.putExtra(CLASS_APPLICATIONPKGNAME, EXCHANGE_PACKAGE_NAME);
+ }
+ return localIntent;
}
private class ProxyConnection implements ServiceConnection {
@@ -115,6 +161,8 @@
mTask.run();
} catch (RemoteException e) {
LogUtils.e(mTag, e, "RemoteException thrown running mTask!");
+ } catch (java.lang.SecurityException e) {
+ mHandler.sendEmptyMessage(TIPS);
} finally {
// Make sure that we unbind the mConnection even on exceptions in the
// task provided by the subclass.
diff --git a/emailcommon/src/com/android/emailcommon/service/SyncSize.java b/emailcommon/src/com/android/emailcommon/service/SyncSize.java
new file mode 100644
index 0000000..36aea9f
--- /dev/null
+++ b/emailcommon/src/com/android/emailcommon/service/SyncSize.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.emailcommon.service;
+
+public class SyncSize {
+ /**
+ * 1 means the sync size function is enabled, others means the sync size
+ * function is disabled.
+ */
+ public static final int ENABLED = 1;
+ public static final int DISABLED = 0;
+
+ public static final int SYNC_SIZE_ENTIRE_MAIL = Integer.MAX_VALUE;
+ public static final int SYNC_SIZE_20_K = 20480;
+ public static final int SYNC_SIZE_100_K = 102400;
+ public static final int SYNC_SIZE_200_K = 204800;
+ public static final int SYNC_SIZE_500_K = 512000;
+ public static final int SYNC_SIZE_1_M = 1024000;
+
+ public static final int ENABLED_DEFAULT_VALUE = ENABLED;
+ public static final int SYNC_SIZE_DEFAULT_VALUE = SYNC_SIZE_200_K;
+}
diff --git a/emailcommon/src/com/android/emailcommon/utility/AttachmentUtilities.java b/emailcommon/src/com/android/emailcommon/utility/AttachmentUtilities.java
index 407a903..5c3df3e 100644
--- a/emailcommon/src/com/android/emailcommon/utility/AttachmentUtilities.java
+++ b/emailcommon/src/com/android/emailcommon/utility/AttachmentUtilities.java
@@ -398,16 +398,38 @@
final ContentValues cv = new ContentValues();
final long attachmentId = attachment.mId;
final long accountId = attachment.mAccountKey;
- final String contentUri;
- final long size;
+ String contentUri = null;
+ long size = attachment.mSize;
try {
ContentResolver resolver = context.getContentResolver();
- if (attachment.mUiDestination == UIProvider.AttachmentDestination.CACHE) {
+ // As we changed the save attachment process to use the cached content first,
+ // if the cached do not exist, we will try to download it. Then under this case
+ // we need save the content to cache and external both.
+ if (attachment.mUiDestination == UIProvider.AttachmentDestination.CACHE
+ || !Utility.attachmentExists(context, attachment)) {
Uri attUri = getAttachmentUri(accountId, attachmentId);
size = copyFile(in, resolver.openOutputStream(attUri));
contentUri = attUri.toString();
- } else if (Utility.isExternalStorageMounted()) {
+
+ // Update the attachment
+ cv.put(AttachmentColumns.SIZE, size);
+ cv.put(AttachmentColumns.CONTENT_URI, contentUri);
+ cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED);
+ context.getContentResolver().update(uri, cv, null, null);
+ } else {
+ // Do not use the input stream, close it.
+ in.close();
+ }
+
+ // If the destination is external, try to save the content to external.
+ if (attachment.mUiDestination == UIProvider.AttachmentDestination.EXTERNAL) {
+ if (!Utility.isExternalStorageMounted()) {
+ LogUtils.w(Logging.LOG_TAG,
+ "Trying to save an attachment without external storage?");
+ throw new IOException();
+ }
+
if (TextUtils.isEmpty(attachment.mFileName)) {
// TODO: This will prevent a crash but does not surface the underlying problem
// to the user correctly.
@@ -419,7 +441,8 @@
Environment.DIRECTORY_DOWNLOADS);
downloads.mkdirs();
File file = Utility.createUniqueFile(downloads, attachment.mFileName);
- size = copyFile(in, new FileOutputStream(file));
+ Uri attUri = getAttachmentUri(accountId, attachmentId);
+ size = copyFile(resolver.openInputStream(attUri), new FileOutputStream(file));
String absolutePath = file.getAbsolutePath();
// Although the download manager can scan media files, scanning only happens
@@ -440,25 +463,17 @@
false /* do not use media scanner */,
mimeType, absolutePath, size,
true /* show notification */);
- contentUri = dm.getUriForDownloadedFile(id).toString();
+ LogUtils.d(Logging.LOG_TAG, "Save the att to download manager, id = %d", id);
} catch (final IllegalArgumentException e) {
LogUtils.d(LogUtils.TAG, e, "IAE from DownloadManager while saving attachment");
throw new IOException(e);
}
- } else {
- LogUtils.w(Logging.LOG_TAG,
- "Trying to save an attachment without external storage?");
- throw new IOException();
}
-
- // Update the attachment
- cv.put(AttachmentColumns.SIZE, size);
- cv.put(AttachmentColumns.CONTENT_URI, contentUri);
- cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED);
} catch (IOException e) {
// Handle failures here...
+ cv.clear();
cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.FAILED);
+ context.getContentResolver().update(uri, cv, null, null);
}
- context.getContentResolver().update(uri, cv, null, null);
}
}
diff --git a/emailcommon/src/com/android/emailcommon/utility/Utility.java b/emailcommon/src/com/android/emailcommon/utility/Utility.java
old mode 100644
new mode 100755
index 55ac448..1e38542
--- a/emailcommon/src/com/android/emailcommon/utility/Utility.java
+++ b/emailcommon/src/com/android/emailcommon/utility/Utility.java
@@ -44,6 +44,7 @@
import com.google.common.annotations.VisibleForTesting;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -62,6 +63,8 @@
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.regex.Pattern;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
public class Utility {
public static final Charset UTF_8 = Charset.forName("UTF-8");
@@ -73,6 +76,8 @@
private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE =
Pattern.compile("GMT([-+]\\d{4})$");
+ // the temp encode for compress and decompress
+ private static final String TEMP_ENCODE = "ISO-8859-1";
private static Handler sMainThreadHandler;
/**
@@ -788,4 +793,44 @@
? new StrictMode.VmPolicy.Builder().detectAll().build()
: StrictMode.VmPolicy.LAX);
}
+
+ public static String compress(String str) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ GZIPOutputStream gzip = new GZIPOutputStream(out);
+ gzip.write(str.getBytes());
+ gzip.close();
+ return out.toString(TEMP_ENCODE);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return str;
+ }
+
+ public static String uncompress(String str) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(str
+ .getBytes(TEMP_ENCODE));
+ GZIPInputStream gunzip = new GZIPInputStream(in);
+ byte[] buffer = new byte[256];
+ int n;
+ while ((n = gunzip.read(buffer)) >= 0) {
+ out.write(buffer, 0, n);
+ }
+ if (gunzip != null) {
+ gunzip.close();
+ }
+ return out.toString();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return str;
+ }
}
diff --git a/provider_src/com/android/email/AttachmentInfo.java b/provider_src/com/android/email/AttachmentInfo.java
index 13ff068..a4d28fb 100644
--- a/provider_src/com/android/email/AttachmentInfo.java
+++ b/provider_src/com/android/email/AttachmentInfo.java
@@ -132,13 +132,7 @@
// Check for unacceptable attachments by filename extension
String extension = AttachmentUtilities.getFilenameExtension(mName);
- if (!TextUtils.isEmpty(extension) &&
- Utility.arrayContains(AttachmentUtilities.UNACCEPTABLE_ATTACHMENT_EXTENSIONS,
- extension)) {
- canView = false;
- canSave = false;
- denyFlags |= DENY_MALWARE;
- }
+
// Check for policy restrictions on download
if ((flags & Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD) != 0) {
@@ -147,21 +141,8 @@
denyFlags |= DENY_POLICY;
}
- // Check for installable attachments by filename extension
- extension = AttachmentUtilities.getFilenameExtension(mName);
- if (!TextUtils.isEmpty(extension) &&
- Utility.arrayContains(AttachmentUtilities.INSTALLABLE_ATTACHMENT_EXTENSIONS,
- extension)) {
- boolean sideloadEnabled;
- sideloadEnabled = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.INSTALL_NON_MARKET_APPS, 0 /* sideload disabled */) == 1;
- canSave &= sideloadEnabled;
- canView = canSave;
- canInstall = canSave;
- if (!sideloadEnabled) {
- denyFlags |= DENY_NOSIDELOAD;
- }
- }
+
+
// Check for file size exceeded
// The size limit is overridden when on a wifi connection - any size is OK
@@ -178,11 +159,7 @@
Intent intent = getAttachmentIntent(context, 0);
PackageManager pm = context.getPackageManager();
List<ResolveInfo> activityList = pm.queryIntentActivities(intent, 0 /*no account*/);
- if (activityList.isEmpty()) {
- canView = false;
- canSave = false;
- denyFlags |= DENY_NOINTENT;
- }
+
mAllowView = canView;
mAllowSave = canSave;
@@ -221,7 +198,7 @@
* @return whether the attachment is eligible for download
*/
public boolean isEligibleForDownload() {
- return mAllowView || mAllowSave;
+ return mAllowView || mAllowSave || mAllowInstall;
}
@Override
diff --git a/provider_src/com/android/email/LegacyConversions.java b/provider_src/com/android/email/LegacyConversions.java
index 3de9b68..7b2f15b 100644
--- a/provider_src/com/android/email/LegacyConversions.java
+++ b/provider_src/com/android/email/LegacyConversions.java
@@ -310,7 +310,10 @@
localMessage.mAttachments = new ArrayList<Attachment>();
}
localMessage.mAttachments.add(localAttachment);
- localMessage.mFlagAttachment = true;
+ if (TextUtils.isEmpty(localAttachment.mContentId)) {
+ // This isn't the viewable part, set the local message has attachment.
+ localMessage.mFlagAttachment = true;
+ }
}
/**
diff --git a/provider_src/com/android/email/activity/setup/AccountSettingsUtils.java b/provider_src/com/android/email/activity/setup/AccountSettingsUtils.java
index dbbd51e..452c5cc 100644
--- a/provider_src/com/android/email/activity/setup/AccountSettingsUtils.java
+++ b/provider_src/com/android/email/activity/setup/AccountSettingsUtils.java
@@ -111,6 +111,8 @@
cv.put(AccountColumns.FLAGS, account.mFlags);
cv.put(AccountColumns.SYNC_LOOKBACK, account.mSyncLookback);
cv.put(AccountColumns.SECURITY_SYNC_KEY, account.mSecuritySyncKey);
+ cv.put(AccountColumns.SET_SYNC_SIZE_ENABLED, account.mSetSyncSizeEnabled);
+ cv.put(AccountColumns.SYNC_SIZE, account.mSyncSize);
return cv;
}
diff --git a/provider_src/com/android/email/mail/store/ImapFolder.java b/provider_src/com/android/email/mail/store/ImapFolder.java
index 3a90811..28b3fb5 100644
--- a/provider_src/com/android/email/mail/store/ImapFolder.java
+++ b/provider_src/com/android/email/mail/store/ImapFolder.java
@@ -46,6 +46,7 @@
import com.android.emailcommon.mail.Part;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.service.SearchParams;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.utility.CountingOutputStream;
import com.android.emailcommon.utility.EOLConvertingOutputStream;
import com.android.emailcommon.utility.Utility;
@@ -638,6 +639,9 @@
* BODY_SANE - UID FETCH (BODY.PEEK[]<0.N>) where N = max bytes returned
* BODY - UID FETCH (BODY.PEEK[])
* Part - UID FETCH (BODY.PEEK[ID]) where ID = mime part ID
+ * Part_SANE - UID FETCH (BODY.PEEK[ID]<0.N>) where ID = mime part ID
+ * and N = max bytes returned
+ * - this is add for sync size.
*/
final LinkedHashSet<String> fetchFields = new LinkedHashSet<String>();
@@ -670,8 +674,12 @@
// TODO Why can a single part have more than one Id? And why should we only fetch
// the first id if there are more than one?
if (partIds != null) {
- fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_BARE
- + "[" + partIds[0] + "]");
+ String fetchFieldCommand = ImapConstants.FETCH_FIELD_BODY_PEEK_BARE
+ + "[" + partIds[0] + "]";
+ if (fp.getAllowSyncSize() != SyncSize.SYNC_SIZE_ENTIRE_MAIL) {
+ fetchFieldCommand = fetchFieldCommand + "<0." + fp.getAllowSyncSize() + ">";
+ }
+ fetchFields.add(fetchFieldCommand);
}
}
@@ -858,6 +866,7 @@
* This is a multipart/*
*/
MimeMultipart mp = new MimeMultipart();
+ int textplainIndex = -1;
for (int i = 0, count = bs.size(); i < count; i++) {
ImapElement e = bs.getElementOrNone(i);
if (e.isList()) {
@@ -872,6 +881,16 @@
} else {
parseBodyStructure(bs.getListOrEmpty(i), bp, id + "." + (i + 1));
}
+ /**
+ * If the MimeMultipart has the TEXT/HTML content and TEXT/PLAIN content,
+ * we could only download the TEXT/HTML content to save data traffic.
+ */
+ if (bp.getMimeType().equals("text/plain")) {
+ textplainIndex = i;
+ } else if (textplainIndex != -1 && bp.getMimeType().equals("text/html")) {
+ mp.removeBodyPart(textplainIndex);
+ }
+
mp.addBodyPart(bp);
} else {
@@ -896,6 +915,7 @@
body description
body encoding
body size
+ body line
*/
final ImapString type = bs.getStringOrEmpty(0);
diff --git a/provider_src/com/android/email/mail/store/ImapStore.java b/provider_src/com/android/email/mail/store/ImapStore.java
index 5fc83e0..9de9bde 100644
--- a/provider_src/com/android/email/mail/store/ImapStore.java
+++ b/provider_src/com/android/email/mail/store/ImapStore.java
@@ -458,10 +458,11 @@
// In order to properly map INBOX -> Inbox, handle it as a special case.
final Mailbox inbox =
Mailbox.restoreMailboxOfType(mContext, mAccount.mId, Mailbox.TYPE_INBOX);
- final ImapFolder newFolder = addMailbox(
- mContext, mAccount.mId, inbox.mServerId, '\0', true /*selectable*/, inbox);
- mailboxes.put(ImapConstants.INBOX, newFolder);
-
+ if (inbox != null) {
+ final ImapFolder newFolder = addMailbox(
+ mContext, mAccount.mId, inbox.mServerId, '\0', true /*selectable*/, inbox);
+ mailboxes.put(ImapConstants.INBOX, newFolder);
+ }
createHierarchy(mailboxes);
saveMailboxList(mContext, mailboxes);
return mailboxes.values().toArray(new Folder[mailboxes.size()]);
diff --git a/provider_src/com/android/email/provider/AccountReconciler.java b/provider_src/com/android/email/provider/AccountReconciler.java
index 8031f17..2761372 100644
--- a/provider_src/com/android/email/provider/AccountReconciler.java
+++ b/provider_src/com/android/email/provider/AccountReconciler.java
@@ -260,11 +260,11 @@
final String protocol = EmailServiceUtils.getProtocolFromAccountType(
context, accountType);
final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol);
- if (info == null || !info.syncCalendar) {
+ if (info != null && !info.syncCalendar) {
ContentResolver.setIsSyncable(accountManagerAccount,
CalendarContract.AUTHORITY, 0);
}
- if (info == null || !info.syncContacts) {
+ if (info != null && !info.syncContacts) {
ContentResolver.setIsSyncable(accountManagerAccount,
ContactsContract.AUTHORITY, 0);
}
diff --git a/provider_src/com/android/email/provider/DBHelper.java b/provider_src/com/android/email/provider/DBHelper.java
index dbeca63..3305353 100644
--- a/provider_src/com/android/email/provider/DBHelper.java
+++ b/provider_src/com/android/email/provider/DBHelper.java
@@ -57,6 +57,7 @@
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.provider.QuickResponse;
import com.android.emailcommon.service.LegacyPolicySet;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.service.SyncWindow;
import com.android.mail.providers.UIProvider;
import com.android.mail.utils.LogUtils;
@@ -184,7 +185,8 @@
// Version 126: Decode address lists for To, From, Cc, Bcc and Reply-To columns in Message.
// Version 127: Force mFlags to contain the correct flags for EAS accounts given a protocol
// version above 12.0
- public static final int DATABASE_VERSION = 127;
+ // Version 128: Add setSyncSizeEnabled and syncSize columns for Account table.
+ public static final int DATABASE_VERSION = 128;
// Any changes to the database format *must* include update-in-place code.
// Original version: 2
@@ -516,7 +518,9 @@
+ AccountColumns.SIGNATURE + " text, "
+ AccountColumns.POLICY_KEY + " integer, "
+ AccountColumns.MAX_ATTACHMENT_SIZE + " integer, "
- + AccountColumns.PING_DURATION + " integer"
+ + AccountColumns.PING_DURATION + " integer, "
+ + AccountColumns.SET_SYNC_SIZE_ENABLED + " integer, "
+ + AccountColumns.SYNC_SIZE + " integer"
+ ");";
db.execSQL("create table " + Account.TABLE_NAME + s);
// Deleting an account deletes associated Mailboxes and HostAuth's
@@ -1469,6 +1473,20 @@
if (oldVersion <= 126) {
upgradeFromVersion126ToVersion127(mContext, db);
}
+
+ if (oldVersion <= 127) {
+ try {
+ db.execSQL("alter table " + Account.TABLE_NAME
+ + " add column " + AccountColumns.SET_SYNC_SIZE_ENABLED + " integer"
+ + " default " + SyncSize.ENABLED_DEFAULT_VALUE + ";");
+ db.execSQL("alter table " + Account.TABLE_NAME
+ + " add column " + AccountColumns.SYNC_SIZE + " integer"
+ + " default " + SyncSize.SYNC_SIZE_DEFAULT_VALUE + ";");
+ } catch (SQLException e) {
+ // Shouldn't be needed unless we're debugging and interrupt the process
+ LogUtils.w(TAG, "Exception upgrading EmailProvider.db from 127 to 128", e);
+ }
+ }
}
@Override
diff --git a/provider_src/com/android/email/provider/EmailProvider.java b/provider_src/com/android/email/provider/EmailProvider.java
index 4bd9d4d..98cab48 100644
--- a/provider_src/com/android/email/provider/EmailProvider.java
+++ b/provider_src/com/android/email/provider/EmailProvider.java
@@ -18,6 +18,7 @@
import android.accounts.AccountManager;
import android.appwidget.AppWidgetManager;
+import android.content.AsyncQueryHandler;
import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -276,7 +277,9 @@
private static final int UI_PURGE_FOLDER = UI_BASE + 20;
private static final int UI_INBOX = UI_BASE + 21;
private static final int UI_ACCTSETTINGS = UI_BASE + 22;
+ private static final int UI_MESSAGE_LOAD_MORE = UI_BASE + 23;
+ private static final int UI_LOCAL_SEARCH = UI_BASE + 24;
private static final int BODY_BASE = 0xA000;
private static final int BODY = BODY_BASE;
private static final int BODY_ID = BODY_BASE + 1;
@@ -1233,6 +1236,11 @@
sURIMatcher.addURI(EmailContent.AUTHORITY, "pickSentFolder/#",
ACCOUNT_PICK_SENT_FOLDER);
sURIMatcher.addURI(EmailContent.AUTHORITY, "uipurgefolder/#", UI_PURGE_FOLDER);
+ sURIMatcher.addURI(EmailContent.AUTHORITY, "uimessageloadmore/#",
+ UI_MESSAGE_LOAD_MORE);
+
+ sURIMatcher.addURI(EmailContent.AUTHORITY, "uilocalsearch/#",
+ UI_LOCAL_SEARCH);
}
}
@@ -1311,6 +1319,11 @@
case UI_SEARCH:
c = uiSearch(uri, projection);
return c;
+
+ case UI_LOCAL_SEARCH:
+ c = uiLocalSearch(uri, projection);
+ return c;
+
case UI_ACCTS:
final String suppressParam =
uri.getQueryParameter(EmailContent.SUPPRESS_COMBINED_ACCOUNT_PARAM);
@@ -1353,6 +1366,9 @@
case UI_FOLDER_REFRESH:
c = uiFolderRefresh(getMailbox(uri), 0);
return c;
+ case UI_MESSAGE_LOAD_MORE:
+ c = uiMessageLoadMore(getMessageFromLastSegment(uri));
+ return c;
case MAILBOX_NOTIFICATION:
c = notificationQuery(uri);
return c;
@@ -2084,6 +2100,7 @@
selectionArgs);
if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) {
handleMessageUpdateNotifications(uri, id, values);
+ notifyVirtualMailBoxWidget(values,uri);
} else if (match == ATTACHMENT_ID) {
long attId = Integer.parseInt(id);
if (values.containsKey(AttachmentColumns.FLAGS)) {
@@ -2331,7 +2348,8 @@
private static void writeBodyFiles(final Context c, final long messageId,
final ContentValues cv) throws IllegalStateException {
if (cv.containsKey(BodyColumns.HTML_CONTENT)) {
- final String htmlContent = cv.getAsString(BodyColumns.HTML_CONTENT);
+ String htmlContent = cv.getAsString(BodyColumns.HTML_CONTENT);
+ htmlContent = Utility.uncompress(htmlContent);
try {
writeBodyFile(c, messageId, "html", htmlContent);
} catch (final IOException e) {
@@ -2340,7 +2358,8 @@
}
}
if (cv.containsKey(BodyColumns.TEXT_CONTENT)) {
- final String textContent = cv.getAsString(BodyColumns.TEXT_CONTENT);
+ String textContent = cv.getAsString(BodyColumns.TEXT_CONTENT);
+ textContent = Utility.uncompress(textContent);
try {
writeBodyFile(c, messageId, "txt", textContent);
} catch (final IOException e) {
@@ -2753,6 +2772,10 @@
.add(UIProvider.MessageColumns.VIA_DOMAIN, null)
.add(UIProvider.MessageColumns.CLIPPED, "0")
.add(UIProvider.MessageColumns.PERMALINK, null)
+ .add(UIProvider.MessageColumns.MESSAGE_FLAG_LOADED,
+ EmailContent.MessageColumns.FLAG_LOADED)
+ .add(UIProvider.MessageColumns.MESSAGE_LOAD_MORE_URI,
+ uriWithFQId("uimessageloadmore", Message.TABLE_NAME))
.build();
}
return sMessageViewMap;
@@ -2951,6 +2974,7 @@
AttachmentColumns.UI_DOWNLOADED_SIZE)
.add(UIProvider.AttachmentColumns.CONTENT_URI, AttachmentColumns.CONTENT_URI)
.add(UIProvider.AttachmentColumns.FLAGS, AttachmentColumns.FLAGS)
+ .add(UIProvider.AttachmentColumns.CONTENT_ID, AttachmentColumns.CONTENT_ID)
.build();
}
return sAttachmentMap;
@@ -3119,6 +3143,7 @@
uiAtt.size = (int) att.mSize;
uiAtt.uri = uiUri("uiattachment", att.mId);
uiAtt.flags = att.mFlags;
+ uiAtt.partId = att.mContentId;
uiAtts.add(uiAtt);
}
values.put(UIProvider.MessageColumns.ATTACHMENTS, "@?"); // @ for literal
@@ -3142,6 +3167,7 @@
final Uri attachmentListUri = uiUri("uiattachments", messageId).buildUpon()
.appendQueryParameter("MessageLoaded",
msg.mFlagLoaded == Message.FLAG_LOADED_COMPLETE ? "true" : "false")
+ .appendQueryParameter(AttachmentColumns.CONTENT_ID, "null")
.build();
values.put(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, attachmentListUri.toString());
}
@@ -3170,7 +3196,8 @@
* @param unseenOnly <code>true</code> to only return unseen messages
* @return the SQLite query to be executed on the EmailProvider database
*/
- private static String genQueryMailboxMessages(String[] uiProjection, final boolean unseenOnly) {
+ private static String genQueryMailboxMessages(String[] uiProjection, final boolean unseenOnly,
+ String selection) {
StringBuilder sb = genSelect(getMessageListMap(), uiProjection);
appendConversationInfoColumns(sb);
sb.append(" FROM " + Message.TABLE_NAME + " WHERE " +
@@ -3180,6 +3207,10 @@
sb.append("AND ").append(MessageColumns.FLAG_SEEN).append(" = 0 ");
sb.append("AND ").append(MessageColumns.FLAG_READ).append(" = 0 ");
}
+
+ if (!TextUtils.isEmpty(selection)) {
+ sb.append("AND ").append(selection);
+ }
sb.append("ORDER BY " + MessageColumns.TIMESTAMP + " DESC ");
sb.append("LIMIT " + UIProvider.CONVERSATION_PROJECTION_QUERY_CURSOR_WINDOW_LIMIT);
return sb.toString();
@@ -3193,8 +3224,8 @@
* @param unseenOnly <code>true</code> to only return unseen messages
* @return the SQLite query to be executed on the EmailProvider database
*/
- private static Cursor getVirtualMailboxMessagesCursor(SQLiteDatabase db, String[] uiProjection,
- long mailboxId, final boolean unseenOnly) {
+ private Cursor getVirtualMailboxMessagesCursor(SQLiteDatabase db, String[] uiProjection,
+ long mailboxId, final boolean unseenOnly, String selection) {
ContentValues values = new ContentValues();
values.put(UIProvider.ConversationColumns.COLOR, CONVERSATION_COLOR);
final int virtualMailboxId = getVirtualMailboxType(mailboxId);
@@ -3223,7 +3254,8 @@
"=" + Mailbox.TYPE_INBOX + ")");
break;
case Mailbox.TYPE_STARRED:
- sb.append(MessageColumns.FLAG_FAVORITE + "=1");
+ sb.append(MessageColumns.FLAG_FAVORITE + "=1 AND "+MessageColumns.MAILBOX_KEY
+ +"<>5");
break;
case Mailbox.TYPE_UNREAD:
sb.append(MessageColumns.FLAG_READ + "=0 AND " + MessageColumns.MAILBOX_KEY +
@@ -3233,7 +3265,14 @@
default:
throw new IllegalArgumentException("No virtual mailbox for: " + mailboxId);
}
+
+ if (!TextUtils.isEmpty(selection)) {
+ sb.append(" AND ").append(selection);
+ }
+
sb.append(" ORDER BY " + MessageColumns.TIMESTAMP + " DESC");
+
+
return db.rawQuery(sb.toString(), selectionArgs);
}
@@ -3485,7 +3524,8 @@
// If the configuration states that feedback is supported, add that capability
final Resources res = context.getResources();
- if (res.getBoolean(R.bool.feedback_supported)) {
+ Uri feedbackUri = Utils.getValidUri(res.getString(R.string.email_feedback_uri));
+ if (res.getBoolean(R.bool.feedback_supported) && !Uri.EMPTY.equals(feedbackUri)) {
capabilities |= AccountCapabilities.SEND_FEEDBACK;
}
@@ -3922,7 +3962,8 @@
whereArgs = new String[] { Long.toString(accountId) };
}
final int starredCount = EmailContent.count(getContext(), Message.CONTENT_URI,
- accountKeyClause + MessageColumns.FLAG_FAVORITE + "=1", whereArgs);
+ accountKeyClause + MessageColumns.FLAG_FAVORITE + "=1 AND "
+ + MessageColumns.MAILBOX_KEY + "<>5", whereArgs);
values[i] = starredCount;
}
} else if (column.equals(UIProvider.FolderColumns.ICON_RES_ID)) {
@@ -4018,7 +4059,7 @@
* @return the SQLite query to be executed on the EmailProvider database
*/
private static String genQueryAttachments(String[] uiProjection,
- List<String> contentTypeQueryParameters) {
+ List<String> contentTypeQueryParameters, List<String> contentIdQueryParameters) {
// MAKE SURE THESE VALUES STAY IN SYNC WITH GEN QUERY ATTACHMENT
ContentValues values = new ContentValues(1);
values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1);
@@ -4050,6 +4091,27 @@
}
sb.append(")");
}
+
+ // Filter for in-line attachments.
+ // The filter works by adding IS operators for each content id you wish to request.
+ if (contentIdQueryParameters != null && !contentIdQueryParameters.isEmpty()) {
+ final int size = contentIdQueryParameters.size();
+ sb.append("AND (");
+ for (int i = 0; i < size; i++) {
+ final String contentId = contentIdQueryParameters.get(i);
+ sb.append(AttachmentColumns.CONTENT_ID + " IS ");
+ if (contentId.toLowerCase().equals("null")) {
+ sb.append("NULL");
+ } else {
+ sb.append("'" + contentId + "'");
+ }
+ if (i != size - 1) {
+ sb.append(" OR ");
+ }
+ }
+ sb.append(")");
+ }
+
return sb.toString();
}
@@ -4680,10 +4742,13 @@
return new MatrixCursor(uiProjection);
}
if (isVirtualMailbox(mailboxId)) {
- c = getVirtualMailboxMessagesCursor(db, uiProjection, mailboxId, unseenOnly);
+ c = getVirtualMailboxMessagesCursor(db, uiProjection, mailboxId, unseenOnly,
+ null);
} else {
c = db.rawQuery(
- genQueryMailboxMessages(uiProjection, unseenOnly), new String[] {id});
+ genQueryMailboxMessages(uiProjection, unseenOnly, null), new String[] {
+ id
+ });
}
notifyUri = UIPROVIDER_CONVERSATION_NOTIFIER.buildUpon().appendPath(id).build();
c = new EmailConversationCursor(context, c, folder, mailboxId);
@@ -4707,8 +4772,11 @@
case UI_ATTACHMENTS:
final List<String> contentTypeQueryParameters =
uri.getQueryParameters(PhotoContract.ContentTypeParameters.CONTENT_TYPE);
- c = db.rawQuery(genQueryAttachments(uiProjection, contentTypeQueryParameters),
- new String[] {id});
+ final List<String> contentIdQueryParameters =
+ uri.getQueryParameters(AttachmentColumns.CONTENT_ID);
+ String sqlAttachments = genQueryAttachments(uiProjection,
+ contentTypeQueryParameters, contentIdQueryParameters);
+ c = db.rawQuery(sqlAttachments, new String[] {id});
c = new AttachmentsCursor(context, c);
notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build();
break;
@@ -5469,7 +5537,7 @@
if (msg == null) return 0;
Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey);
if (mailbox == null) return 0;
- if (mailbox.mType == Mailbox.TYPE_TRASH || mailbox.mType == Mailbox.TYPE_DRAFTS) {
+ if (mailbox.mType == Mailbox.TYPE_TRASH) {
// We actually delete these, including attachments
AttachmentUtilities.deleteAllAttachmentFiles(context, msg.mAccountKey, msg.mId);
final int r = context.getContentResolver().delete(
@@ -5535,6 +5603,49 @@
return deletedCount;
}
+ private Cursor uiMessageLoadMore(final Message msg) {
+ if (msg == null) return null;
+
+ // Start the fetch process running in the background
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(Void... params) {
+ LogUtils.d(TAG, "Run load more task. account: " + msg.mAccountKey);
+
+ // Delete the dummy attachment from the database.
+ deleteDummyAttachment(msg.mId);
+ // As the delete action will not notify the UI change.
+ // We will notify it with the message id.
+ notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, msg.mId);
+
+ // Update the message loaded status as partial before load entire content.
+ Utilities.updateMessageLoadStatus(getContext(), msg.mId,
+ EmailContent.Message.FLAG_LOADED_PARTIAL_FETCHING);
+
+ final EmailServiceProxy service =
+ EmailServiceUtils.getServiceForAccount(getContext(), msg.mAccountKey);
+ if (service != null) {
+ try {
+ service.loadMore(msg.mId);
+ } catch (RemoteException e) {
+ LogUtils.e("loadMore", "RemoteException", e);
+ }
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+
+ return null;
+ }
+
+ private int deleteDummyAttachment(long messageId) {
+ StringBuilder selection = new StringBuilder()
+ .append(AttachmentColumns.MESSAGE_KEY + "=" + messageId)
+ .append(" AND ")
+ .append(AttachmentColumns.FLAGS + "&" + Attachment.FLAG_DUMMY_ATTACHMENT + "!=0");
+ return delete(Attachment.CONTENT_URI, selection.toString(), null);
+ }
+
public static final String PICKER_UI_ACCOUNT = "picker_ui_account";
public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type";
// Currently unused
@@ -6006,6 +6117,59 @@
searchMailbox.mId), projection, false);
}
+
+ private Cursor uiLocalSearch(Uri uri, String[] uiProjection) {
+ Context context = getContext();
+ SQLiteDatabase db = getDatabase(context);
+
+ Cursor c = null;
+ Uri notifyUri = null;
+ String id = uri.getPathSegments().get(1);
+
+ final String seenParam = uri.getQueryParameter(UIProvider.SEEN_QUERY_PARAMETER);
+ final boolean unseenOnly =
+ seenParam != null && Boolean.FALSE.toString().equals(seenParam);
+
+ final String queryFilter = uri.getQueryParameter(SearchParams.BUNDLE_QUERY_FILTER);
+ final String queryFactor = uri.getQueryParameter(SearchParams.BUNDLE_QUERY_FACTOR);
+
+ if (TextUtils.isEmpty(queryFilter) || TextUtils.isEmpty(queryFactor)) {
+
+ return new MatrixCursor(uiProjection);
+ }
+
+ long mailboxId = Long.parseLong(id);
+ final Folder folder = getFolder(context, mailboxId);
+ if (folder == null) {
+
+ return new MatrixCursor(uiProjection);
+ }
+
+ String selection = Message.buildLocalSearchSelection(context, mailboxId, queryFilter,
+ queryFactor);
+
+ if (null == selection) {
+ return new MatrixCursor(uiProjection);
+ }
+
+ if (isVirtualMailbox(mailboxId)) {
+ c = getVirtualMailboxMessagesCursor(db, uiProjection, mailboxId,
+ unseenOnly, selection);
+ } else {
+ c = db.rawQuery(
+ genQueryMailboxMessages(uiProjection, unseenOnly, selection),
+ new String[] {
+ id
+ });
+ }
+ c = new EmailConversationCursor(context, c, folder, mailboxId);
+
+ if (notifyUri != null) {
+ c.setNotificationUri(context.getContentResolver(), notifyUri);
+ }
+ return c;
+ }
+
private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?";
/**
@@ -6185,11 +6349,37 @@
// If our mailbox needs to be notified, do so...
if (mWidgetNotifyMailboxes.contains(mailboxId)) {
- Intent intent = new Intent(Utils.ACTION_NOTIFY_DATASET_CHANGED);
- intent.putExtra(Utils.EXTRA_FOLDER_URI, uiUri("uifolder", mailboxId));
- intent.setType(EMAIL_APP_MIME_TYPE);
- context.sendBroadcast(intent);
- }
+ Intent intent = new Intent();
+ if (isVirtualMailbox(mailboxId)) {
+ intent.setAction(Utils.ACTION_WIDGET_FOLDER_UPDATE);
+ Bundle extras = new Bundle();
+ extras.putParcelable(Utils.EXTRA_FOLDER_URI, uiUri("uifolder", mailboxId));
+ extras.putParcelable(Utils.EXTRA_CONVERSATIONLIST_URI, uiUri("uimessages", mailboxId));
+ intent.putExtras(extras);
+ context.sendBroadcast(intent);
+ } else {
+ intent.setAction(Utils.ACTION_NOTIFY_DATASET_CHANGED);
+ intent.putExtra(Utils.EXTRA_FOLDER_URI, uiUri("uifolder", mailboxId));
+ intent.setType(EMAIL_APP_MIME_TYPE);
+ context.sendBroadcast(intent);
+ }
+ }
+ }
+
+ private void notifyVirtualMailBoxWidget(ContentValues values, Uri uri) {
+ if (values.containsKey(MessageColumns.FLAG_FAVORITE)
+ || values.containsKey(MessageColumns.FLAG_READ)) {
+ Message msg = Message.restoreMessageWithId(getContext(),
+ Long.parseLong(uri.getLastPathSegment()));
+ if (msg == null) {
+ return;
+ }
+ if (values.containsKey(MessageColumns.FLAG_FAVORITE)) {
+ notifyWidgets(getVirtualMailboxId(msg.mAccountKey, Mailbox.TYPE_STARRED));
+ } else if (values.containsKey(MessageColumns.FLAG_READ)) {
+ notifyWidgets(getVirtualMailboxId(msg.mAccountKey, Mailbox.TYPE_UNREAD));
+ }
+ }
}
@Override
diff --git a/provider_src/com/android/email/provider/Utilities.java b/provider_src/com/android/email/provider/Utilities.java
index c3b7ec9..3846dac 100644
--- a/provider_src/com/android/email/provider/Utilities.java
+++ b/provider_src/com/android/email/provider/Utilities.java
@@ -45,6 +45,19 @@
public class Utilities {
/**
+ * Update the local message's load status.
+ *
+ * @param messageId the local message's id
+ * @param loadStatus the new load status
+ */
+ public static void updateMessageLoadStatus(Context context, long messageId, int loadStatus) {
+ ContentValues cv = new ContentValues();
+ cv.put(EmailContent.MessageColumns.FLAG_LOADED, loadStatus);
+ Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, messageId);
+ context.getContentResolver().update(uri, cv, null, null);
+ }
+
+ /**
* Copy one downloaded message (which may have partially-loaded sections)
* into a newly created EmailProvider Message, given the account and mailbox
*
@@ -138,7 +151,11 @@
// TODO(pwestbro): What should happen with unknown status?
LegacyConversions.updateAttachments(context, localMessage, attachments);
LegacyConversions.updateInlineAttachments(context, localMessage, viewables);
- } else {
+ }
+
+ // if the message didn't loaded complete, add a dummy attachment.
+ if (loadStatus == EmailContent.Message.FLAG_LOADED_PARTIAL
+ || loadStatus == EmailContent.Message.FLAG_LOADED_PARTIAL_COMPLETE) {
EmailContent.Attachment att = new EmailContent.Attachment();
// Since we haven't actually loaded the attachment, we're just putting
// a dummy placeholder here. When the user taps on it, we'll load the attachment
@@ -163,7 +180,7 @@
att.mAccountKey = localMessage.mAccountKey;
att.mFlags = Attachment.FLAG_DUMMY_ATTACHMENT;
att.save(context);
- localMessage.mFlagAttachment = true;
+ // localMessage.mFlagAttachment = true;
}
// One last update of message with two updated flags
diff --git a/provider_src/com/android/email/service/AccountService.java b/provider_src/com/android/email/service/AccountService.java
index c8d94a1..4c3574c 100644
--- a/provider_src/com/android/email/service/AccountService.java
+++ b/provider_src/com/android/email/service/AccountService.java
@@ -60,8 +60,9 @@
public void run() {
// Make sure remote services are running (re: lifecycle)
EmailServiceUtils.startRemoteServices(mContext);
- // Send current logging flags
- DebugUtils.updateLoggingFlags(mContext);
+ // Send current logging flags, need disable it first
+ //it may cause ServiceConnection leak when bindService
+ // DebugUtils.updateLoggingFlags(mContext);
}});
return Device.getDeviceId(mContext);
} catch (IOException e) {
diff --git a/provider_src/com/android/email/service/BluetoothEmailBroadcastReceiver.java b/provider_src/com/android/email/service/BluetoothEmailBroadcastReceiver.java
new file mode 100644
index 0000000..ae2408a
--- /dev/null
+++ b/provider_src/com/android/email/service/BluetoothEmailBroadcastReceiver.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import com.android.email.Preferences;
+import com.android.email.R;
+import com.android.email.SecurityPolicy;
+import com.android.email.provider.AccountReconciler;
+import com.android.email.provider.EmailProvider;
+import com.android.emailcommon.Logging;
+import com.android.emailcommon.VendorPolicyLoader;
+import com.android.emailcommon.provider.Account;
+import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.EmailContent.AccountColumns;
+import com.android.emailcommon.provider.HostAuth;
+import com.android.emailcommon.provider.Mailbox;
+import com.android.mail.utils.LogUtils;
+import android.util.Log;
+
+
+/**
+ * The broadcast receiver. The actual job is done in EmailBroadcastProcessor on a worker thread.
+ * Extend EmailBroadcastReceiver to handle Bluetooth MAP relevant intents.
+ */
+public class BluetoothEmailBroadcastReceiver extends EmailBroadcastReceiver {
+
+ private static final String TAG = "BluetoothEmailBroadcastReceiver";
+ private static final String ACTION_CHECK_MAIL =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_WAKEUP";
+ private static final String EXTRA_ACCOUNT = "org.codeaurora.email.intent.extra.ACCOUNT";
+ private static final String ACTION_DELETE_MESSAGE =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_DELETE_MESSAGE";
+ private static final String ACTION_MOVE_MESSAGE =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_MOVE_MESSAGE";
+ private static final String ACTION_MESSAGE_READ =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_MESSAGE_READ";
+ private static final String ACTION_SEND_PENDING_MAIL =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_SEND_PENDING";
+ private static final String EXTRA_MESSAGE_ID = "org.codeaurora.email.intent.extra.MESSAGE_ID";
+ private static final String EXTRA_MESSAGE_INFO =
+ "org.codeaurora.email.intent.extra.MESSAGE_INFO";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG,"Received " + action);
+ if (ACTION_CHECK_MAIL.equals(action)) {
+ Intent i;
+ final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1);
+ Log.d(TAG, "accountId is " + accountId);
+ final long inboxId = Mailbox.findMailboxOfType(context, accountId,
+ Mailbox.TYPE_INBOX);
+ Log.d(TAG, "inboxId is " + inboxId);
+ Mailbox mailbox = Mailbox.restoreMailboxWithId(context, inboxId);
+ if (mailbox == null) {
+ return;
+ }
+ Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey);
+ String protocol = account.getProtocol(context);
+ Log.d(TAG, "protocol is " + protocol);
+ String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
+ if (protocol.equals(legacyImapProtocol)) {
+ i = new Intent(context, BluetoothImapService.class);
+ } else {
+ i = new Intent(context, BluetoothPop3Service.class);
+ }
+ i.setAction(intent.getAction());
+ i.putExtra(EXTRA_ACCOUNT,
+ intent.getLongExtra(EXTRA_ACCOUNT, -1));
+ context.startService(i);
+ } else if (ACTION_DELETE_MESSAGE.equals(action)) {
+ Intent i;
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ Log.d(TAG, "messageId is " + messageId);
+ Account account = Account.getAccountForMessageId(context, messageId);
+ if (account == null ) {
+ return;
+ }
+ String protocol = account.getProtocol(context);
+ Log.d(TAG, "protocol is " + protocol + " ActId: " + account.getId());
+ String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
+ if (protocol.equals(legacyImapProtocol)) {
+ i = new Intent(context, BluetoothImapService.class);
+ i.setAction(intent.getAction());
+ i.putExtra(EXTRA_ACCOUNT,
+ intent.getLongExtra(EXTRA_ACCOUNT, -1));
+ i.putExtra(EXTRA_MESSAGE_ID,
+ intent.getLongExtra(EXTRA_MESSAGE_ID, -1));
+ context.startService(i);
+ } else {
+ Log.i(TAG, "DELETE MESSAGE POP3 NOT Implemented");
+ }
+ } else if (ACTION_MESSAGE_READ.equals(action)) {
+ Intent i;
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ Log.d(TAG, "messageId is " + messageId);
+ Account account = Account.getAccountForMessageId(context, messageId);
+ if (account == null ) {
+ return;
+ }
+ String protocol = account.getProtocol(context);
+ Log.d(TAG, "protocol is " + protocol + " ActId: " + account.getId());
+ String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
+ if (protocol.equals(legacyImapProtocol)) {
+ i = new Intent(context, BluetoothImapService.class);
+ i.setAction(intent.getAction());
+ i.putExtra(EXTRA_ACCOUNT,
+ intent.getLongExtra(EXTRA_ACCOUNT, -1));
+ i.putExtra(EXTRA_MESSAGE_ID,
+ intent.getLongExtra(EXTRA_MESSAGE_ID, -1));
+ i.putExtra(EXTRA_MESSAGE_INFO,
+ intent.getIntExtra(EXTRA_MESSAGE_INFO, 0));
+ context.startService(i);
+ } else {
+ Log.i(TAG, "READ MESSAGE POP3 NOT Implemented");
+ }
+ } else if (ACTION_MOVE_MESSAGE.equals(action)) {
+ Intent i;
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ Log.d(TAG, "messageId is " + messageId);
+ Account account = Account.getAccountForMessageId(context, messageId);
+ if (account == null ) {
+ return;
+ }
+ String protocol = account.getProtocol(context);
+ Log.d(TAG, "protocol is " + protocol + " ActId: " + account.getId());
+ String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
+ if (protocol.equals(legacyImapProtocol)) {
+ i = new Intent(context, BluetoothImapService.class);
+ i.setAction(intent.getAction());
+ i.putExtra(EXTRA_ACCOUNT,
+ intent.getLongExtra(EXTRA_ACCOUNT, -1));
+ i.putExtra(EXTRA_MESSAGE_ID,
+ intent.getLongExtra(EXTRA_MESSAGE_ID, -1));
+ i.putExtra(EXTRA_MESSAGE_INFO,
+ intent.getIntExtra(EXTRA_MESSAGE_INFO, 0));
+ context.startService(i);
+ } else {
+ Log.i(TAG, "READ MESSAGE POP3 NOT Implemented");
+ }
+ } else if (ACTION_SEND_PENDING_MAIL.equals(action)) {
+ Intent i;
+ final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1);
+ Log.d(TAG, "accountId is " + accountId);
+ Account account = Account.restoreAccountWithId(context, accountId);
+ if (account == null ) {
+ return;
+ }
+ String protocol = account.getProtocol(context);
+ Log.d(TAG, "protocol is " + protocol);
+ String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
+ if (protocol.equals(legacyImapProtocol)) {
+ i = new Intent(context, BluetoothImapService.class);
+ i.setAction(intent.getAction());
+ i.putExtra(EXTRA_ACCOUNT,
+ intent.getLongExtra(EXTRA_ACCOUNT, -1));
+ context.startService(i);
+ } else {
+ Log.i(TAG, "SEND MESSAGE POP3 NOT Implemented");
+ }
+ } else {
+ EmailBroadcastProcessorService.processBroadcastIntent(context, intent);
+ }
+ }
+}
diff --git a/provider_src/com/android/email/service/BluetoothImapService.java b/provider_src/com/android/email/service/BluetoothImapService.java
new file mode 100644
index 0000000..bfd49d4
--- /dev/null
+++ b/provider_src/com/android/email/service/BluetoothImapService.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.service;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+
+import com.android.email.DebugUtils;
+import com.android.email.LegacyConversions;
+import com.android.email.NotificationController;
+import com.android.email.NotificationControllerCreatorHolder;
+import com.android.email.R;
+import com.android.email.mail.Store;
+import com.android.email.provider.Utilities;
+import com.android.emailcommon.Logging;
+import com.android.emailcommon.TrafficFlags;
+import com.android.emailcommon.internet.MimeUtility;
+import com.android.emailcommon.mail.AuthenticationFailedException;
+import com.android.emailcommon.mail.FetchProfile;
+import com.android.emailcommon.mail.Flag;
+import com.android.emailcommon.mail.Folder;
+import com.android.emailcommon.mail.Folder.FolderType;
+import com.android.emailcommon.mail.Folder.MessageRetrievalListener;
+import com.android.emailcommon.mail.Folder.MessageUpdateCallbacks;
+import com.android.emailcommon.mail.Folder.OpenMode;
+import com.android.emailcommon.mail.Message;
+import com.android.emailcommon.mail.MessagingException;
+import com.android.emailcommon.mail.Part;
+import com.android.emailcommon.provider.Account;
+import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.EmailContent.MailboxColumns;
+import com.android.emailcommon.provider.EmailContent.MessageColumns;
+import com.android.emailcommon.provider.EmailContent.SyncColumns;
+import com.android.emailcommon.provider.Mailbox;
+import com.android.emailcommon.service.EmailServiceStatus;
+import com.android.emailcommon.service.SearchParams;
+import com.android.emailcommon.service.SyncWindow;
+import com.android.emailcommon.utility.AttachmentUtilities;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.LogUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+public class BluetoothImapService extends ImapService {
+ private static final String TAG = "BluetoothImapService";
+ private static final String ACTION_CHECK_MAIL =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_WAKEUP";
+ private static final String EXTRA_ACCOUNT = "org.codeaurora.email.intent.extra.ACCOUNT";
+ private static final String ACTION_DELETE_MESSAGE =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_DELETE_MESSAGE";
+ private static final String ACTION_MOVE_MESSAGE =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_MOVE_MESSAGE";
+ private static final String ACTION_MESSAGE_READ =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_MESSAGE_READ";
+ private static final String ACTION_SEND_PENDING_MAIL =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_SEND_PENDING";
+ private static final String EXTRA_MESSAGE_ID = "org.codeaurora.email.intent.extra.MESSAGE_ID";
+ private static final String EXTRA_MESSAGE_INFO =
+ "org.codeaurora.email.intent.extra.MESSAGE_INFO";
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ final String action = intent.getAction();
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "Action: ", action);
+ }
+ final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1);
+ Context context = getApplicationContext();
+ if (ACTION_CHECK_MAIL.equals(action)) {
+ final long inboxId = Mailbox.findMailboxOfType(context, accountId,
+ Mailbox.TYPE_INBOX);
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "accountId is " + accountId);
+ LogUtils.d(Logging.LOG_TAG, "inboxId is " + inboxId);
+ }
+ if (accountId <= -1 || inboxId <= -1 ) {
+ return START_NOT_STICKY;
+ }
+ mBinder.init(context);
+ mBinder.requestSync(inboxId,true,0);
+ } else if (ACTION_DELETE_MESSAGE.equals(action)) {
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "action: Delete Message mail");
+ LogUtils.d(Logging.LOG_TAG, "action: delmsg " + messageId);
+ }
+ if (accountId <= -1 || messageId <= -1 ) {
+ return START_NOT_STICKY;
+ }
+ Store remoteStore = null;
+ try {
+ remoteStore = Store.getInstance(Account.getAccountForMessageId(context, messageId),
+ context);
+ mBinder.init(context);
+ mBinder.deleteMessage(messageId);
+ synchronizePendingActions(context,
+ Account.getAccountForMessageId(context, messageId), remoteStore, true);
+ } catch (Exception e) {
+ LogUtils.d(Logging.LOG_TAG, "RemoteException " + e);
+ }
+ } else if (ACTION_MESSAGE_READ.equals(action)) {
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ final int flagRead = intent.getIntExtra(EXTRA_MESSAGE_INFO, 0);
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "action: Message Mark Read or UnRead ");
+ LogUtils.d(Logging.LOG_TAG, "action: delmsg " + messageId);
+ }
+ if (accountId <= -1 || messageId <= -1 ) {
+ return START_NOT_STICKY;
+ }
+ Store remoteStore = null;
+ try {
+ mBinder.init(context);
+ mBinder.setMessageRead(messageId, (flagRead == 1)? true:false);
+ remoteStore = Store.getInstance(Account.getAccountForMessageId(context, messageId),
+ context);
+ synchronizePendingActions(context,
+ Account.getAccountForMessageId(context, messageId), remoteStore, true);
+ } catch (Exception e){
+ LogUtils.d(Logging.LOG_TAG, "RemoteException " + e);
+ }
+ } else if (ACTION_MOVE_MESSAGE.equals(action)) {
+ final long messageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
+ final int mailboxType = intent.getIntExtra(EXTRA_MESSAGE_INFO, Mailbox.TYPE_INBOX);
+ final long mailboxId = Mailbox.findMailboxOfType(context, accountId, mailboxType);
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "action: Move Message mail");
+ LogUtils.d(Logging.LOG_TAG, "action: movemsg " + messageId +
+ "mailbox: " + mailboxType + "accountId: " + accountId + "mailboxId: "
+ + mailboxId);
+ }
+ if (accountId <= -1 || messageId <= -1 || mailboxId <= -1){
+ return START_NOT_STICKY;
+ }
+ Store remoteStore = null;
+ try {
+ mBinder.init(context);
+ mBinder.MoveMessages(messageId, mailboxId);
+ remoteStore = Store.getInstance(Account.getAccountForMessageId(context, messageId),
+ context);
+ synchronizePendingActions(context,
+ Account.getAccountForMessageId(context, messageId),remoteStore, true);
+ } catch (Exception e){
+ LogUtils.d(Logging.LOG_TAG, "RemoteException " + e);
+ }
+ } else if (ACTION_SEND_PENDING_MAIL.equals(action)) {
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "action: Send Pending Mail " + accountId);
+ }
+ if (accountId <= -1 ) {
+ return START_NOT_STICKY;
+ }
+ try {
+ mBinder.init(context);
+ mBinder.sendMail(accountId);
+ } catch (Exception e) {
+ LogUtils.e(Logging.LOG_TAG, "RemoteException " + e);
+ }
+ }
+
+ return Service.START_STICKY;
+ }
+
+ /*
+ Create our EmailService implementation here.
+ */
+ class BluetoothEmailServiceStub extends EmailServiceStub {
+ @Override
+ public void loadMore(long messageId) throws RemoteException {
+ LogUtils.i("ImapService", "Try to load more content for message: " + messageId);
+ }
+ /**
+ * Delete a single message by moving it to the trash, or really delete it if it's already in
+ * trash or a draft message.
+ *
+ * This function has no callback, no result reporting, because the desired outcome
+ * is reflected entirely by changes to one or more cursors.
+ *
+ * @param messageId The id of the message to "delete".
+ */
+ public void deleteMessage(long messageId) {
+
+ final EmailContent.Message message =
+ EmailContent.Message.restoreMessageWithId(mContext, messageId);
+ if (message == null) {
+ if (Logging.LOGD) LogUtils.v(Logging.LOG_TAG, "dletMsg message NULL");
+ return;
+ }
+ // 1. Get the message's account
+ final Account account = Account.restoreAccountWithId(mContext, message.mAccountKey);
+ // 2. Get the message's original mailbox
+ final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
+ if (account == null || mailbox == null) {
+ if (Logging.LOGD) LogUtils.v(Logging.LOG_TAG, "dletMsg account or mailbox NULL");
+ return;
+ }
+ if(Logging.LOGD)
+ LogUtils.d(Logging.LOG_TAG, "AccountKey " + account.mId + "oirigMailbix: "
+ + mailbox.mId);
+ // 3. Confirm that there is a trash mailbox available. If not, create one
+ Mailbox trashFolder = Mailbox.restoreMailboxOfType(mContext, account.mId,
+ Mailbox.TYPE_TRASH);
+ if (trashFolder == null) {
+ if (Logging.LOGD) LogUtils.v(Logging.LOG_TAG, "dletMsg Trash mailbox NULL");
+ } else {
+ LogUtils.d(Logging.LOG_TAG, "TrasMailbix: " + trashFolder.mId);
+ }
+ // 4. Drop non-essential data for the message (e.g. attachment files)
+ AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId,
+ messageId);
+
+ Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI,
+ messageId);
+
+ // 5. Perform "delete" as appropriate
+ if ((mailbox.mId == trashFolder.mId) || (mailbox.mType == Mailbox.TYPE_DRAFTS)) {
+ // 5a. Really delete it
+ mContext.getContentResolver().delete(uri, null, null);
+ } else {
+ // 5b. Move to trash
+ ContentValues cv = new ContentValues();
+ cv.put(EmailContent.MessageColumns.MAILBOX_KEY, trashFolder.mId);
+ mContext.getContentResolver().update(uri, cv, null, null);
+ }
+ }
+
+ /**
+ * Moves messages to a new mailbox.
+ * This function has no callback, no result reporting, because the desired outcome
+ * is reflected entirely by changes to one or more cursors.
+ * Note this method assumes all of the given message and mailbox IDs belong to the same
+ * account.
+ *
+ * @param messageIds IDs of the messages that are to be moved
+ * @param newMailboxId ID of the new mailbox that the messages will be moved to
+ * @return an asynchronous task that executes the move (for testing only)
+ */
+ public void MoveMessages(long messageId, long newMailboxId) {
+ Account account = Account.getAccountForMessageId(mContext, messageId);
+ if (account != null) {
+ if (Logging.LOGD) {
+ LogUtils.d(Logging.LOG_TAG, "moveMessage Acct " + account.mId);
+ LogUtils.d(Logging.LOG_TAG, "moveMessage messageId:" + messageId);
+ }
+ ContentValues cv = new ContentValues();
+ cv.put(EmailContent.MessageColumns.MAILBOX_KEY, newMailboxId);
+ ContentResolver resolver = mContext.getContentResolver();
+ Uri uri = ContentUris.withAppendedId(
+ EmailContent.Message.SYNCED_CONTENT_URI, messageId);
+ resolver.update(uri, cv, null, null);
+ } else {
+ LogUtils.d(Logging.LOG_TAG, "moveMessage Cannot find account");
+ }
+ }
+
+ /**
+ * Set/clear boolean columns of a message
+ * @param messageId the message to update
+ * @param columnName the column to update
+ * @param columnValue the new value for the column
+ */
+ private void setMessageBoolean(long messageId, String columnName, boolean columnValue) {
+ ContentValues cv = new ContentValues();
+ cv.put(columnName, columnValue);
+ Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId);
+ mContext.getContentResolver().update(uri, cv, null, null);
+ }
+
+ /**
+ * Set/clear the unread status of a message
+ *
+ * @param messageId the message to update
+ * @param isRead the new value for the isRead flag
+ */
+ public void setMessageRead(long messageId, boolean isRead) {
+ setMessageBoolean(messageId, EmailContent.MessageColumns.FLAG_READ, isRead);
+ }
+
+ };
+
+ private final BluetoothEmailServiceStub mBinder = new BluetoothEmailServiceStub ();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ mBinder.init(this);
+ return mBinder;
+ }
+ }
diff --git a/provider_src/com/android/email/service/BluetoothPop3Service.java b/provider_src/com/android/email/service/BluetoothPop3Service.java
new file mode 100644
index 0000000..b8470bc
--- /dev/null
+++ b/provider_src/com/android/email/service/BluetoothPop3Service.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email.service;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.email.DebugUtils;
+import com.android.email.NotificationController;
+import com.android.email.NotificationControllerCreatorHolder;
+import com.android.email.mail.Store;
+import com.android.email.mail.store.Pop3Store;
+import com.android.email.mail.store.Pop3Store.Pop3Folder;
+import com.android.email.mail.store.Pop3Store.Pop3Message;
+import com.android.email.provider.Utilities;
+import com.android.emailcommon.Logging;
+import com.android.emailcommon.TrafficFlags;
+import com.android.emailcommon.mail.AuthenticationFailedException;
+import com.android.emailcommon.mail.Folder.OpenMode;
+import com.android.emailcommon.mail.MessagingException;
+import com.android.emailcommon.provider.Account;
+import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.EmailContent.Attachment;
+import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
+import com.android.emailcommon.provider.EmailContent.Message;
+import com.android.emailcommon.provider.EmailContent.MessageColumns;
+import com.android.emailcommon.provider.EmailContent.SyncColumns;
+import com.android.emailcommon.provider.Mailbox;
+import com.android.emailcommon.service.EmailServiceStatus;
+import com.android.emailcommon.service.IEmailServiceCallback;
+import com.android.emailcommon.utility.AttachmentUtilities;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.providers.UIProvider.AttachmentState;
+import com.android.mail.utils.LogUtils;
+
+import org.apache.james.mime4j.EOLConvertingInputStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import android.util.Log;
+
+public class BluetoothPop3Service extends Pop3Service {
+ private static final String TAG = "BluetoothPop3Service";
+ private static final String ACTION_CHECK_MAIL =
+ "org.codeaurora.email.intent.action.MAIL_SERVICE_WAKEUP";
+ private static final String EXTRA_ACCOUNT = "org.codeaurora.email.intent.extra.ACCOUNT";
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) return Service.START_STICKY;
+
+ final String action = intent.getAction();
+ Log.d(TAG, "action is " + action);
+ Context context = getApplicationContext();
+ if (ACTION_CHECK_MAIL.equals(action)) {
+ final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1);
+ final long inboxId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_INBOX);
+ Log.d(TAG, "accountId is " + accountId + ", inboxId is " + inboxId);
+ mBinder.init(context);
+ mBinder.requestSync(inboxId, true, 0);
+ }
+ return Service.START_STICKY;
+ }
+
+ /**
+ * Create our EmailService implementation here.
+ */
+ private final EmailServiceStub mBinder = new EmailServiceStub() {
+ @Override
+ public void loadMore(long messageId) throws RemoteException {
+ LogUtils.i(TAG, "Try to load more content for message: " + messageId);
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ mBinder.init(this);
+ return mBinder;
+ }
+
+ }
diff --git a/provider_src/com/android/email/service/EmailServiceUtils.java b/provider_src/com/android/email/service/EmailServiceUtils.java
index 3532689..4b93d1e 100644
--- a/provider_src/com/android/email/service/EmailServiceUtils.java
+++ b/provider_src/com/android/email/service/EmailServiceUtils.java
@@ -703,6 +703,10 @@
}
@Override
+ public void loadMore(long arg0) throws RemoteException {
+ }
+
+ @Override
public void updateFolderList(long accountId) throws RemoteException {}
@Override
diff --git a/provider_src/com/android/email/service/ExtendAuthenticatorService.java b/provider_src/com/android/email/service/ExtendAuthenticatorService.java
new file mode 100644
index 0000000..9975db2
--- /dev/null
+++ b/provider_src/com/android/email/service/ExtendAuthenticatorService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.email.service;
+
+/**
+ * This service needs to be declared separately from the base service
+ */
+public class ExtendAuthenticatorService {
+ public static class DefaultFirstAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultSecondAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultThirdAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultFourthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultFifthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultSixthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultSeventhAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultEighthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultNinthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultTenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultEleventhAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultTwelfthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultThirteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultFourteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultFifteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultSixteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultSeventeenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultEighteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultNinteenthAuthenticatorService extends AuthenticatorService {
+ }
+
+ public static class DefaultTwentithAuthenticatorService extends AuthenticatorService {
+ }
+}
diff --git a/provider_src/com/android/email/service/ImapService.java b/provider_src/com/android/email/service/ImapService.java
old mode 100644
new mode 100755
index d2dcd54..3814587
--- a/provider_src/com/android/email/service/ImapService.java
+++ b/provider_src/com/android/email/service/ImapService.java
@@ -26,6 +26,7 @@
import android.net.TrafficStats;
import android.net.Uri;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -59,6 +60,7 @@
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.service.EmailServiceStatus;
import com.android.emailcommon.service.SearchParams;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.service.SyncWindow;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.mail.providers.UIProvider;
@@ -137,6 +139,48 @@
*/
private final EmailServiceStub mBinder = new EmailServiceStub() {
@Override
+ public void loadMore(long messageId) throws RemoteException {
+ LogUtils.i("ImapService", "Try to load more content for message: " + messageId);
+ try {
+ final EmailContent.Message message =
+ EmailContent.Message.restoreMessageWithId(mContext, messageId);
+ if (message == null
+ || message.mFlagLoaded == EmailContent.Message.FLAG_LOADED_COMPLETE) {
+ return;
+ }
+
+ // Open the remote folder.
+ final Account account = Account.restoreAccountWithId(mContext, message.mAccountKey);
+ final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
+ if (account == null || mailbox == null) {
+ return;
+ }
+ TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account));
+
+ final Store remoteStore = Store.getInstance(account, mContext);
+ final String remoteServerId;
+ // If this is a search result, use the protocolSearchInfo field to get the
+ // correct remote location
+ if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) {
+ remoteServerId = message.mProtocolSearchInfo;
+ } else {
+ remoteServerId = mailbox.mServerId;
+ }
+ final Folder remoteFolder = remoteStore.getFolder(remoteServerId);
+ remoteFolder.open(OpenMode.READ_WRITE);
+
+ // Download the entire message
+ final Message remoteMessage = remoteFolder.getMessage(message.mServerId);
+ loadEntireViewableContent(mContext, account, remoteFolder, remoteMessage, mailbox,
+ message.mFlagSeen);
+ } catch (MessagingException me) {
+ LogUtils.v(Logging.LOG_TAG, "ImapService loadMore: ", me);
+ } catch (RuntimeException rte) {
+ LogUtils.d(Logging.LOG_TAG, "ImapService loadMore: ", rte);
+ }
+ }
+
+ @Override
public int searchMessages(long accountId, SearchParams searchParams, long destMailboxId) {
try {
return searchMailboxImpl(getApplicationContext(), accountId, searchParams,
@@ -244,6 +288,44 @@
}
/**
+ * Load the structure and body of messages
+ * @param account the account we're syncing
+ * @param remoteFolder the (open) Folder we're working on
+ * @param message the message we've got entire viewable content for
+ * @param toMailbox the destination mailbox we're syncing
+ * @throws MessagingException
+ */
+ static void loadEntireViewableContent(final Context context, final Account account,
+ Folder remoteFolder, Message message, final Mailbox toMailbox, boolean seen)
+ throws MessagingException {
+ FetchProfile fp = new FetchProfile();
+ fp.add(FetchProfile.Item.STRUCTURE);
+ Message [] oneMessageArray = new Message[] { message };
+ remoteFolder.fetch(oneMessageArray, fp, null);
+ // Build a list of parts we are interested in. Text parts will be downloaded
+ // right now, attachments will be left for later.
+ ArrayList<Part> viewables = new ArrayList<Part>();
+ ArrayList<Part> attachments = new ArrayList<Part>();
+ MimeUtility.collectParts(message, viewables, attachments);
+ // Download the viewables immediately
+ for (Part part : viewables) {
+ if (part.getMimeType().startsWith("text")) {
+ fp.clear();
+ fp.add(part);
+ remoteFolder.fetch(oneMessageArray, fp, null);
+ }
+ }
+
+ if (seen) {
+ // Set the SEEN flag to this message as it must be read.
+ message.setFlag(Flag.SEEN, true);
+ }
+ // Store the updated message locally and mark it fully loaded
+ Utilities.copyOneMessageToProvider(context, message, account, toMailbox,
+ EmailContent.Message.FLAG_LOADED_COMPLETE);
+ }
+
+ /**
* Load the structure and body of messages not yet synced
* @param account the account we're syncing
* @param remoteFolder the (open) Folder we're working on
@@ -267,14 +349,39 @@
MimeUtility.collectParts(message, viewables, attachments);
// Download the viewables immediately
oneMessageArray[0] = message;
+ boolean syncedEntireMail = true;
+ int allowSyncSize;
+ if (account.isSetSyncSizeEnabled()) {
+ allowSyncSize = account.getSyncSize();
+ } else {
+ allowSyncSize = SyncSize.SYNC_SIZE_ENTIRE_MAIL;
+ }
for (Part part : viewables) {
fp.clear();
fp.add(part);
+ // We will only try to limit the sync size for text part.
+ if (account.getSyncSize() != SyncSize.SYNC_SIZE_ENTIRE_MAIL
+ && part.getMimeType().startsWith("text")) {
+ LogUtils.d(Logging.LOG_TAG, "Try to fetch the text part as limit the size"
+ + ", part size: " + part.getSize()
+ + ", allow sync size: " + allowSyncSize);
+ // If the part's size is larger than allow sync size, it means this part
+ // couldn't get the entire content.
+ if (part.getSize() > allowSyncSize) {
+ syncedEntireMail = false;
+ // If the allow sync size is less than 0, it means this part needn't sync.
+ if (allowSyncSize <= 0) continue;
+ }
+ // Try to sync the viewable part, we need set the allow sync size for fp.
+ fp.setAllowSyncSize(allowSyncSize);
+ allowSyncSize = allowSyncSize - part.getSize();
+ }
remoteFolder.fetch(oneMessageArray, fp, null);
}
// Store the updated message locally and mark it fully loaded
Utilities.copyOneMessageToProvider(context, message, account, toMailbox,
- EmailContent.Message.FLAG_LOADED_COMPLETE);
+ syncedEntireMail ? EmailContent.Message.FLAG_LOADED_COMPLETE
+ : EmailContent.Message.FLAG_LOADED_PARTIAL_COMPLETE);
}
}
@@ -737,6 +844,26 @@
// 14. Clean up and report results
remoteFolder.close(false);
}
+ /**
+ * Find messages in the updated table that need to be written back to server.
+ * This is called from Intent methods to support Bluetooth MAP email sharing functionality.
+ * Handles:
+ * Read/Unread
+ * Flagged
+ * Append (upload)
+ * Move To Trash
+ * Empty trash
+ * TODO:
+ * Move
+ *
+ * @param account the account to scan for pending actions
+ * @throws MessagingException
+ */
+ public static void synchronizePendingActions(Context context, Account account,
+ Store remoteStore, boolean manualSync)
+ throws MessagingException {
+ processPendingActionsSynchronous(context, account, remoteStore, manualSync);
+ }
/**
* Find messages in the updated table that need to be written back to server.
diff --git a/provider_src/com/android/email/service/Pop3Service.java b/provider_src/com/android/email/service/Pop3Service.java
old mode 100644
new mode 100755
index 36e88d7..bd2fcd8
--- a/provider_src/com/android/email/service/Pop3Service.java
+++ b/provider_src/com/android/email/service/Pop3Service.java
@@ -27,6 +27,7 @@
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import android.text.TextUtils;
import com.android.email.DebugUtils;
import com.android.email.NotificationController;
@@ -39,6 +40,7 @@
import com.android.emailcommon.Logging;
import com.android.emailcommon.TrafficFlags;
import com.android.emailcommon.mail.AuthenticationFailedException;
+import com.android.emailcommon.mail.Flag;
import com.android.emailcommon.mail.Folder.OpenMode;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
@@ -51,6 +53,7 @@
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.service.EmailServiceStatus;
import com.android.emailcommon.service.IEmailServiceCallback;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AttachmentState;
@@ -62,13 +65,30 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import android.util.Log;
public class Pop3Service extends Service {
private static final String TAG = "Pop3Service";
private static final int DEFAULT_SYNC_COUNT = 100;
+ private static final String ACTION_CHECK_MAIL =
+ "com.android.email.intent.action.MAIL_SERVICE_WAKEUP";
+ private static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
+
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) return Service.START_STICKY;
+
+ final String action = intent.getAction();
+ Log.d(TAG, "action is " + action);
+ Context context = getApplicationContext();
+ if (ACTION_CHECK_MAIL.equals(action)) {
+ final long accountId = intent.getLongExtra(EXTRA_ACCOUNT, -1);
+ final long inboxId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_INBOX);
+ Log.d(TAG, "accountId is " + accountId + ", inboxId is " + inboxId);
+ mBinder.init(context);
+ mBinder.requestSync(inboxId, true, 0);
+ }
return Service.START_STICKY;
}
@@ -86,6 +106,56 @@
// We load attachments during a sync
requestSync(inboxId, true, 0);
}
+
+ @Override
+ public void loadMore(long messageId) throws RemoteException {
+ LogUtils.i(TAG, "Try to load more content for message: " + messageId);
+ try {
+ final Message message = Message.restoreMessageWithId(mContext, messageId);
+ if (message == null || message.mFlagLoaded == Message.FLAG_LOADED_COMPLETE) {
+ return;
+ }
+
+ // Open the remote folder.
+ final Account account = Account.restoreAccountWithId(mContext, message.mAccountKey);
+ final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
+ if (account == null || mailbox == null) {
+ return;
+ }
+ TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account));
+
+ final Pop3Store remoteStore = (Pop3Store) Store.getInstance(account, mContext);
+ final String remoteServerId;
+ // If this is a search result, use the protocolSearchInfo field to get the
+ // correct remote location
+ if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) {
+ remoteServerId = message.mProtocolSearchInfo;
+ } else {
+ remoteServerId = mailbox.mServerId;
+ }
+ final Pop3Folder remoteFolder = (Pop3Folder) remoteStore.getFolder(remoteServerId);
+ remoteFolder.open(OpenMode.READ_WRITE);
+
+ // Download the entire message
+ final Pop3Message remoteMessage = (Pop3Message) remoteFolder
+ .getMessage(message.mServerId);
+ remoteFolder.fetchBody(remoteMessage, -1 /* entire mail */, null);
+
+ if (message.mFlagSeen) {
+ // Set the SEEN flag to this message as it must be read.
+ remoteMessage.setFlag(Flag.SEEN, true);
+ }
+ // Store the updated message locally and mark it fully loaded
+ Utilities.copyOneMessageToProvider(mContext, remoteMessage, account, mailbox,
+ EmailContent.Message.FLAG_LOADED_COMPLETE);
+ } catch (MessagingException me) {
+ LogUtils.d(Logging.LOG_TAG, "Pop3Service loadMore: ", me);
+ } catch (RuntimeException rte) {
+ LogUtils.d(Logging.LOG_TAG, "Pop3Service loadMore: ", rte);
+ } catch (IOException ioe) {
+ LogUtils.d(Logging.LOG_TAG, "Pop3Service loadMore: ", ioe);
+ }
+ }
};
@Override
@@ -179,8 +249,18 @@
// They are in most recent to least recent order, process them that way.
for (int i = 0; i < cnt; i++) {
final Pop3Message message = unsyncedMessages.get(i);
- remoteFolder.fetchBody(message, Pop3Store.FETCH_BODY_SANE_SUGGESTED_SIZE / 76,
- null);
+
+ // Get the sync lines of this account's message.
+ int allowSyncLines = -1;
+ if (account.isSetSyncSizeEnabled()) {
+ if (account.getSyncSize() != SyncSize.SYNC_SIZE_ENTIRE_MAIL) {
+ allowSyncLines = account.getSyncSize() / 76;
+ }
+ } else {
+ allowSyncLines = Pop3Store.FETCH_BODY_SANE_SUGGESTED_SIZE / 76;
+ }
+
+ remoteFolder.fetchBody(message, allowSyncLines, null);
int flag = EmailContent.Message.FLAG_LOADED_COMPLETE;
if (!message.isComplete()) {
// TODO: when the message is not complete, this should mark the message as
@@ -188,7 +268,7 @@
// 1) Partial messages are shown in the conversation list
// 2) We are able to download the rest of the message/attachment when the
// user requests it.
- flag = EmailContent.Message.FLAG_LOADED_PARTIAL;
+ flag = EmailContent.Message.FLAG_LOADED_PARTIAL_COMPLETE;
}
if (DebugUtils.DEBUG) {
LogUtils.d(TAG, "Message is " + (message.isComplete() ? "" : "NOT ")
diff --git a/res/layout-w600dp/account_setup_options_fragment.xml b/res/layout-w600dp/account_setup_options_fragment.xml
index e92b2eb..e44920e 100644
--- a/res/layout-w600dp/account_setup_options_fragment.xml
+++ b/res/layout-w600dp/account_setup_options_fragment.xml
@@ -114,4 +114,28 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/account_setup_options_background_attachments_label" />
+ <View
+ android:id="@+id/account_sync_size_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/account_setup_divider_color" />
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <CheckBox
+ android:id="@+id/account_sync_size_enable"
+ style="@style/account_setup_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_sync_size_enable" />
+ <Spinner
+ android:id="@+id/account_sync_size"
+ android:layout_toRightOf="@+id/account_sync_size_enable"
+ android:layout_alignTop="@+id/account_sync_size_enable"
+ android:layout_alignBottom="@+id/account_sync_size_enable"
+ android:layout_marginLeft="10dip"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="invisible" />
+ </RelativeLayout>
</LinearLayout>
diff --git a/res/layout/account_settings_buttons.xml b/res/layout/account_settings_buttons.xml
index af6280e..1a4fa01 100644
--- a/res/layout/account_settings_buttons.xml
+++ b/res/layout/account_settings_buttons.xml
@@ -18,6 +18,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:background="@android:color/white"
style="?android:attr/buttonBarStyle" >
<Button
diff --git a/res/layout/account_setup_options_fragment.xml b/res/layout/account_setup_options_fragment.xml
index 8dd44d6..19d2c09 100644
--- a/res/layout/account_setup_options_fragment.xml
+++ b/res/layout/account_setup_options_fragment.xml
@@ -73,4 +73,22 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/account_setup_options_background_attachments_label" />
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <CheckBox
+ android:id="@+id/account_sync_size_enable"
+ style="@style/account_setup_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_sync_size_enable" />
+ <Spinner
+ android:id="@+id/account_sync_size"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@+id/account_sync_size_enable"
+ android:layout_alignTop="@+id/account_sync_size_enable"
+ android:layout_alignBottom="@+id/account_sync_size_enable"
+ android:visibility="invisible" />
+ </RelativeLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/res/mipmap-hdpi/ic_alice_email.png b/res/mipmap-hdpi/ic_alice_email.png
new file mode 100644
index 0000000..2232762
--- /dev/null
+++ b/res/mipmap-hdpi/ic_alice_email.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_alice_email.png b/res/mipmap-mdpi/ic_alice_email.png
new file mode 100644
index 0000000..2810d90
--- /dev/null
+++ b/res/mipmap-mdpi/ic_alice_email.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_alice_email.png b/res/mipmap-xhdpi/ic_alice_email.png
new file mode 100644
index 0000000..fdf0938
--- /dev/null
+++ b/res/mipmap-xhdpi/ic_alice_email.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_alice_email.png b/res/mipmap-xxhdpi/ic_alice_email.png
new file mode 100644
index 0000000..6bf8eef
--- /dev/null
+++ b/res/mipmap-xxhdpi/ic_alice_email.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_alice_email.png b/res/mipmap-xxxhdpi/ic_alice_email.png
new file mode 100644
index 0000000..2e37767
--- /dev/null
+++ b/res/mipmap-xxxhdpi/ic_alice_email.png
Binary files differ
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 65ab66d..a8ab580 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -239,4 +239,17 @@
<string name="no_quick_responses" msgid="8716297053803961304">"没有可供选择的快速回复"</string>
<string name="gmail_name" msgid="2099786953868369991">"Gmail"</string>
<string name="folder_sync_settings_pref_title" msgid="349478353401667107">"文件夹同步设置"</string>
+
+ <!-- In Account setup options & Account Settings screens, Email sync size option. -->
+ <string name="account_settings_sync_size_enable">配置邮件的同步缓存大小</string>
+ <string name="account_settings_sync_size_enable_summary">您可以自定义该账户中的邮件的同步缓存大小,从而节约数据流量</string>
+ <string name="account_settings_sync_size_label">选择同步缓存大小</string>
+ <string name="account_settings_sync_size_category_label">同步缓存大小配置</string>
+
+ <string name="account_setup_options_mail_sync_size_all">全部</string>
+ <string name="account_setup_options_mail_sync_size_20k">20KB</string>
+ <string name="account_setup_options_mail_sync_size_100k">100KB</string>
+ <string name="account_setup_options_mail_sync_size_200k">200KB</string>
+ <string name="account_setup_options_mail_sync_size_500k">500KB</string>
+ <string name="account_setup_options_mail_sync_size_1M">1MB</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e662f8d..8483b6d 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -239,4 +239,17 @@
<string name="no_quick_responses" msgid="8716297053803961304">"沒有可用的回應"</string>
<string name="gmail_name" msgid="2099786953868369991">"Gmail"</string>
<string name="folder_sync_settings_pref_title" msgid="349478353401667107">"資料夾同步處理設定"</string>
+
+ <!-- In Account setup options & Account Settings screens, Email sync size option. -->
+ <string name="account_settings_sync_size_enable">配置郵件的同步緩存大小</string>
+ <string name="account_settings_sync_size_enable_summary">您可以自由定義該帳戶中的郵件的同步緩存大小,從而節約數據流量</string>
+ <string name="account_settings_sync_size_label">選擇同步緩存大小</string>
+ <string name="account_settings_sync_size_category_label">同步緩存大小配置</string>
+
+ <string name="account_setup_options_mail_sync_size_all">全部</string>
+ <string name="account_setup_options_mail_sync_size_20k">20KB</string>
+ <string name="account_setup_options_mail_sync_size_100k">100KB</string>
+ <string name="account_setup_options_mail_sync_size_200k">200KB</string>
+ <string name="account_setup_options_mail_sync_size_500k">500KB</string>
+ <string name="account_setup_options_mail_sync_size_1M">1MB</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 99b013e..8eec351 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -239,4 +239,17 @@
<string name="no_quick_responses" msgid="8716297053803961304">"沒有可用的回應"</string>
<string name="gmail_name" msgid="2099786953868369991">"Gmail"</string>
<string name="folder_sync_settings_pref_title" msgid="349478353401667107">"資料夾同步處理設定"</string>
+
+ <!-- In Account setup options & Account Settings screens, Email sync size option. -->
+ <string name="account_settings_sync_size_enable">配置郵件的同步緩存大小</string>
+ <string name="account_settings_sync_size_enable_summary">您可以自由定義該帳戶中的郵件的同步緩存大小,從而節約數據流量</string>
+ <string name="account_settings_sync_size_label">選擇同步緩存大小</string>
+ <string name="account_settings_sync_size_category_label">同步緩存大小配置</string>
+
+ <string name="account_setup_options_mail_sync_size_all">全部</string>
+ <string name="account_setup_options_mail_sync_size_20k">20KB</string>
+ <string name="account_setup_options_mail_sync_size_100k">100KB</string>
+ <string name="account_setup_options_mail_sync_size_200k">200KB</string>
+ <string name="account_setup_options_mail_sync_size_500k">500KB</string>
+ <string name="account_setup_options_mail_sync_size_1M">1MB</string>
</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index a8393bc..0d76734 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -132,4 +132,24 @@
<item>pop</item>
<item>imap</item>
</string-array>
+
+ <!-- Mail sync size -->
+ <string-array name="account_setup_options_mail_sync_size_entries_labels">
+ <item>@string/account_setup_options_mail_sync_size_all</item>
+ <item>@string/account_setup_options_mail_sync_size_20k</item>
+ <item>@string/account_setup_options_mail_sync_size_100k</item>
+ <item>@string/account_setup_options_mail_sync_size_200k</item>
+ <item>@string/account_setup_options_mail_sync_size_500k</item>
+ <item>@string/account_setup_options_mail_sync_size_1M</item>
+ </string-array>
+
+ <string-array name="account_setup_options_mail_sync_size_entries_values">
+ <!-- This is the sync size for entire mail, and the value is the integer max value -->
+ <item>2147483647</item>
+ <item>20480</item>
+ <item>102400</item>
+ <item>204800</item>
+ <item>512000</item>
+ <item>1024000</item>
+ </string-array>
</resources>
diff --git a/res/values/constants.xml b/res/values/constants.xml
index 3b88d7d..f5a19e9 100644
--- a/res/values/constants.xml
+++ b/res/values/constants.xml
@@ -31,4 +31,17 @@
<!-- the email application starts services -->
<bool name="enable_services">true</bool>
-</resources>
\ No newline at end of file
+
+ <!-- Customize Email account's signature -->
+ <string name="customize_set_email_signature"></string>
+
+ <!-- Boolean value indicating whether we should allow force create account -->
+ <bool name="enable_force_configure_account">false</bool>
+
+ <!-- Boolean value to show Customize Email signature with brand -->
+ <bool name="config_email_signature_with_brand">false</bool>
+ <!-- Boolean value indicating whether modify email sync default size -->
+ <bool name="customize_email_sync_default_size">false</bool>
+ <!-- Customize Email sync size choice,default 307200 -->
+ <integer name="customize_mail_sync_default_size">307200</integer>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2f39425..fbdb403 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -682,4 +682,69 @@
<!-- Name for preference entry which leads to the per-folder sync settings activity -->
<string name="folder_sync_settings_pref_title">Folder sync settings</string>
+
+ <!-- In Account setup options & Account Settings screens, Email sync size option. -->
+ <string name="account_settings_sync_size_enable">Configure sync size per mail</string>
+ <string name="account_settings_sync_size_enable_summary">To save the data, you could configure the sync size per mail of the account</string>
+ <string name="account_settings_sync_size_label">Choose sync size</string>
+ <string name="account_settings_sync_size_category_label">Sync size settings</string>
+
+ <string name="account_setup_options_mail_sync_size_all">Entire</string>
+ <string name="account_setup_options_mail_sync_size_20k">20KB</string>
+ <string name="account_setup_options_mail_sync_size_100k">100KB</string>
+ <string name="account_setup_options_mail_sync_size_200k">200KB</string>
+ <string name="account_setup_options_mail_sync_size_500k">500KB</string>
+ <string name="account_setup_options_mail_sync_size_1M">1MB</string>
+
+ <!--Delete email account -->
+ <string name="remove_email_account">Remove account</string>
+ <string name="remove_email_account_continue">CONTINUE</string>
+ <string name="remove_email_account_message">You are about to go to the Settings app, where you can remove Accounts</string>
+ <string name="default_domain"></string>
+ <!-- Customize Email account's signature -->
+ <string name="default_email_signature"></string>
+ <string name="default_email_signature_with_brand"></string>
+ <string name="missing_required_permission">You have disabled a required permission.</string>
+ <string name="account_manager_type_default_first" translatable="false"></string>
+ <string name="default_first_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_second" translatable="false"></string>
+ <string name="default_second_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_third" translatable="false"></string>
+ <string name="default_third_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_fourth" translatable="false"></string>
+ <string name="default_fourth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_fifth" translatable="false"></string>
+ <string name="default_fifth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_sixth" translatable="false"></string>
+ <string name="default_sixth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_seventh" translatable="false"></string>
+ <string name="default_seventh_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_eighth" translatable="false"></string>
+ <string name="default_eighth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_ninth" translatable="false"></string>
+ <string name="default_ninth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_tenth" translatable="false"></string>
+ <string name="default_tenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_eleventh" translatable="false"></string>
+ <string name="default_eleventh_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_twelfth" translatable="false"></string>
+ <string name="default_twelfth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_thirteenth" translatable="false"></string>
+ <string name="default_thirteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_fourteenth" translatable="false"></string>
+ <string name="default_fourteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_fifteenth" translatable="false"></string>
+ <string name="default_fifteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_sixteenth" translatable="false"></string>
+ <string name="default_sixteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_seventeenth" translatable="false"></string>
+ <string name="default_seventeenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_eighteenth" translatable="false"></string>
+ <string name="default_eighteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_ninteenth" translatable="false"></string>
+ <string name="default_ninteenth_eas_name" translatable="false"></string>
+ <string name="account_manager_type_default_twentith" translatable="false"></string>
+ <string name="default_twentith_eas_name" translatable="false"></string>
+ <!-- string to show Email signature with brand -->
+ <string name="default_email_signature_with_brand"></string>
</resources>
diff --git a/res/xml/account_settings_preferences.xml b/res/xml/account_settings_preferences.xml
index 3cdd474..676e7f1 100755
--- a/res/xml/account_settings_preferences.xml
+++ b/res/xml/account_settings_preferences.xml
@@ -83,6 +83,26 @@
</PreferenceCategory>
+ <PreferenceCategory
+ android:title="@string/account_settings_sync_size_category_label">
+
+ <CheckBoxPreference
+ android:key="account_sync_size_enable"
+ android:enabled="false"
+ android:defaultValue="true"
+ android:title="@string/account_settings_sync_size_enable"
+ android:summary="@string/account_settings_sync_size_enable_summary" />
+
+ <ListPreference
+ android:key="account_sync_size"
+ android:enabled="false"
+ android:title="@string/account_settings_sync_size_label"
+ android:entries="@array/account_setup_options_mail_sync_size_entries_labels"
+ android:entryValues="@array/account_setup_options_mail_sync_size_entries_values"
+ android:dialogTitle="@string/account_settings_sync_size_label" />
+
+ </PreferenceCategory>
+
<!-- This category is enabled after the folder preferences are loaded -->
<PreferenceCategory
android:enabled="false"
diff --git a/res/xml/authenticator_default_eighteenth.xml b/res/xml/authenticator_default_eighteenth.xml
new file mode 100644
index 0000000..285d638
--- /dev/null
+++ b/res/xml/authenticator_default_eighteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_eighteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_eighteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_eighth.xml b/res/xml/authenticator_default_eighth.xml
new file mode 100644
index 0000000..dd7c2a8
--- /dev/null
+++ b/res/xml/authenticator_default_eighth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_eighth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_eighth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_eleventh.xml b/res/xml/authenticator_default_eleventh.xml
new file mode 100644
index 0000000..140901d
--- /dev/null
+++ b/res/xml/authenticator_default_eleventh.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_eleventh"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_eleventh_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_fifteenth.xml b/res/xml/authenticator_default_fifteenth.xml
new file mode 100644
index 0000000..774bc90
--- /dev/null
+++ b/res/xml/authenticator_default_fifteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_fifteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_fifteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_fifth.xml b/res/xml/authenticator_default_fifth.xml
new file mode 100644
index 0000000..8cd2494
--- /dev/null
+++ b/res/xml/authenticator_default_fifth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_fifth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_fifth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_first.xml b/res/xml/authenticator_default_first.xml
new file mode 100644
index 0000000..596b2e3
--- /dev/null
+++ b/res/xml/authenticator_default_first.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_first"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_first_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_fourteenth.xml b/res/xml/authenticator_default_fourteenth.xml
new file mode 100644
index 0000000..74dd24a
--- /dev/null
+++ b/res/xml/authenticator_default_fourteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_fourteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_fourteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_fourth.xml b/res/xml/authenticator_default_fourth.xml
new file mode 100644
index 0000000..82a9e70
--- /dev/null
+++ b/res/xml/authenticator_default_fourth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_fourth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_fourth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_ninteenth.xml b/res/xml/authenticator_default_ninteenth.xml
new file mode 100644
index 0000000..248b123
--- /dev/null
+++ b/res/xml/authenticator_default_ninteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_ninteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_ninteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_ninth.xml b/res/xml/authenticator_default_ninth.xml
new file mode 100644
index 0000000..b7726d3
--- /dev/null
+++ b/res/xml/authenticator_default_ninth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_ninth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_ninth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_second.xml b/res/xml/authenticator_default_second.xml
new file mode 100644
index 0000000..f054962
--- /dev/null
+++ b/res/xml/authenticator_default_second.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_second"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_second_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_seventeenth.xml b/res/xml/authenticator_default_seventeenth.xml
new file mode 100644
index 0000000..6cc51fa
--- /dev/null
+++ b/res/xml/authenticator_default_seventeenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_seventeenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_seventeenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_seventh.xml b/res/xml/authenticator_default_seventh.xml
new file mode 100644
index 0000000..ae3e0f6
--- /dev/null
+++ b/res/xml/authenticator_default_seventh.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_seventh"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_seventh_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_sixteenth.xml b/res/xml/authenticator_default_sixteenth.xml
new file mode 100644
index 0000000..0229c38
--- /dev/null
+++ b/res/xml/authenticator_default_sixteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_sixteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_sixteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_sixth.xml b/res/xml/authenticator_default_sixth.xml
new file mode 100644
index 0000000..e90700a
--- /dev/null
+++ b/res/xml/authenticator_default_sixth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_sixth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_sixth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_tenth.xml b/res/xml/authenticator_default_tenth.xml
new file mode 100644
index 0000000..13c25ae
--- /dev/null
+++ b/res/xml/authenticator_default_tenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_tenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_tenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_third.xml b/res/xml/authenticator_default_third.xml
new file mode 100644
index 0000000..5bb711b
--- /dev/null
+++ b/res/xml/authenticator_default_third.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_third"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_third_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_thirteenth.xml b/res/xml/authenticator_default_thirteenth.xml
new file mode 100644
index 0000000..d462ce8
--- /dev/null
+++ b/res/xml/authenticator_default_thirteenth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_thirteenth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_thirteenth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_twelfth.xml b/res/xml/authenticator_default_twelfth.xml
new file mode 100644
index 0000000..157ae2e
--- /dev/null
+++ b/res/xml/authenticator_default_twelfth.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_twelfth"
+ android:icon="@mipmap/ic_launcher_mail"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_twelfth_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/res/xml/authenticator_default_twentith.xml b/res/xml/authenticator_default_twentith.xml
new file mode 100644
index 0000000..606a453
--- /dev/null
+++ b/res/xml/authenticator_default_twentith.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="@string/account_manager_type_default_twentith"
+ android:icon="@mipmap/ic_alice_email"
+ android:smallIcon="@drawable/ic_notification_mail_24dp"
+ android:label="@string/default_twentith_eas_name"
+ android:accountPreferences="@xml/account_preferences"
+/>
diff --git a/src/com/android/email/activity/RequestPermissionsActivity.java b/src/com/android/email/activity/RequestPermissionsActivity.java
new file mode 100644
index 0000000..742eb47
--- /dev/null
+++ b/src/com/android/email/activity/RequestPermissionsActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.email.activity;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import com.android.email.R;
+
+/**
+ * Activity that requests permissions needed for activities exported from Contacts.
+ */
+public class RequestPermissionsActivity extends RequestPermissionsActivityBase {
+
+ private static final String[] REQUIRED_PERMISSIONS = new String[]{
+ permission.READ_CONTACTS, // Contacts group
+ permission.READ_EXTERNAL_STORAGE,
+ permission.WRITE_EXTERNAL_STORAGE,
+ permission.READ_CALENDAR, // Calendar group
+ permission.WRITE_CALENDAR, // Calendar group w
+ permission.GET_ACCOUNTS,
+ permission.READ_PHONE_STATE
+ };
+
+ @Override
+ protected String[] getRequiredPermissions() {
+ return REQUIRED_PERMISSIONS;
+ }
+
+ @Override
+ protected String[] getDesiredPermissions() {
+ return new String[]{
+ permission.READ_CONTACTS, // Contacts group
+ permission.READ_EXTERNAL_STORAGE,
+ permission.WRITE_EXTERNAL_STORAGE,
+ permission.READ_CALENDAR, // Calendar group
+ permission.WRITE_CALENDAR, // Calendar group w
+ permission.GET_ACCOUNTS,
+ permission.READ_PHONE_STATE
+ };
+ }
+
+ public static boolean startPermissionActivity(Activity activity) {
+ return startPermissionActivity(activity,
+ REQUIRED_PERMISSIONS,
+ RequestPermissionsActivity.class);
+ }
+}
diff --git a/src/com/android/email/activity/RequestPermissionsActivityBase.java b/src/com/android/email/activity/RequestPermissionsActivityBase.java
new file mode 100644
index 0000000..3933dfb
--- /dev/null
+++ b/src/com/android/email/activity/RequestPermissionsActivityBase.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.email.activity;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Trace;
+import android.widget.Toast;
+
+import com.android.email.R;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Activity that asks the user for all {@link #getDesiredPermissions} if any of
+ * {@link #getRequiredPermissions} are missing.
+ *
+ * NOTE: As a result of b/22095159, this can behave oddly in the case where the final permission
+ * you are requesting causes an application restart.
+ */
+public abstract class RequestPermissionsActivityBase extends Activity {
+ public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";
+ private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;
+
+ /**
+ * @return list of permissions that are needed in order for {@link #PREVIOUS_ACTIVITY_INTENT} to
+ * operate. You only need to return a single permission per permission group you care about.
+ */
+ protected abstract String[] getRequiredPermissions();
+
+ /**
+ * @return list of permissions that would be useful for {@link #PREVIOUS_ACTIVITY_INTENT} to
+ * operate. You only need to return a single permission per permission group you care about.
+ */
+ protected abstract String[] getDesiredPermissions();
+
+ private Intent mPreviousActivityIntent;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
+
+ // Only start a requestPermissions() flow when first starting this activity the first time.
+ // The process is likely to be restarted during the permission flow (necessary to enable
+ // permissions) so this is important to track.
+ if (savedInstanceState == null) {
+ requestPermissions();
+ }
+ }
+
+ /**
+ * If any permissions the Contacts app needs are missing, open an Activity
+ * to prompt the user for these permissions. Moreover, finish the current activity.
+ *
+ * This is designed to be called inside {@link android.app.Activity#onCreate}
+ */
+ protected static boolean startPermissionActivity(Activity activity,
+ String[] requiredPermissions, Class<?> newActivityClass) {
+ if (!RequestPermissionsActivity.hasPermissions(activity, requiredPermissions)) {
+ final Intent intent = new Intent(activity, newActivityClass);
+ intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
+ activity.startActivity(intent);
+ activity.finish();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String permissions[],
+ int[] grantResults) {
+ if (permissions != null && permissions.length > 0
+ && isAllGranted(permissions, grantResults)) {
+ mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ startActivity(mPreviousActivityIntent);
+ finish();
+ overridePendingTransition(0, 0);
+ } else {
+ Toast.makeText(this, R.string.missing_required_permission, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ }
+
+ private boolean isAllGranted(String permissions[], int[] grantResult) {
+ for (int i = 0; i < permissions.length; i++) {
+ if (grantResult[i] != PackageManager.PERMISSION_GRANTED
+ && isPermissionRequired(permissions[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isPermissionRequired(String p) {
+ return Arrays.asList(getRequiredPermissions()).contains(p);
+ }
+
+ private void requestPermissions() {
+ Trace.beginSection("requestPermissions");
+ try {
+ // Construct a list of missing permissions
+ final ArrayList<String> unsatisfiedPermissions = new ArrayList<>();
+ for (String permission : getDesiredPermissions()) {
+ if (checkSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ unsatisfiedPermissions.add(permission);
+ }
+ }
+ if (unsatisfiedPermissions.size() == 0) {
+ throw new RuntimeException("Request permission activity was called even"
+ + " though all permissions are satisfied.");
+ }
+ requestPermissions(
+ unsatisfiedPermissions.toArray(new String[unsatisfiedPermissions.size()]),
+ PERMISSIONS_REQUEST_ALL_PERMISSIONS);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ protected static boolean hasPermissions(Context context, String[] permissions) {
+ Trace.beginSection("hasPermission");
+ try {
+ for (String permission : permissions) {
+ if (context.checkSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ } finally {
+ Trace.endSection();
+ }
+ }
+}
diff --git a/src/com/android/email/activity/setup/AccountCreationFragment.java b/src/com/android/email/activity/setup/AccountCreationFragment.java
index 1f0d685..6c7f354 100644
--- a/src/com/android/email/activity/setup/AccountCreationFragment.java
+++ b/src/com/android/email/activity/setup/AccountCreationFragment.java
@@ -189,7 +189,9 @@
boolean createSuccess = false;
try {
- future.getResult();
+ if (future != null) {
+ future.getResult();
+ }
createSuccess = true;
} catch (OperationCanceledException e) {
LogUtils.d(LogUtils.TAG, "addAccount was canceled");
diff --git a/src/com/android/email/activity/setup/AccountSettingsEditQuickResponsesFragment.java b/src/com/android/email/activity/setup/AccountSettingsEditQuickResponsesFragment.java
index 3a782ca..f97a296 100644
--- a/src/com/android/email/activity/setup/AccountSettingsEditQuickResponsesFragment.java
+++ b/src/com/android/email/activity/setup/AccountSettingsEditQuickResponsesFragment.java
@@ -143,6 +143,13 @@
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.quick_response_prefs_fragment_menu, menu);
+
+ MenuItem feedbackMenuItem = menu.findItem(R.id.feedback_menu_item);
+ Uri feedbackUri = Utils.getValidUri(getString(R.string.email_feedback_uri));
+
+ if (feedbackMenuItem != null) {
+ feedbackMenuItem.setVisible(!Uri.EMPTY.equals(feedbackUri));
+ }
}
@Override
diff --git a/src/com/android/email/activity/setup/AccountSettingsFragment.java b/src/com/android/email/activity/setup/AccountSettingsFragment.java
index 30c3d9c..90d74af 100644
--- a/src/com/android/email/activity/setup/AccountSettingsFragment.java
+++ b/src/com/android/email/activity/setup/AccountSettingsFragment.java
@@ -44,6 +44,7 @@
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.Menu;
+import android.view.MenuItem;
import android.view.MenuInflater;
import com.android.email.R;
@@ -67,6 +68,7 @@
import com.android.mail.utils.ContentProviderTask.UpdateTask;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.NotificationUtils;
+import com.android.mail.utils.Utils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -94,6 +96,8 @@
private static final String PREFERENCE_SYNC_EMAIL = "account_sync_email";
private static final String PREFERENCE_SYNC_CONTACTS = "account_sync_contacts";
private static final String PREFERENCE_SYNC_CALENDAR = "account_sync_calendar";
+ private static final String PREFERENCE_SYNC_SIZE_ENABLE = "account_sync_size_enable";
+ private static final String PREFERENCE_SYNC_SIZE = "account_sync_size";
private static final String PREFERENCE_BACKGROUND_ATTACHMENTS =
"account_background_attachments";
private static final String PREFERENCE_CATEGORY_DATA_USAGE = "data_usage";
@@ -124,6 +128,8 @@
private ListPreference mCheckFrequency;
private ListPreference mSyncWindow;
private Preference mSyncSettings;
+ private CheckBoxPreference mSyncSizeEnable;
+ private ListPreference mSyncSize;
private CheckBoxPreference mInboxVibrate;
private Preference mInboxRingtone;
@@ -380,6 +386,10 @@
ContentResolver.setSyncAutomatically(androidAcct, CalendarContract.AUTHORITY,
(Boolean) newValue);
loadSettings();
+ } else if (key.equals(PREFERENCE_SYNC_SIZE_ENABLE)) {
+ final boolean enabled = (Boolean) newValue;
+ mSyncSize.setEnabled(enabled);
+ cv.put(AccountColumns.SET_SYNC_SIZE_ENABLED, enabled ? 1 : 0);
} else if (key.equals(PREFERENCE_BACKGROUND_ATTACHMENTS)) {
int newFlags = mAccount.getFlags() & ~(Account.FLAGS_BACKGROUND_ATTACHMENTS);
@@ -413,6 +423,13 @@
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.settings_fragment_menu, menu);
+
+ MenuItem feedbackMenuItem = menu.findItem(R.id.feedback_menu_item);
+ Uri feedbackUri = Utils.getValidUri(getString(R.string.email_feedback_uri));
+
+ if (feedbackMenuItem != null) {
+ feedbackMenuItem.setVisible(!Uri.EMPTY.equals(feedbackUri));
+ }
}
/**
@@ -783,6 +800,36 @@
}
}
+ mSyncSizeEnable = (CheckBoxPreference) findPreference(PREFERENCE_SYNC_SIZE_ENABLE);
+ mSyncSize = (ListPreference) findPreference(PREFERENCE_SYNC_SIZE);
+ if (mSyncSizeEnable != null && mSyncSize != null) {
+ mSyncSizeEnable.setOnPreferenceChangeListener(this);
+ mSyncSize.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final String summary = newValue.toString();
+ int index = mSyncSize.findIndexOfValue(summary);
+ mSyncSize.setSummary(mSyncSize.getEntries()[index]);
+ mSyncSize.setValue(summary);
+
+ // Commit the value
+ ContentValues cv = new ContentValues();
+ cv.put(AccountColumns.SYNC_SIZE, Integer.parseInt(summary));
+ new UpdateTask().run(mContext.getContentResolver(), mAccount.getUri(), cv,
+ null, null);
+ EmailProvider.setServicesEnabledAsync(mContext);
+ return false;
+ }
+ });
+
+ // Set sync size configurations
+ mSyncSizeEnable.setEnabled(true);
+ mSyncSizeEnable.setChecked(mAccount.isSetSyncSizeEnabled());
+
+ mSyncSize.setEnabled(mAccount.isSetSyncSizeEnabled());
+ mSyncSize.setValue(String.valueOf(mAccount.getSyncSize()));
+ mSyncSize.setSummary(mSyncSize.getEntry());
+ }
+
final PreferenceCategory notificationsCategory =
(PreferenceCategory) findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS);
diff --git a/src/com/android/email/activity/setup/AccountSetupFinal.java b/src/com/android/email/activity/setup/AccountSetupFinal.java
index adaa32a..04c7152 100644
--- a/src/com/android/email/activity/setup/AccountSetupFinal.java
+++ b/src/com/android/email/activity/setup/AccountSetupFinal.java
@@ -35,6 +35,7 @@
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
+import android.os.Build;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.text.TextUtils;
@@ -43,6 +44,7 @@
import android.widget.Toast;
import com.android.email.R;
+import com.android.email.activity.RequestPermissionsActivity;
import com.android.email.setup.AuthenticatorSetupIntentHelper;
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.VendorPolicyLoader;
@@ -182,6 +184,9 @@
@Override
public void onCreate(Bundle savedInstanceState) {
+ if (RequestPermissionsActivity.startPermissionActivity(this)) {
+ finish();
+ }
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
@@ -347,12 +352,17 @@
updateContentFragment(false /* addToBackstack */);
getFragmentManager().executePendingTransactions();
- if (!DEBUG_ALLOW_NON_TEST_HARNESS_CREATION &&
- !ActivityManager.isRunningInTestHarness()) {
- LogUtils.e(LogUtils.TAG,
- "ERROR: Force account create only allowed while in test harness");
- finish();
- return;
+ //Enabling force create account for OMA CP
+ boolean forceConfigurationEnabled = getResources()
+ .getBoolean(R.bool.enable_force_configure_account);
+ if(!forceConfigurationEnabled){
+ if (!DEBUG_ALLOW_NON_TEST_HARNESS_CREATION &&
+ !ActivityManager.isRunningInTestHarness()) {
+ LogUtils.e(LogUtils.TAG,
+ "ERROR: Force account create only allowed while in test harness");
+ finish();
+ return;
+ }
}
mForceCreate = true;
@@ -930,6 +940,16 @@
*/
private void populateSetupData(String senderName, String senderEmail) {
final Account account = mSetupData.getAccount();
+ String deviceName = Build.MODEL;
+ String signature = getResources().getString(R.string.default_email_signature, deviceName);
+ if (getResources().getBoolean(
+ R.bool.config_email_signature_with_brand)) {
+ signature = String.format(getResources().getString(
+ R.string.default_email_signature_with_brand) ,Build.BRAND);
+ }
+ if (!TextUtils.isEmpty(signature)) {
+ account.setSignature(signature);
+ }
account.setSenderName(senderName);
account.setEmailAddress(senderEmail);
account.setDisplayName(senderEmail);
@@ -1126,7 +1146,8 @@
newFlags |= Account.FLAGS_BACKGROUND_ATTACHMENTS;
}
final HostAuth hostAuth = account.getOrCreateHostAuthRecv(this);
- if (hostAuth.mProtocol.equals(getString(R.string.protocol_eas))) {
+ if (hostAuth.mProtocol.equals(getString(R.string.protocol_eas))
+ && account.mProtocolVersion != null) {
try {
final double protocolVersionDouble = Double.parseDouble(account.mProtocolVersion);
if (protocolVersionDouble >= 12.0) {
@@ -1143,6 +1164,8 @@
}
account.setFlags(newFlags);
account.setSyncInterval(fragment.getCheckFrequencyValue());
+ account.setSyncSizeEnabled(fragment.getSyncSizeEnabledValue());
+ account.setSyncSize(fragment.getSyncSizeValue());
final Integer syncWindowValue = fragment.getAccountSyncWindowValue();
if (syncWindowValue != null) {
account.setSyncLookback(syncWindowValue);
diff --git a/src/com/android/email/activity/setup/AccountSetupOptionsFragment.java b/src/com/android/email/activity/setup/AccountSetupOptionsFragment.java
index 9d048c1..c8ccc91 100644
--- a/src/com/android/email/activity/setup/AccountSetupOptionsFragment.java
+++ b/src/com/android/email/activity/setup/AccountSetupOptionsFragment.java
@@ -22,6 +22,8 @@
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
import com.android.email.R;
@@ -29,11 +31,14 @@
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.Policy;
+import com.android.emailcommon.service.SyncSize;
import com.android.emailcommon.service.SyncWindow;
public class AccountSetupOptionsFragment extends AccountSetupFragment {
private Spinner mCheckFrequencyView;
private Spinner mSyncWindowView;
+ private CheckBox mSyncSizeEnableView;
+ private Spinner mSyncSizeView;
private View mSyncwindowLabel;
private CheckBox mNotifyView;
private CheckBox mSyncContactsView;
@@ -60,6 +65,8 @@
mCheckFrequencyView = UiUtilities.getView(view, R.id.account_check_frequency);
mSyncWindowView = UiUtilities.getView(view, R.id.account_sync_window);
+ mSyncSizeEnableView = UiUtilities.getView(view, R.id.account_sync_size_enable);
+ mSyncSizeView = UiUtilities.getView(view, R.id.account_sync_size);
mNotifyView = UiUtilities.getView(view, R.id.account_notify);
mNotifyView.setChecked(true);
mSyncContactsView = UiUtilities.getView(view, R.id.account_sync_contacts);
@@ -107,6 +114,26 @@
enableLookbackSpinner(account);
}
+ // Configure the sync size
+ mSyncSizeEnableView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ int visibility = isChecked ? View.VISIBLE : View.INVISIBLE;
+ mSyncSizeView.setVisibility(visibility);
+ UiUtilities.setVisibilitySafe(view, R.id.account_sync_size, visibility);
+ }
+ });
+ buildSyncSizeSpinner(account);
+ if (account.isSetSyncSizeEnabled()) {
+ mSyncSizeEnableView.setChecked(true);
+ mSyncSizeView.setVisibility(View.VISIBLE);
+ UiUtilities.setVisibilitySafe(view, R.id.account_sync_size, View.VISIBLE);
+ } else {
+ mSyncSizeEnableView.setChecked(false);
+ mSyncSizeView.setVisibility(View.INVISIBLE);
+ UiUtilities.setVisibilitySafe(view, R.id.account_sync_size, View.INVISIBLE);
+ }
+
if (serviceInfo.syncContacts) {
mSyncContactsView.setVisibility(View.VISIBLE);
mSyncContactsView.setChecked(true);
@@ -210,4 +237,56 @@
public boolean getNotifyValue() {
return mNotifyView.isChecked();
}
+
+ public boolean getSyncSizeEnabledValue() {
+ return mSyncSizeEnableView.isChecked();
+ }
+
+ public int getSyncSizeValue() {
+ if (mSyncSizeView.getVisibility() != View.VISIBLE) {
+ return SyncSize.SYNC_SIZE_ENTIRE_MAIL;
+ }
+ return (int) ((SpinnerOption)mSyncSizeView.getSelectedItem()).value;
+ }
+
+ /**
+ * Build an additional spinner to let the user could choose sync size.
+ */
+ private void buildSyncSizeSpinner(Account account) {
+ // Generate spinner entries using XML arrays used by the preferences
+ CharSequence[] sizeValues = getResources().getTextArray(
+ R.array.account_setup_options_mail_sync_size_entries_values);
+ CharSequence[] sizeEntries = getResources().getTextArray(
+ R.array.account_setup_options_mail_sync_size_entries_labels);
+
+ // Now create the array used by the Spinner
+ SpinnerOption[] syncSizes = new SpinnerOption[sizeEntries.length];
+ int defaultIndex = -1;
+ for (int i = 0; i < sizeEntries.length; ++i) {
+ final int value = Integer.valueOf(sizeValues[i].toString());
+ syncSizes[i] = new SpinnerOption(value, sizeEntries[i].toString());
+ if(getResources().getBoolean(R.bool.customize_email_sync_default_size)) {
+ if (value == getResources().getInteger(R.integer.
+ customize_mail_sync_default_size)) {
+ defaultIndex = i;
+ }
+ }else{
+ if (value == SyncSize.SYNC_SIZE_DEFAULT_VALUE) {
+ defaultIndex = i;
+ }
+ }
+ }
+
+ ArrayAdapter<SpinnerOption> syncSizesAdapter = new ArrayAdapter<SpinnerOption>(
+ getActivity(), android.R.layout.simple_spinner_item, syncSizes);
+ syncSizesAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mSyncSizeView.setAdapter(syncSizesAdapter);
+
+ // set the default value
+ SpinnerOption.setSpinnerOptionValue(mSyncSizeView, account.getSyncSize());
+ if (defaultIndex >= 0) {
+ mSyncSizeView.setSelection(defaultIndex);
+ }
+ }
}
diff --git a/src/com/android/email/activity/setup/EmailPreferenceActivity.java b/src/com/android/email/activity/setup/EmailPreferenceActivity.java
index cbb47b9..62fb401 100644
--- a/src/com/android/email/activity/setup/EmailPreferenceActivity.java
+++ b/src/com/android/email/activity/setup/EmailPreferenceActivity.java
@@ -27,6 +27,7 @@
import android.view.MenuItem;
import com.android.email.R;
+import com.android.email.activity.RequestPermissionsActivity;
import com.android.email.setup.AuthenticatorSetupIntentHelper;
import com.android.emailcommon.utility.IntentUtilities;
import com.android.mail.providers.UIProvider.EditSettingsExtras;
@@ -93,6 +94,9 @@
@Override
public void onCreate(Bundle savedInstanceState) {
+ if (RequestPermissionsActivity.startPermissionActivity(this)) {
+ finish();
+ }
super.onCreate(savedInstanceState);
final Intent i = getIntent();
diff --git a/src/com/android/email/mail/transport/SmtpSender.java b/src/com/android/email/mail/transport/SmtpSender.java
old mode 100644
new mode 100755
index 060b9ca..14756d9
--- a/src/com/android/email/mail/transport/SmtpSender.java
+++ b/src/com/android/email/mail/transport/SmtpSender.java
@@ -213,6 +213,13 @@
} catch (IOException ioe) {
throw new MessagingException("Unable to send message", ioe);
}
+ finally {
+ try {
+ close();
+ } catch (RuntimeException ioe) {
+ throw new RuntimeException("DEBUG #Unable to send message", ioe);
+ }
+ }
}
/**
diff --git a/src/com/android/email2/ui/MailActivityEmail.java b/src/com/android/email2/ui/MailActivityEmail.java
index 23b3fac..630a03b 100644
--- a/src/com/android/email2/ui/MailActivityEmail.java
+++ b/src/com/android/email2/ui/MailActivityEmail.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import com.android.email.Preferences;
+import com.android.email.activity.RequestPermissionsActivity;
import com.android.email.provider.EmailProvider;
import com.android.email.service.AttachmentService;
import com.android.email.service.EmailServiceUtils;
@@ -57,6 +58,9 @@
@Override
public void onCreate(Bundle bundle) {
+ if (RequestPermissionsActivity.startPermissionActivity(this)) {
+ finish();
+ }
final Intent intent = getIntent();
final Uri data = intent != null ? intent.getData() : null;
if (data != null) {
diff --git a/tests/src/com/android/emailcommon/service/SearchParamsTests.java b/tests/src/com/android/emailcommon/service/SearchParamsTests.java
index e69809c..99f8f4b 100644
--- a/tests/src/com/android/emailcommon/service/SearchParamsTests.java
+++ b/tests/src/com/android/emailcommon/service/SearchParamsTests.java
@@ -23,7 +23,7 @@
@Suppress
public class SearchParamsTests extends AndroidTestCase {
public void brokentestParcel() {
- SearchParams params = new SearchParams(1, "query");
+ SearchParams params = new SearchParams(1, "query", "factor");
params.mIncludeChildren = true;
params.mLimit = 66;
params.mOffset = 99;