Implement basic EAS 12.1 functionality
* Support required protocol changes
* Handle new security policies based on current device capabilities
Change-Id: Id1d629d41d957911344e6c503d28418f5e7e1386
diff --git a/src/com/android/exchange/Eas.java b/src/com/android/exchange/Eas.java
index 8e561e7..2fa162b 100644
--- a/src/com/android/exchange/Eas.java
+++ b/src/com/android/exchange/Eas.java
@@ -45,6 +45,8 @@
public static final double SUPPORTED_PROTOCOL_EX2003_DOUBLE = 2.5;
public static final String SUPPORTED_PROTOCOL_EX2007 = "12.0";
public static final double SUPPORTED_PROTOCOL_EX2007_DOUBLE = 12.0;
+ public static final String SUPPORTED_PROTOCOL_EX2007_SP1 = "12.1";
+ public static final double SUPPORTED_PROTOCOL_EX2007_SP1_DOUBLE = 12.1;
public static final String DEFAULT_PROTOCOL_VERSION = SUPPORTED_PROTOCOL_EX2003;
// From EAS spec
diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java
index 82a375f..0f9639a 100644
--- a/src/com/android/exchange/EasSyncService.java
+++ b/src/com/android/exchange/EasSyncService.java
@@ -352,7 +352,8 @@
// Find the most recent version we support
for (String version: supportedVersionsArray) {
if (version.equals(Eas.SUPPORTED_PROTOCOL_EX2003) ||
- version.equals(Eas.SUPPORTED_PROTOCOL_EX2007)) {
+ version.equals(Eas.SUPPORTED_PROTOCOL_EX2007) ||
+ version.equals(Eas.SUPPORTED_PROTOCOL_EX2007_SP1)) {
ourVersion = version;
}
}
@@ -1979,9 +1980,12 @@
userLog("sync, sending ", className, " syncKey: ", syncKey);
s.start(Tags.SYNC_SYNC)
.start(Tags.SYNC_COLLECTIONS)
- .start(Tags.SYNC_COLLECTION)
- .data(Tags.SYNC_CLASS, className)
- .data(Tags.SYNC_SYNC_KEY, syncKey)
+ .start(Tags.SYNC_COLLECTION);
+ // The "Class" element is removed in EAS 12.1 and later versions
+ if (mProtocolVersionDouble < Eas.SUPPORTED_PROTOCOL_EX2007_SP1_DOUBLE) {
+ s.data(Tags.SYNC_CLASS, className);
+ }
+ s.data(Tags.SYNC_SYNC_KEY, syncKey)
.data(Tags.SYNC_COLLECTION_ID, mailbox.mServerId);
// Start with the default timeout
diff --git a/src/com/android/exchange/adapter/ProvisionParser.java b/src/com/android/exchange/adapter/ProvisionParser.java
index af1ecdd..5304639 100644
--- a/src/com/android/exchange/adapter/ProvisionParser.java
+++ b/src/com/android/exchange/adapter/ProvisionParser.java
@@ -56,7 +56,7 @@
return mRemoteWipe;
}
- public void parseProvisionDocWbxml() throws IOException {
+ private void parseProvisionDocWbxml() throws IOException {
int minPasswordLength = 0;
int passwordMode = PolicySet.PASSWORD_MODE_NONE;
int maxPasswordFails = 0;
@@ -64,6 +64,7 @@
boolean canSupport = true;
while (nextTag(Tags.PROVISION_EAS_PROVISION_DOC) != END) {
+ boolean supported = true;
switch (tag) {
case Tags.PROVISION_DEVICE_PASSWORD_ENABLED:
if (getValueInt() == 1) {
@@ -92,10 +93,28 @@
// Hint: I haven't seen any that's more specific than "simple"
getValue();
break;
- // The following policy, if false, can't be supported at the moment
+ // The following policies, if false, can't be supported at the moment
case Tags.PROVISION_ATTACHMENTS_ENABLED:
+ case Tags.PROVISION_ALLOW_STORAGE_CARD:
+ case Tags.PROVISION_ALLOW_CAMERA:
+ case Tags.PROVISION_ALLOW_UNSIGNED_APPLICATIONS:
+ case Tags.PROVISION_ALLOW_UNSIGNED_INSTALLATION_PACKAGES:
+ case Tags.PROVISION_ALLOW_WIFI:
+ case Tags.PROVISION_ALLOW_TEXT_MESSAGING:
+ case Tags.PROVISION_ALLOW_POP_IMAP_EMAIL:
+ case Tags.PROVISION_ALLOW_IRDA:
+ case Tags.PROVISION_ALLOW_HTML_EMAIL:
+ case Tags.PROVISION_ALLOW_BROWSER:
+ case Tags.PROVISION_ALLOW_CONSUMER_EMAIL:
+ case Tags.PROVISION_ALLOW_INTERNET_SHARING:
if (getValueInt() == 0) {
- canSupport = false;
+ supported = false;
+ }
+ break;
+ // Bluetooth: 0 = no bluetooth; 1 = only hands-free; 2 = allowed
+ case Tags.PROVISION_ALLOW_BLUETOOTH:
+ if (getValueInt() != 2) {
+ supported = false;
}
break;
// The following policies, if true, can't be supported at the moment
@@ -103,14 +122,68 @@
case Tags.PROVISION_PASSWORD_RECOVERY_ENABLED:
case Tags.PROVISION_DEVICE_PASSWORD_EXPIRATION:
case Tags.PROVISION_DEVICE_PASSWORD_HISTORY:
- case Tags.PROVISION_MAX_ATTACHMENT_SIZE:
+ case Tags.PROVISION_REQUIRE_DEVICE_ENCRYPTION:
+ case Tags.PROVISION_REQUIRE_SIGNED_SMIME_MESSAGES:
+ case Tags.PROVISION_REQUIRE_ENCRYPTED_SMIME_MESSAGES:
+ case Tags.PROVISION_REQUIRE_SIGNED_SMIME_ALGORITHM:
+ case Tags.PROVISION_REQUIRE_ENCRYPTION_SMIME_ALGORITHM:
+ case Tags.PROVISION_REQUIRE_MANUAL_SYNC_WHEN_ROAMING:
if (getValueInt() == 1) {
- canSupport = false;
+ supported = false;
+ }
+ break;
+ // The following, if greater than zero, can't be supported at the moment
+ case Tags.PROVISION_MAX_ATTACHMENT_SIZE:
+ if (getValueInt() > 0) {
+ supported = false;
+ }
+ break;
+ // Complex character setting is only used if we're in "strong" (alphanumeric) mode
+ case Tags.PROVISION_MIN_DEVICE_PASSWORD_COMPLEX_CHARS:
+ if ((passwordMode == PolicySet.PASSWORD_MODE_STRONG) && (getValueInt() > 0)) {
+ supported = false;
+ }
+ break;
+ // The following policies are moot; they allow functionality that we don't support
+ case Tags.PROVISION_ALLOW_DESKTOP_SYNC:
+ case Tags.PROVISION_ALLOW_SMIME_ENCRYPTION_NEGOTIATION:
+ case Tags.PROVISION_ALLOW_SMIME_SOFT_CERTS:
+ case Tags.PROVISION_ALLOW_REMOTE_DESKTOP:
+ skipTag();
+ break;
+ // We don't handle approved/unapproved application lists
+ case Tags.PROVISION_UNAPPROVED_IN_ROM_APPLICATION_LIST:
+ case Tags.PROVISION_APPROVED_APPLICATION_LIST:
+ // Parse and throw away the content
+ if (specifiesApplications(tag)) {
+ supported = false;
+ }
+ break;
+ // NOTE: We can support these entirely within the email application if we choose
+ case Tags.PROVISION_MAX_CALENDAR_AGE_FILTER:
+ case Tags.PROVISION_MAX_EMAIL_AGE_FILTER:
+ // 0 indicates no specified filter
+ if (getValueInt() != 0) {
+ supported = false;
+ }
+ break;
+ // NOTE: We can support these entirely within the email application if we choose
+ case Tags.PROVISION_MAX_EMAIL_BODY_TRUNCATION_SIZE:
+ case Tags.PROVISION_MAX_EMAIL_HTML_BODY_TRUNCATION_SIZE:
+ String value = getValue();
+ // -1 indicates no required truncation
+ if (!value.equals("-1")) {
+ supported = false;
}
break;
default:
skipTag();
}
+
+ if (!supported) {
+ log("** Policy not supported");
+ canSupport = false;
+ }
}
if (canSupport) {
@@ -119,6 +192,27 @@
}
}
+ /**
+ * Return whether or not either of the application list tags specifies any applications
+ * @param endTag the tag whose children we're walking through
+ * @return whether any applications were specified (by name or by hash)
+ * @throws IOException
+ */
+ private boolean specifiesApplications(int endTag) throws IOException {
+ boolean specifiesApplications = false;
+ while (nextTag(endTag) != END) {
+ switch (tag) {
+ case Tags.PROVISION_APPLICATION_NAME:
+ case Tags.PROVISION_HASH:
+ specifiesApplications = true;
+ break;
+ default:
+ skipTag();
+ }
+ }
+ return specifiesApplications;
+ }
+
class ShadowPolicySet {
int mMinPasswordLength = 0;
int mPasswordMode = PolicySet.PASSWORD_MODE_NONE;
@@ -126,7 +220,7 @@
int mMaxScreenLockTime = 0;
}
- public void parseProvisionDocXml(String doc) throws IOException {
+ /*package*/ void parseProvisionDocXml(String doc) throws IOException {
ShadowPolicySet sps = new ShadowPolicySet();
try {
@@ -154,7 +248,7 @@
/**
* Return true if password is required; otherwise false.
*/
- boolean parseSecurityPolicy(XmlPullParser parser, ShadowPolicySet sps)
+ private boolean parseSecurityPolicy(XmlPullParser parser, ShadowPolicySet sps)
throws XmlPullParserException, IOException {
boolean passwordRequired = true;
while (true) {
@@ -177,7 +271,7 @@
return passwordRequired;
}
- void parseCharacteristic(XmlPullParser parser, ShadowPolicySet sps)
+ private void parseCharacteristic(XmlPullParser parser, ShadowPolicySet sps)
throws XmlPullParserException, IOException {
boolean enforceInactivityTimer = true;
while (true) {
@@ -219,7 +313,7 @@
}
}
- void parseRegistry(XmlPullParser parser, ShadowPolicySet sps)
+ private void parseRegistry(XmlPullParser parser, ShadowPolicySet sps)
throws XmlPullParserException, IOException {
while (true) {
int type = parser.nextTag();
@@ -234,7 +328,7 @@
}
}
- void parseWapProvisioningDoc(XmlPullParser parser, ShadowPolicySet sps)
+ private void parseWapProvisioningDoc(XmlPullParser parser, ShadowPolicySet sps)
throws XmlPullParserException, IOException {
while (true) {
int type = parser.nextTag();
@@ -258,7 +352,7 @@
}
}
- public void parseProvisionData() throws IOException {
+ private void parseProvisionData() throws IOException {
while (nextTag(Tags.PROVISION_DATA) != END) {
if (tag == Tags.PROVISION_EAS_PROVISION_DOC) {
parseProvisionDocWbxml();
@@ -268,7 +362,7 @@
}
}
- public void parsePolicy() throws IOException {
+ private void parsePolicy() throws IOException {
String policyType = null;
while (nextTag(Tags.PROVISION_POLICY) != END) {
switch (tag) {
@@ -297,7 +391,7 @@
}
}
- public void parsePolicies() throws IOException {
+ private void parsePolicies() throws IOException {
while (nextTag(Tags.PROVISION_POLICIES) != END) {
if (tag == Tags.PROVISION_POLICY) {
parsePolicy();
diff --git a/src/com/android/exchange/adapter/Tags.java b/src/com/android/exchange/adapter/Tags.java
index ef70981..2745e33 100644
--- a/src/com/android/exchange/adapter/Tags.java
+++ b/src/com/android/exchange/adapter/Tags.java
@@ -596,7 +596,7 @@
"MinDevicePasswordComplexCharacters", "AllowWiFi", "AllowTextMessaging",
"AllowPOPIMAPEmail", "AllowBluetooth", "AllowIrDA", "RequireManualSyncWhenRoaming",
"AllowDesktopSync",
- "MaxCalendarAgeFilder", "AllowHTMLEmail", "MaxEmailAgeFilder",
+ "MaxCalendarAgeFilder", "AllowHTMLEmail", "MaxEmailAgeFilter",
"MaxEmailBodyTruncationSize", "MaxEmailHTMLBodyTruncationSize",
"RequireSignedSMIMEMessages", "RequireEncryptedSMIMEMessages",
"RequireSignedSMIMEAlgorithm", "RequireEncryptionSMIMEAlgorithm",