Sync jb-dev to jb-ub-mail Exchange
* For convenience in Eclipse
Change-Id: I99da4238ed83f29c33bd9116faa66edc5c1429a7
diff --git a/exchange2/src/com/android/exchange/EasSyncService.java b/exchange2/src/com/android/exchange/EasSyncService.java
index f1e544d..657bc84 100644
--- a/exchange2/src/com/android/exchange/EasSyncService.java
+++ b/exchange2/src/com/android/exchange/EasSyncService.java
@@ -166,6 +166,7 @@
private boolean mSsl = true;
private boolean mTrustSsl = false;
private String mClientCertAlias = null;
+ private int mPort;
public ContentResolver mContentResolver;
// Whether or not the sync service is valid (usable)
@@ -387,10 +388,7 @@
svc.mUserName = ha.mLogin;
svc.mPassword = ha.mPassword;
try {
- svc.setConnectionParameters(
- (ha.mFlags & HostAuth.FLAG_SSL) != 0,
- (ha.mFlags & HostAuth.FLAG_TRUST_ALL) != 0,
- ha.mClientCertAlias);
+ svc.setConnectionParameters(ha);
svc.mDeviceId = ExchangeService.getDeviceId(context);
} catch (IOException e) {
return null;
@@ -441,10 +439,7 @@
mUserName = hostAuth.mLogin;
mPassword = hostAuth.mPassword;
- setConnectionParameters(
- hostAuth.shouldUseSsl(),
- hostAuth.shouldTrustAllServerCerts(),
- hostAuth.mClientCertAlias);
+ setConnectionParameters(hostAuth);
mDeviceId = ExchangeService.getDeviceId(context);
mAccount = new Account();
mAccount.mEmailAddress = hostAuth.mLogin;
@@ -705,6 +700,10 @@
// Initialize the user name and password
mUserName = userName;
mPassword = password;
+ // Port is always 443 and SSL is used
+ mPort = 443;
+ mSsl = true;
+
// Make sure the authentication string is recreated and cached
cacheAuthUserAndBaseUriStrings();
@@ -1215,26 +1214,23 @@
}
}
- protected void setConnectionParameters(
- boolean useSsl, boolean trustAllServerCerts, String clientCertAlias)
- throws CertificateException {
-
- EmailClientConnectionManager connManager = getClientConnectionManager();
-
- mSsl = useSsl;
- mTrustSsl = trustAllServerCerts;
- mClientCertAlias = clientCertAlias;
+ protected void setConnectionParameters(HostAuth hostAuth) throws CertificateException {
+ mSsl = hostAuth.shouldUseSsl();
+ mTrustSsl = hostAuth.shouldTrustAllServerCerts();
+ mClientCertAlias = hostAuth.mClientCertAlias;
+ mPort = hostAuth.mPort;
// Register the new alias, if needed.
if (mClientCertAlias != null) {
// Ensure that the connection manager knows to use the proper client certificate
// when establishing connections for this service.
- connManager.registerClientCert(mContext, mClientCertAlias, mTrustSsl);
+ EmailClientConnectionManager connManager = getClientConnectionManager();
+ connManager.registerClientCert(mContext, hostAuth);
}
}
private EmailClientConnectionManager getClientConnectionManager() {
- return ExchangeService.getClientConnectionManager();
+ return ExchangeService.getClientConnectionManager(mSsl, mPort);
}
private HttpClient getHttpClient(int timeout) {
@@ -1668,14 +1664,14 @@
// Start with the default timeout
int timeout = COMMAND_TIMEOUT;
- if (!syncKey.equals("0")) {
- // EAS doesn't allow GetChanges in an initial sync; sending other options
- // appears to cause the server to delay its response in some cases, and this delay
- // can be long enough to result in an IOException and total failure to sync.
- // Therefore, we don't send any options with the initial sync.
- // Set the truncation amount, body preference, lookback, etc.
- target.sendSyncOptions(mProtocolVersionDouble, s);
- } else {
+ boolean initialSync = syncKey.equals("0");
+ // EAS doesn't allow GetChanges in an initial sync; sending other options
+ // appears to cause the server to delay its response in some cases, and this delay
+ // can be long enough to result in an IOException and total failure to sync.
+ // Therefore, we don't send any options with the initial sync.
+ // Set the truncation amount, body preference, lookback, etc.
+ target.sendSyncOptions(mProtocolVersionDouble, s, initialSync);
+ if (initialSync) {
// Use enormous timeout for initial sync, which empirically can take a while longer
timeout = 120*SECONDS;
}
@@ -1805,10 +1801,7 @@
mPassword = ha.mPassword;
try {
- setConnectionParameters(
- (ha.mFlags & HostAuth.FLAG_SSL) != 0,
- (ha.mFlags & HostAuth.FLAG_TRUST_ALL) != 0,
- ha.mClientCertAlias);
+ setConnectionParameters(ha);
} catch (CertificateException e) {
userLog("Couldn't retrieve certificate for connection");
try {
diff --git a/exchange2/src/com/android/exchange/ExchangeService.java b/exchange2/src/com/android/exchange/ExchangeService.java
index 0107d55..b1ae3b7 100644
--- a/exchange2/src/com/android/exchange/ExchangeService.java
+++ b/exchange2/src/com/android/exchange/ExchangeService.java
@@ -220,8 +220,9 @@
private static Thread sServiceThread = null;
// Cached unique device id
private static String sDeviceId = null;
- // ConnectionManager that all EAS threads can use
- private static EmailClientConnectionManager sClientConnectionManager = null;
+ // HashMap of ConnectionManagers that all EAS threads can use (by ssl/port pair)
+ private static HashMap<Integer, EmailClientConnectionManager> sClientConnectionManagers =
+ new HashMap<Integer, EmailClientConnectionManager>();
// Count of ClientConnectionManager shutdowns
private static volatile int sClientConnectionManagerShutdownCount = 0;
@@ -1263,8 +1264,12 @@
}
};
- static public synchronized EmailClientConnectionManager getClientConnectionManager() {
- if (sClientConnectionManager == null) {
+ static public synchronized EmailClientConnectionManager getClientConnectionManager(boolean ssl,
+ int port) {
+ // We'll use a different connection manager for each ssl/port pair
+ int key = (ssl ? 0x10000 : 0) + port;
+ EmailClientConnectionManager mgr = sClientConnectionManagers.get(key);
+ if (mgr == null) {
// After two tries, kill the process. Most likely, this will happen in the background
// The service will restart itself after about 5 seconds
if (sClientConnectionManagerShutdownCount > MAX_CLIENT_CONNECTION_MANAGER_SHUTDOWNS) {
@@ -1274,19 +1279,20 @@
HttpParams params = new BasicHttpParams();
params.setIntParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 25);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, sConnPerRoute);
- sClientConnectionManager = EmailClientConnectionManager.newInstance(params);
+ mgr = EmailClientConnectionManager.newInstance(params, ssl, port);
+ log("Creating connection manager for port " + port + ", ssl: " + ssl);
+ sClientConnectionManagers.put(key, mgr);
}
// Null is a valid return result if we get an exception
- return sClientConnectionManager;
+ return mgr;
}
static private synchronized void shutdownConnectionManager() {
- if (sClientConnectionManager != null) {
- log("Shutting down ClientConnectionManager");
- sClientConnectionManager.shutdown();
- sClientConnectionManagerShutdownCount++;
- sClientConnectionManager = null;
+ log("Shutting down ClientConnectionManagers");
+ for (EmailClientConnectionManager mgr: sClientConnectionManagers.values()) {
+ mgr.shutdown();
}
+ sClientConnectionManagers.clear();
}
public static void stopAccountSyncs(long acctId) {
diff --git a/exchange2/src/com/android/exchange/adapter/AbstractSyncAdapter.java b/exchange2/src/com/android/exchange/adapter/AbstractSyncAdapter.java
index 52400c4..04a67d0 100644
--- a/exchange2/src/com/android/exchange/adapter/AbstractSyncAdapter.java
+++ b/exchange2/src/com/android/exchange/adapter/AbstractSyncAdapter.java
@@ -71,7 +71,8 @@
public abstract void cleanup();
public abstract boolean isSyncable();
// Add sync options (filter, body type - html vs plain, and truncation)
- public abstract void sendSyncOptions(Double protocolVersion, Serializer s) throws IOException;
+ public abstract void sendSyncOptions(Double protocolVersion, Serializer s, boolean initialSync)
+ throws IOException;
/**
* Delete all records of this class in this account
*/
diff --git a/exchange2/src/com/android/exchange/adapter/AccountSyncAdapter.java b/exchange2/src/com/android/exchange/adapter/AccountSyncAdapter.java
index cf54ed5..e56a7d3 100644
--- a/exchange2/src/com/android/exchange/adapter/AccountSyncAdapter.java
+++ b/exchange2/src/com/android/exchange/adapter/AccountSyncAdapter.java
@@ -40,6 +40,7 @@
}
@Override
- public void sendSyncOptions(Double protocolVersion, Serializer s) throws IOException {
+ public void sendSyncOptions(Double protocolVersion, Serializer s, boolean initialSync)
+ throws IOException {
}
}
diff --git a/exchange2/src/com/android/exchange/adapter/CalendarSyncAdapter.java b/exchange2/src/com/android/exchange/adapter/CalendarSyncAdapter.java
index 4df45a9..c21be00 100644
--- a/exchange2/src/com/android/exchange/adapter/CalendarSyncAdapter.java
+++ b/exchange2/src/com/android/exchange/adapter/CalendarSyncAdapter.java
@@ -223,8 +223,11 @@
}
@Override
- public void sendSyncOptions(Double protocolVersion, Serializer s) throws IOException {
- setPimSyncOptions(protocolVersion, Eas.FILTER_2_WEEKS, s);
+ public void sendSyncOptions(Double protocolVersion, Serializer s, boolean initialSync)
+ throws IOException {
+ if (!initialSync) {
+ setPimSyncOptions(protocolVersion, Eas.FILTER_2_WEEKS, s);
+ }
}
@Override
diff --git a/exchange2/src/com/android/exchange/adapter/ContactsSyncAdapter.java b/exchange2/src/com/android/exchange/adapter/ContactsSyncAdapter.java
index 1b21d11..c0c3a48 100644
--- a/exchange2/src/com/android/exchange/adapter/ContactsSyncAdapter.java
+++ b/exchange2/src/com/android/exchange/adapter/ContactsSyncAdapter.java
@@ -58,13 +58,17 @@
import android.util.Base64;
import android.util.Log;
+import com.android.emailcommon.utility.Utility;
import com.android.exchange.CommandStatusException;
import com.android.exchange.Eas;
import com.android.exchange.EasSyncService;
+import com.android.exchange.utility.CalendarUtilities;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
/**
* Sync adapter for EAS Contacts
@@ -144,8 +148,73 @@
}
@Override
- public void sendSyncOptions(Double protocolVersion, Serializer s) throws IOException {
- setPimSyncOptions(protocolVersion, null, s);
+ public void sendSyncOptions(Double protocolVersion, Serializer s, boolean initialSync)
+ throws IOException {
+ if (initialSync) {
+ // These are the tags we support for upload; whenever we add/remove support
+ // (in addData), we need to update this list
+ s.start(Tags.SYNC_SUPPORTED);
+ s.tag(Tags.CONTACTS_FIRST_NAME);
+ s.tag(Tags.CONTACTS_LAST_NAME);
+ s.tag(Tags.CONTACTS_MIDDLE_NAME);
+ s.tag(Tags.CONTACTS_SUFFIX);
+ s.tag(Tags.CONTACTS_COMPANY_NAME);
+ s.tag(Tags.CONTACTS_JOB_TITLE);
+ s.tag(Tags.CONTACTS_EMAIL1_ADDRESS);
+ s.tag(Tags.CONTACTS_EMAIL2_ADDRESS);
+ s.tag(Tags.CONTACTS_EMAIL3_ADDRESS);
+ s.tag(Tags.CONTACTS_BUSINESS2_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_BUSINESS_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS2_MMS);
+ s.tag(Tags.CONTACTS_BUSINESS_FAX_NUMBER);
+ s.tag(Tags.CONTACTS2_COMPANY_MAIN_PHONE);
+ s.tag(Tags.CONTACTS_HOME_FAX_NUMBER);
+ s.tag(Tags.CONTACTS_HOME_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_HOME2_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_MOBILE_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_CAR_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_RADIO_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS_PAGER_NUMBER);
+ s.tag(Tags.CONTACTS_ASSISTANT_TELEPHONE_NUMBER);
+ s.tag(Tags.CONTACTS2_IM_ADDRESS);
+ s.tag(Tags.CONTACTS2_IM_ADDRESS_2);
+ s.tag(Tags.CONTACTS2_IM_ADDRESS_3);
+ s.tag(Tags.CONTACTS_BUSINESS_ADDRESS_CITY);
+ s.tag(Tags.CONTACTS_BUSINESS_ADDRESS_COUNTRY);
+ s.tag(Tags.CONTACTS_BUSINESS_ADDRESS_POSTAL_CODE);
+ s.tag(Tags.CONTACTS_BUSINESS_ADDRESS_STATE);
+ s.tag(Tags.CONTACTS_BUSINESS_ADDRESS_STREET);
+ s.tag(Tags.CONTACTS_HOME_ADDRESS_CITY);
+ s.tag(Tags.CONTACTS_HOME_ADDRESS_COUNTRY);
+ s.tag(Tags.CONTACTS_HOME_ADDRESS_POSTAL_CODE);
+ s.tag(Tags.CONTACTS_HOME_ADDRESS_STATE);
+ s.tag(Tags.CONTACTS_HOME_ADDRESS_STREET);
+ s.tag(Tags.CONTACTS_OTHER_ADDRESS_CITY);
+ s.tag(Tags.CONTACTS_OTHER_ADDRESS_COUNTRY);
+ s.tag(Tags.CONTACTS_OTHER_ADDRESS_POSTAL_CODE);
+ s.tag(Tags.CONTACTS_OTHER_ADDRESS_STATE);
+ s.tag(Tags.CONTACTS_OTHER_ADDRESS_STREET);
+ s.tag(Tags.CONTACTS_YOMI_COMPANY_NAME);
+ s.tag(Tags.CONTACTS_YOMI_FIRST_NAME);
+ s.tag(Tags.CONTACTS_YOMI_LAST_NAME);
+ s.tag(Tags.CONTACTS2_NICKNAME);
+ s.tag(Tags.CONTACTS_ASSISTANT_NAME);
+ s.tag(Tags.CONTACTS2_MANAGER_NAME);
+ s.tag(Tags.CONTACTS_SPOUSE);
+ s.tag(Tags.CONTACTS_DEPARTMENT);
+ s.tag(Tags.CONTACTS_TITLE);
+ s.tag(Tags.CONTACTS_OFFICE_LOCATION);
+ s.tag(Tags.CONTACTS2_CUSTOMER_ID);
+ s.tag(Tags.CONTACTS2_GOVERNMENT_ID);
+ s.tag(Tags.CONTACTS2_ACCOUNT_NAME);
+ s.tag(Tags.CONTACTS_ANNIVERSARY);
+ s.tag(Tags.CONTACTS_BIRTHDAY);
+ s.tag(Tags.CONTACTS_WEBPAGE);
+ s.tag(Tags.CONTACTS_PICTURE);
+ s.end(); // SYNC_SUPPORTED
+ } else {
+ setPimSyncOptions(protocolVersion, null, s);
+ }
}
@Override
@@ -294,11 +363,13 @@
}
}
+ @Override
public void addValues(RowBuilder builder) {
builder.withValue(Email.DATA, email);
builder.withValue(Email.DISPLAY_NAME, displayName);
}
+ @Override
public boolean isSameAs(int type, String value) {
return email.equalsIgnoreCase(value);
}
@@ -311,10 +382,12 @@
im = _im;
}
+ @Override
public void addValues(RowBuilder builder) {
builder.withValue(Im.DATA, im);
}
+ @Override
public boolean isSameAs(int type, String value) {
return im.equalsIgnoreCase(value);
}
@@ -329,11 +402,13 @@
type = _type;
}
+ @Override
public void addValues(RowBuilder builder) {
builder.withValue(Im.DATA, phone);
builder.withValue(Phone.TYPE, type);
}
+ @Override
public boolean isSameAs(int _type, String value) {
return type == _type && phone.equalsIgnoreCase(value);
}
@@ -352,7 +427,6 @@
public void addData(String serverId, ContactOperations ops, Entity entity)
throws IOException {
- String fileAs = null;
String prefix = null;
String firstName = null;
String lastName = null;
@@ -390,9 +464,6 @@
case Tags.CONTACTS_MIDDLE_NAME:
middleName = getValue();
break;
- case Tags.CONTACTS_FILE_AS:
- fileAs = getValue();
- break;
case Tags.CONTACTS_SUFFIX:
suffix = getValue();
break;
@@ -568,11 +639,6 @@
categoriesParser(ops, entity);
break;
- case Tags.CONTACTS_COMPRESSED_RTF:
- // We don't use this, and it isn't necessary to upload, so we'll ignore it
- skipTag();
- break;
-
default:
skipTag();
}
@@ -593,7 +659,7 @@
}
ops.addName(entity, prefix, firstName, lastName, middleName, suffix, name,
- yomiFirstName, yomiLastName, fileAs);
+ yomiFirstName, yomiLastName);
ops.addBusiness(entity, business);
ops.addPersonal(entity, personal);
@@ -1202,14 +1268,21 @@
if (cv != null && cvCompareString(cv, Event.START_DATE, birthday)) {
return;
}
- builder.withValue(Event.START_DATE, birthday);
+ long millis = Utility.parseEmailDateTimeToMillis(birthday);
+ GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+ cal.setTimeInMillis(millis);
+ if (cal.get(GregorianCalendar.HOUR_OF_DAY) >= 12) {
+ cal.add(GregorianCalendar.DATE, 1);
+ }
+ String realBirthday = CalendarUtilities.calendarToBirthdayString(cal);
+ builder.withValue(Event.START_DATE, realBirthday);
builder.withValue(Event.TYPE, Event.TYPE_BIRTHDAY);
add(builder.build());
}
public void addName(Entity entity, String prefix, String givenName, String familyName,
String middleName, String suffix, String displayName, String yomiFirstName,
- String yomiLastName, String fileAs) {
+ String yomiLastName) {
RowBuilder builder = untypedRowBuilder(entity, StructuredName.CONTENT_ITEM_TYPE);
ContentValues cv = builder.cv;
if (cv != null && cvCompareString(cv, StructuredName.GIVEN_NAME, givenName) &&
@@ -1218,7 +1291,6 @@
cvCompareString(cv, StructuredName.PREFIX, prefix) &&
cvCompareString(cv, StructuredName.PHONETIC_GIVEN_NAME, yomiFirstName) &&
cvCompareString(cv, StructuredName.PHONETIC_FAMILY_NAME, yomiLastName) &&
- //cvCompareString(cv, StructuredName.DISPLAY_NAME, fileAs) &&
cvCompareString(cv, StructuredName.SUFFIX, suffix)) {
return;
}
@@ -1229,7 +1301,6 @@
builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, yomiFirstName);
builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, yomiLastName);
builder.withValue(StructuredName.PREFIX, prefix);
- //builder.withValue(StructuredName.DISPLAY_NAME, fileAs);
add(builder.build());
}
@@ -1601,12 +1672,6 @@
sendStringData(s, cv, StructuredName.PHONETIC_GIVEN_NAME, Tags.CONTACTS_YOMI_FIRST_NAME);
sendStringData(s, cv, StructuredName.PHONETIC_FAMILY_NAME, Tags.CONTACTS_YOMI_LAST_NAME);
sendStringData(s, cv, StructuredName.PREFIX, Tags.CONTACTS_TITLE);
- if (cv.containsKey(StructuredName.DISPLAY_NAME)) {
- displayName = cv.getAsString(StructuredName.DISPLAY_NAME);
- if (!TextUtils.isEmpty(displayName)) {
- s.data(Tags.CONTACTS_FILE_AS, displayName);
- }
- }
return displayName;
}
diff --git a/exchange2/src/com/android/exchange/adapter/EmailSyncAdapter.java b/exchange2/src/com/android/exchange/adapter/EmailSyncAdapter.java
index 73199f8..b419f23 100644
--- a/exchange2/src/com/android/exchange/adapter/EmailSyncAdapter.java
+++ b/exchange2/src/com/android/exchange/adapter/EmailSyncAdapter.java
@@ -25,6 +25,9 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
+import android.provider.CalendarContract.Events;
+import android.text.Html;
+import android.text.SpannedString;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -52,6 +55,7 @@
import com.android.emailcommon.service.SyncWindow;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.emailcommon.utility.ConversionUtilities;
+import com.android.emailcommon.utility.TextUtilities;
import com.android.emailcommon.utility.Utility;
import com.android.exchange.CommandStatusException;
import com.android.exchange.Eas;
@@ -193,8 +197,9 @@
}
@Override
- public void sendSyncOptions(Double protocolVersion, Serializer s)
+ public void sendSyncOptions(Double protocolVersion, Serializer s, boolean initialSync)
throws IOException {
+ if (initialSync) return;
mFetchRequestList.clear();
// Find partially loaded messages; this should typically be a rare occurrence
Cursor c = mContext.getContentResolver().query(Message.CONTENT_URI,
@@ -606,6 +611,39 @@
if (atts.size() > 0) {
msg.mAttachments = atts;
}
+
+ if ((msg.mFlags & Message.FLAG_INCOMING_MEETING_MASK) != 0) {
+ String text = TextUtilities.makeSnippetFromHtmlText(
+ msg.mText != null ? msg.mText : msg.mHtml);
+ if (TextUtils.isEmpty(text)) {
+ // Create text for this invitation
+ String meetingInfo = msg.mMeetingInfo;
+ if (!TextUtils.isEmpty(meetingInfo)) {
+ PackedString ps = new PackedString(meetingInfo);
+ ContentValues values = new ContentValues();
+ putFromMeeting(ps, MeetingInfo.MEETING_LOCATION, values,
+ Events.EVENT_LOCATION);
+ String dtstart = ps.get(MeetingInfo.MEETING_DTSTART);
+ if (!TextUtils.isEmpty(dtstart)) {
+ long startTime = Utility.parseEmailDateTimeToMillis(dtstart);
+ values.put(Events.DTSTART, startTime);
+ }
+ putFromMeeting(ps, MeetingInfo.MEETING_ALL_DAY, values,
+ Events.ALL_DAY);
+ msg.mText = CalendarUtilities.buildMessageTextFromEntityValues(
+ mContext, values, null);
+ msg.mHtml = Html.toHtml(new SpannedString(msg.mText));
+ }
+ }
+ }
+ }
+
+ private void putFromMeeting(PackedString ps, String field, ContentValues values,
+ String column) {
+ String val = ps.get(field);
+ if (!TextUtils.isEmpty(val)) {
+ values.put(column, val);
+ }
}
/**
@@ -647,6 +685,11 @@
case Tags.EMAIL_RESPONSE_REQUESTED:
packedString.put(MeetingInfo.MEETING_RESPONSE_REQUESTED, getValue());
break;
+ case Tags.EMAIL_ALL_DAY_EVENT:
+ if (getValueInt() == 1) {
+ packedString.put(MeetingInfo.MEETING_ALL_DAY, getValue());
+ }
+ break;
default:
skipTag();
}
diff --git a/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java b/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
index 3b0bc7c..2c213a4 100644
--- a/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
+++ b/exchange2/src/com/android/exchange/adapter/FolderSyncParser.java
@@ -32,7 +32,6 @@
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.service.SyncWindow;
import com.android.emailcommon.utility.AttachmentUtilities;
-import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility;
import com.android.exchange.CommandStatusException;
import com.android.exchange.CommandStatusException.CommandStatus;
@@ -47,7 +46,6 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import java.util.concurrent.ExecutionException;
/**
* Parse the result of a FolderSync command
@@ -428,11 +426,14 @@
// Mailbox, so we'll have to query the database
if (parent == null) {
mBindArguments[0] = Long.toString(mAccount.mId);
- mBindArguments[1] = mailbox.mParentServerId;
- long parentId = Utility.getFirstRowInt(mContext, Mailbox.CONTENT_URI,
- EmailContent.ID_PROJECTION,
- MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.SERVER_ID + "=?",
- mBindArguments, null, EmailContent.ID_PROJECTION_COLUMN, -1);
+ long parentId = -1;
+ if (mailbox.mParentServerId != null) {
+ mBindArguments[1] = mailbox.mParentServerId;
+ parentId = Utility.getFirstRowInt(mContext, Mailbox.CONTENT_URI,
+ EmailContent.ID_PROJECTION,
+ MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.SERVER_ID + "=?",
+ mBindArguments, null, EmailContent.ID_PROJECTION_COLUMN, -1);
+ }
if (parentId != -1) {
// Get the parent from the database
parent = Mailbox.restoreMailboxWithId(mContext, parentId);
@@ -540,6 +541,7 @@
public void changesParser(final ArrayList<ContentProviderOperation> ops,
final boolean initialSync) throws IOException {
+
// Array of added mailboxes
final ArrayList<Mailbox> addMailboxes = new ArrayList<Mailbox>();
@@ -562,89 +564,77 @@
skipTag();
}
- EmailAsyncTask<?, ?, ?> task =
- EmailAsyncTask.runAsyncParallel(new Runnable() {
- @Override
- public void run() {
- // Synchronize on the parser to prevent this being run concurrently
- // (an extremely unlikely event, but nonetheless possible)
- synchronized (FolderSyncParser.this) {
- // Mailboxes that we known contain email
- ArrayList<Mailbox> validMailboxes = new ArrayList<Mailbox>();
- // Mailboxes that we're unsure about
- ArrayList<Mailbox> userMailboxes = new ArrayList<Mailbox>();
+ // Synchronize on the parser to prevent this being run concurrently
+ // (an extremely unlikely event, but nonetheless possible)
+ synchronized (FolderSyncParser.this) {
+ // Mailboxes that we known contain email
+ ArrayList<Mailbox> validMailboxes = new ArrayList<Mailbox>();
+ // Mailboxes that we're unsure about
+ ArrayList<Mailbox> userMailboxes = new ArrayList<Mailbox>();
- // Maps folder serverId to mailbox (used to validate user mailboxes)
- HashMap<String, Mailbox> mailboxMap = new HashMap<String, Mailbox>();
- for (Mailbox mailbox : addMailboxes) {
- mailboxMap.put(mailbox.mServerId, mailbox);
- }
-
- int mailboxCommitCount = 0;
- for (Mailbox mailbox : addMailboxes) {
- // And add the mailbox to the proper list
- if (type == USER_MAILBOX_TYPE) {
- userMailboxes.add(mailbox);
- } else {
- validMailboxes.add(mailbox);
- }
- // On initial sync, we commit what we have every 20 mailboxes
- if (initialSync && (++mailboxCommitCount == MAILBOX_COMMIT_SIZE)) {
- if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap,
- ops)) {
- mService.stop();
- return;
- }
- // Clear our arrays to prepare for more
- userMailboxes.clear();
- validMailboxes.clear();
- ops.clear();
- mailboxCommitCount = 0;
- }
- }
- // Commit the sync key and mailboxes
- ContentValues cv = new ContentValues();
- cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
- ops.add(ContentProviderOperation
- .newUpdate(
- ContentUris.withAppendedId(Account.CONTENT_URI,
- mAccount.mId))
- .withValues(cv).build());
- if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops)) {
- mService.stop();
- return;
- }
- String accountSelector = Mailbox.ACCOUNT_KEY + "=" + mAccount.mId;
- // For new boxes, setup the parent key and flags
- if (mFixupUninitializedNeeded) {
- MailboxUtilities.fixupUninitializedParentKeys(mContext,
- accountSelector);
- }
- // For modified parents, reset the flags (and children's parent key)
- for (String parentServerId: mParentFixupsNeeded) {
- Cursor c = mContentResolver.query(Mailbox.CONTENT_URI,
- Mailbox.CONTENT_PROJECTION, Mailbox.PARENT_SERVER_ID + "=?",
- new String[] {parentServerId}, null);
- try {
- if (c.moveToFirst()) {
- MailboxUtilities.setFlagsAndChildrensParentKey(mContext, c,
- accountSelector);
- }
- } finally {
- c.close();
- }
- }
-
- // Signal completion of mailbox changes
- MailboxUtilities.endMailboxChanges(mContext, mAccount.mId);
- }
- }});
- // Make this synchronous if in a unit test
- if (mInUnitTest) {
- try {
- task.get();
- } catch (Exception e) {
+ // Maps folder serverId to mailbox (used to validate user mailboxes)
+ HashMap<String, Mailbox> mailboxMap = new HashMap<String, Mailbox>();
+ for (Mailbox mailbox : addMailboxes) {
+ mailboxMap.put(mailbox.mServerId, mailbox);
}
+
+ int mailboxCommitCount = 0;
+ for (Mailbox mailbox : addMailboxes) {
+ // And add the mailbox to the proper list
+ if (mailbox.mType == Mailbox.TYPE_UNKNOWN) {
+ userMailboxes.add(mailbox);
+ } else {
+ validMailboxes.add(mailbox);
+ }
+ // On initial sync, we commit what we have every 20 mailboxes
+ if (initialSync && (++mailboxCommitCount == MAILBOX_COMMIT_SIZE)) {
+ if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap,
+ ops)) {
+ mService.stop();
+ return;
+ }
+ // Clear our arrays to prepare for more
+ userMailboxes.clear();
+ validMailboxes.clear();
+ ops.clear();
+ mailboxCommitCount = 0;
+ }
+ }
+ // Commit the sync key and mailboxes
+ ContentValues cv = new ContentValues();
+ cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
+ ops.add(ContentProviderOperation
+ .newUpdate(
+ ContentUris.withAppendedId(Account.CONTENT_URI,
+ mAccount.mId))
+ .withValues(cv).build());
+ if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops)) {
+ mService.stop();
+ return;
+ }
+ String accountSelector = Mailbox.ACCOUNT_KEY + "=" + mAccount.mId;
+ // For new boxes, setup the parent key and flags
+ if (mFixupUninitializedNeeded) {
+ MailboxUtilities.fixupUninitializedParentKeys(mContext,
+ accountSelector);
+ }
+ // For modified parents, reset the flags (and children's parent key)
+ for (String parentServerId: mParentFixupsNeeded) {
+ Cursor c = mContentResolver.query(Mailbox.CONTENT_URI,
+ Mailbox.CONTENT_PROJECTION, Mailbox.PARENT_SERVER_ID + "=?",
+ new String[] {parentServerId}, null);
+ try {
+ if (c.moveToFirst()) {
+ MailboxUtilities.setFlagsAndChildrensParentKey(mContext, c,
+ accountSelector);
+ }
+ } finally {
+ c.close();
+ }
+ }
+
+ // Signal completion of mailbox changes
+ MailboxUtilities.endMailboxChanges(mContext, mAccount.mId);
}
}
diff --git a/exchange2/src/com/android/exchange/utility/CalendarUtilities.java b/exchange2/src/com/android/exchange/utility/CalendarUtilities.java
index 2302b7a..792d065 100644
--- a/exchange2/src/com/android/exchange/utility/CalendarUtilities.java
+++ b/exchange2/src/com/android/exchange/utility/CalendarUtilities.java
@@ -903,6 +903,22 @@
}
/**
+ * Generate a birthday string from a GregorianCalendar set appropriately; the format of this
+ * string is YYYY-MM-DD
+ * @param cal the calendar
+ * @return the birthday string
+ */
+ static public String calendarToBirthdayString(GregorianCalendar cal) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cal.get(Calendar.YEAR));
+ sb.append('-');
+ sb.append(formatTwo(cal.get(Calendar.MONTH) + 1));
+ sb.append('-');
+ sb.append(formatTwo(cal.get(Calendar.DAY_OF_MONTH)));
+ return sb.toString();
+ }
+
+ /**
* Generate an EAS formatted local date/time string from a time and a time zone. If the final
* argument is false, only a date will be returned (e.g. 20100331)
* @param millis a time in milliseconds
@@ -1298,7 +1314,7 @@
if (dow == 127) {
rrule.append(";BYMONTHDAY=-1");
// week 5 and dow = weekdays -> last weekday (need BYSETPOS)
- } else if (wom == 5 && (dow == EAS_WEEKDAYS || dow == EAS_WEEKENDS)) {
+ } else if ((wom == 5 || wom == 1) && (dow == EAS_WEEKDAYS || dow == EAS_WEEKENDS)) {
addBySetpos(rrule, dow, wom);
} else if (dow > 0) addByDay(rrule, dow, wom);
break;