diff --git a/Android.mk b/Android.mk
index 960ed4315..451c39b75 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,7 +20,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += \
src/com/android/emailcommon/service/IEmailService.aidl \
- src/com/android/emailcommon/service/IEmailServiceCallback.aidl
+ src/com/android/emailcommon/service/IEmailServiceCallback.aidl \
+ src/com/android/emailcommon/service/IPolicyService.aidl
LOCAL_STATIC_JAVA_LIBRARIES := android-common
# Revive this when the app is unbundled.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cf8306b7c..f8b4b56f8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -358,6 +358,18 @@
android:resource="@xml/syncadapter_pop_imap" />
+
+
+
+
+
+
+
wipe device (0=disabled)
- private static final int PASSWORD_MAX_FAILS_SHIFT = 9;
- private static final int PASSWORD_MAX_FAILS_MASK = 31 << PASSWORD_MAX_FAILS_SHIFT;
- public static final int PASSWORD_MAX_FAILS_MAX = 31;
- // bits 14..24: seconds to screen lock (0=not required)
- private static final int SCREEN_LOCK_TIME_SHIFT = 14;
- private static final int SCREEN_LOCK_TIME_MASK = 2047 << SCREEN_LOCK_TIME_SHIFT;
- public static final int SCREEN_LOCK_TIME_MAX = 2047;
- // bit 25: remote wipe capability required
- private static final int REQUIRE_REMOTE_WIPE = 1 << 25;
- // bit 26..35: password expiration (days; 0=not required)
- private static final int PASSWORD_EXPIRATION_SHIFT = 26;
- private static final long PASSWORD_EXPIRATION_MASK = 1023L << PASSWORD_EXPIRATION_SHIFT;
- public static final int PASSWORD_EXPIRATION_MAX = 1023;
- // bit 36..43: password history (length; 0=not required)
- private static final int PASSWORD_HISTORY_SHIFT = 36;
- private static final long PASSWORD_HISTORY_MASK = 255L << PASSWORD_HISTORY_SHIFT;
- public static final int PASSWORD_HISTORY_MAX = 255;
- // bit 44..48: min complex characters (0=not required)
- private static final int PASSWORD_COMPLEX_CHARS_SHIFT = 44;
- private static final long PASSWORD_COMPLEX_CHARS_MASK = 31L << PASSWORD_COMPLEX_CHARS_SHIFT;
- public static final int PASSWORD_COMPLEX_CHARS_MAX = 31;
- // bit 49: requires device encryption
- private static final long REQUIRE_ENCRYPTION = 1L << 49;
-
- /* Convert days to mSec (used for password expiration) */
- private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000;
- /* Small offset (2 minutes) added to policy expiration to make user testing easier. */
- private static final long EXPIRATION_OFFSET_MSEC = 2 * 60 * 1000;
-
- /*package*/ final int mMinPasswordLength;
- /*package*/ final int mPasswordMode;
- /*package*/ final int mMaxPasswordFails;
- /*package*/ final int mMaxScreenLockTime;
- /*package*/ final boolean mRequireRemoteWipe;
- /*package*/ final int mPasswordExpirationDays;
- /*package*/ final int mPasswordHistory;
- /*package*/ final int mPasswordComplexChars;
- /*package*/ final boolean mRequireEncryption;
-
- public int getMinPasswordLengthForTest() {
- return mMinPasswordLength;
- }
-
- public int getPasswordModeForTest() {
- return mPasswordMode;
- }
-
- public int getMaxPasswordFailsForTest() {
- return mMaxPasswordFails;
- }
-
- public int getMaxScreenLockTimeForTest() {
- return mMaxScreenLockTime;
- }
-
- public boolean isRequireRemoteWipeForTest() {
- return mRequireRemoteWipe;
- }
-
- public boolean isRequireEncryptionForTest() {
- return mRequireEncryption;
- }
-
- /**
- * Create from raw values.
- * @param minPasswordLength (0=not enforced)
- * @param passwordMode
- * @param maxPasswordFails (0=not enforced)
- * @param maxScreenLockTime in seconds (0=not enforced)
- * @param requireRemoteWipe
- * @param passwordExpirationDays in days (0=not enforced)
- * @param passwordHistory (0=not enforced)
- * @param passwordComplexChars (0=not enforced)
- * @throws IllegalArgumentException for illegal arguments.
- */
- public PolicySet(int minPasswordLength, int passwordMode, int maxPasswordFails,
- int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays,
- int passwordHistory, int passwordComplexChars, boolean requireEncryption)
- throws IllegalArgumentException {
- // If we're not enforcing passwords, make sure we clean up related values, since EAS
- // can send non-zero values for any or all of these
- if (passwordMode == PASSWORD_MODE_NONE) {
- maxPasswordFails = 0;
- maxScreenLockTime = 0;
- minPasswordLength = 0;
- passwordComplexChars = 0;
- passwordHistory = 0;
- passwordExpirationDays = 0;
- } else {
- if ((passwordMode != PASSWORD_MODE_SIMPLE) &&
- (passwordMode != PASSWORD_MODE_STRONG)) {
- throw new IllegalArgumentException("password mode");
- }
- // If we're only requiring a simple password, set complex chars to zero; note
- // that EAS can erroneously send non-zero values in this case
- if (passwordMode == PASSWORD_MODE_SIMPLE) {
- passwordComplexChars = 0;
- }
- // The next four values have hard limits which cannot be supported if exceeded.
- if (minPasswordLength > PASSWORD_LENGTH_MAX) {
- throw new IllegalArgumentException("password length");
- }
- if (passwordExpirationDays > PASSWORD_EXPIRATION_MAX) {
- throw new IllegalArgumentException("password expiration");
- }
- if (passwordHistory > PASSWORD_HISTORY_MAX) {
- throw new IllegalArgumentException("password history");
- }
- if (passwordComplexChars > PASSWORD_COMPLEX_CHARS_MAX) {
- throw new IllegalArgumentException("complex chars");
- }
- // This value can be reduced (which actually increases security) if necessary
- if (maxPasswordFails > PASSWORD_MAX_FAILS_MAX) {
- maxPasswordFails = PASSWORD_MAX_FAILS_MAX;
- }
- // This value can be reduced (which actually increases security) if necessary
- if (maxScreenLockTime > SCREEN_LOCK_TIME_MAX) {
- maxScreenLockTime = SCREEN_LOCK_TIME_MAX;
- }
- }
- mMinPasswordLength = minPasswordLength;
- mPasswordMode = passwordMode;
- mMaxPasswordFails = maxPasswordFails;
- mMaxScreenLockTime = maxScreenLockTime;
- mRequireRemoteWipe = requireRemoteWipe;
- mPasswordExpirationDays = passwordExpirationDays;
- mPasswordHistory = passwordHistory;
- mPasswordComplexChars = passwordComplexChars;
- mRequireEncryption = requireEncryption;
- }
-
- /**
- * Create from values encoded in an account
- * @param account
- */
- public PolicySet(Account account) {
- this(account.mSecurityFlags);
- }
-
- /**
- * Create from values encoded in an account flags int
- */
- public PolicySet(long flags) {
- mMinPasswordLength =
- (int) ((flags & PASSWORD_LENGTH_MASK) >> PASSWORD_LENGTH_SHIFT);
- mPasswordMode =
- (int) (flags & PASSWORD_MODE_MASK);
- mMaxPasswordFails =
- (int) ((flags & PASSWORD_MAX_FAILS_MASK) >> PASSWORD_MAX_FAILS_SHIFT);
- mMaxScreenLockTime =
- (int) ((flags & SCREEN_LOCK_TIME_MASK) >> SCREEN_LOCK_TIME_SHIFT);
- mRequireRemoteWipe = 0 != (flags & REQUIRE_REMOTE_WIPE);
- mPasswordExpirationDays =
- (int) ((flags & PASSWORD_EXPIRATION_MASK) >> PASSWORD_EXPIRATION_SHIFT);
- mPasswordHistory =
- (int) ((flags & PASSWORD_HISTORY_MASK) >> PASSWORD_HISTORY_SHIFT);
- mPasswordComplexChars =
- (int) ((flags & PASSWORD_COMPLEX_CHARS_MASK) >> PASSWORD_COMPLEX_CHARS_SHIFT);
- mRequireEncryption = 0 != (flags & REQUIRE_ENCRYPTION);
- }
-
- /**
- * Helper to map our internal encoding to DevicePolicyManager password modes.
- */
- public int getDPManagerPasswordQuality() {
- switch (mPasswordMode) {
- case PASSWORD_MODE_SIMPLE:
- return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
- case PASSWORD_MODE_STRONG:
- return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
- default:
- return DevicePolicyManager .PASSWORD_QUALITY_UNSPECIFIED;
- }
- }
-
- /**
- * Helper to map expiration times to the millisecond values used by DevicePolicyManager.
- */
- public long getDPManagerPasswordExpirationTimeout() {
- long result = mPasswordExpirationDays * DAYS_TO_MSEC;
- // Add a small offset to the password expiration. This makes it easier to test
- // by changing (for example) 1 day to 1 day + 5 minutes. If you set an expiration
- // that is within the warning period, you should get a warning fairly quickly.
- if (result > 0) {
- result += EXPIRATION_OFFSET_MSEC;
- }
- return result;
- }
-
- /**
- * Record flags (and a sync key for the flags) into an Account
- * Note: the hash code is defined as the encoding used in Account
- *
- * @param account to write the values mSecurityFlags and mSecuritySyncKey
- * @param syncKey the value to write into the account's mSecuritySyncKey
- * @param update if true, also writes the account back to the provider (updating only
- * the fields changed by this API)
- * @param context a context for writing to the provider
- * @return true if the actual policies changed, false if no change (note, sync key
- * does not affect this)
- */
- public boolean writeAccount(Account account, String syncKey, boolean update,
- Context context) {
- long newFlags = getSecurityCode();
- boolean dirty = (newFlags != account.mSecurityFlags);
- account.mSecurityFlags = newFlags;
- account.mSecuritySyncKey = syncKey;
- if (update) {
- if (account.isSaved()) {
- ContentValues cv = new ContentValues();
- cv.put(AccountColumns.SECURITY_FLAGS, account.mSecurityFlags);
- cv.put(AccountColumns.SECURITY_SYNC_KEY, account.mSecuritySyncKey);
- account.update(context, cv);
- } else {
- account.save(context);
- }
- }
- return dirty;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof PolicySet) {
- PolicySet other = (PolicySet)o;
- return (this.getSecurityCode() == other.getSecurityCode());
- }
- return false;
- }
-
- /**
- * Supports Parcelable
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * Supports Parcelable
- */
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator() {
- public PolicySet createFromParcel(Parcel in) {
- return new PolicySet(in);
- }
-
- public PolicySet[] newArray(int size) {
- return new PolicySet[size];
- }
- };
-
- /**
- * Supports Parcelable
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mMinPasswordLength);
- dest.writeInt(mPasswordMode);
- dest.writeInt(mMaxPasswordFails);
- dest.writeInt(mMaxScreenLockTime);
- dest.writeInt(mRequireRemoteWipe ? 1 : 0);
- dest.writeInt(mPasswordExpirationDays);
- dest.writeInt(mPasswordHistory);
- dest.writeInt(mPasswordComplexChars);
- dest.writeInt(mRequireEncryption ? 1 : 0);
- }
-
- /**
- * Supports Parcelable
- */
- public PolicySet(Parcel in) {
- mMinPasswordLength = in.readInt();
- mPasswordMode = in.readInt();
- mMaxPasswordFails = in.readInt();
- mMaxScreenLockTime = in.readInt();
- mRequireRemoteWipe = in.readInt() == 1;
- mPasswordExpirationDays = in.readInt();
- mPasswordHistory = in.readInt();
- mPasswordComplexChars = in.readInt();
- mRequireEncryption = in.readInt() == 1;
- }
-
- @Override
- public int hashCode() {
- long code = getSecurityCode();
- return (int) code;
- }
-
- public long getSecurityCode() {
- long flags = 0;
- flags = (long)mMinPasswordLength << PASSWORD_LENGTH_SHIFT;
- flags |= mPasswordMode;
- flags |= (long)mMaxPasswordFails << PASSWORD_MAX_FAILS_SHIFT;
- flags |= (long)mMaxScreenLockTime << SCREEN_LOCK_TIME_SHIFT;
- if (mRequireRemoteWipe) flags |= REQUIRE_REMOTE_WIPE;
- flags |= (long)mPasswordHistory << PASSWORD_HISTORY_SHIFT;
- flags |= (long)mPasswordExpirationDays << PASSWORD_EXPIRATION_SHIFT;
- flags |= (long)mPasswordComplexChars << PASSWORD_COMPLEX_CHARS_SHIFT;
- if (mRequireEncryption) flags |= REQUIRE_ENCRYPTION;
- return flags;
- }
-
- @Override
- public String toString() {
- return "{ " + "pw-len-min=" + mMinPasswordLength + " pw-mode=" + mPasswordMode
- + " pw-fails-max=" + mMaxPasswordFails + " screenlock-max="
- + mMaxScreenLockTime + " remote-wipe-req=" + mRequireRemoteWipe
- + " pw-expiration=" + mPasswordExpirationDays
- + " pw-history=" + mPasswordHistory
- + " pw-complex-chars=" + mPasswordComplexChars
- + " require-encryption=" + mRequireEncryption + "}";
- }
- }
-
/**
* If we are not the active device admin, try to become so.
*
diff --git a/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java b/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java
index 6f5a47c36..84d115a10 100644
--- a/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java
+++ b/src/com/android/email/activity/setup/AccountCheckSettingsFragment.java
@@ -19,13 +19,13 @@ package com.android.email.activity.setup;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
-import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.mail.MessagingException;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.HostAuth;
import com.android.emailcommon.service.EmailServiceProxy;
+import com.android.emailcommon.service.PolicySet;
import android.app.Activity;
import android.app.AlertDialog;
diff --git a/src/com/android/email/activity/setup/AccountSetupOptions.java b/src/com/android/email/activity/setup/AccountSetupOptions.java
index 95b4fcb3a..f07d62263 100644
--- a/src/com/android/email/activity/setup/AccountSetupOptions.java
+++ b/src/com/android/email/activity/setup/AccountSetupOptions.java
@@ -19,13 +19,13 @@ package com.android.email.activity.setup;
import com.android.email.Email;
import com.android.email.ExchangeUtils;
import com.android.email.R;
-import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.Utility;
import com.android.email.activity.ActivityHelper;
import com.android.email.mail.Store;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
import com.android.email.service.MailService;
+import com.android.emailcommon.service.PolicySet;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
diff --git a/src/com/android/email/activity/setup/SetupData.java b/src/com/android/email/activity/setup/SetupData.java
index a3abfd245..4255126f7 100644
--- a/src/com/android/email/activity/setup/SetupData.java
+++ b/src/com/android/email/activity/setup/SetupData.java
@@ -16,8 +16,8 @@
package com.android.email.activity.setup;
-import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.provider.EmailContent.Account;
+import com.android.emailcommon.service.PolicySet;
import android.accounts.AccountAuthenticatorResponse;
import android.os.Bundle;
diff --git a/src/com/android/email/service/PolicyService.java b/src/com/android/email/service/PolicyService.java
new file mode 100644
index 000000000..ace65a716
--- /dev/null
+++ b/src/com/android/email/service/PolicyService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 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 com.android.email.SecurityPolicy;
+import com.android.emailcommon.service.IPolicyService;
+import com.android.emailcommon.service.PolicySet;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class PolicyService extends Service {
+
+ private SecurityPolicy mSecurityPolicy;
+ private Context mContext;
+
+ private final IPolicyService.Stub mBinder = new IPolicyService.Stub() {
+ public boolean isActive(PolicySet policies) {
+ return mSecurityPolicy.isActive(policies);
+ }
+
+ public void policiesRequired(long accountId) {
+ mSecurityPolicy.policiesRequired(accountId);
+ }
+
+ public void updatePolicies(long accountId) {
+ mSecurityPolicy.updatePolicies(accountId);
+ }
+
+ public void setAccountHoldFlag(long accountId, boolean newState) {
+ SecurityPolicy.setAccountHoldFlag(mContext, accountId, newState);
+ }
+
+ public boolean isActiveAdmin() {
+ return mSecurityPolicy.isActiveAdmin();
+ }
+
+ public void remoteWipe() {
+ mSecurityPolicy.remoteWipe();
+ }
+
+ public boolean isSupported(PolicySet policies) {
+ return mSecurityPolicy.isSupported(policies);
+ }
+
+ public PolicySet clearUnsupportedPolicies(PolicySet policies) {
+ return mSecurityPolicy.clearUnsupportedPolicies(policies);
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // When we bind this service, save the context and SecurityPolicy singleton
+ mContext = this;
+ mSecurityPolicy = SecurityPolicy.getInstance(this);
+ return mBinder;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/emailcommon/service/IPolicyService.aidl b/src/com/android/emailcommon/service/IPolicyService.aidl
new file mode 100644
index 000000000..646abf353
--- /dev/null
+++ b/src/com/android/emailcommon/service/IPolicyService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.emailcommon.service;
+
+import com.android.emailcommon.service.PolicySet;
+
+interface IPolicyService {
+ boolean isActive(in PolicySet policies);
+ void policiesRequired(long accountId);
+ void updatePolicies(long accountId);
+ void setAccountHoldFlag(long accountId, boolean newState);
+ boolean isActiveAdmin();
+ // This is about as oneway as you can get
+ oneway void remoteWipe();
+ boolean isSupported(in PolicySet policies);
+ PolicySet clearUnsupportedPolicies(in PolicySet policies);
+}
\ No newline at end of file
diff --git a/src/com/android/emailcommon/service/PolicyServiceProxy.java b/src/com/android/emailcommon/service/PolicyServiceProxy.java
new file mode 100644
index 000000000..463d11dc6
--- /dev/null
+++ b/src/com/android/emailcommon/service/PolicyServiceProxy.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2011 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.emailcommon.service;
+
+import com.android.email.provider.EmailContent.Account;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class PolicyServiceProxy extends ServiceProxy implements IPolicyService {
+ private static final boolean DEBUG_PROXY = true; // STOPSHIP DO NOT CHECK THIS IN SET TO TRUE
+ private static final String TAG = "PolicyServiceProxy";
+
+ // The intent used by sync adapter services to connect to the PolicyService
+ public static final String POLICY_INTENT = "com.android.email.POLICY_INTENT";
+
+ private IPolicyService mService = null;
+ private Object mReturn = null;
+
+ public PolicyServiceProxy(Context _context) {
+ super(_context, new Intent(POLICY_INTENT));
+ }
+
+ @Override
+ public void onConnected(IBinder binder) {
+ mService = IPolicyService.Stub.asInterface(binder);
+ }
+
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public PolicySet clearUnsupportedPolicies(final PolicySet arg0) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mReturn = mService.clearUnsupportedPolicies(arg0);
+ }
+ }, "clearUnsupportedPolicies");
+ waitForCompletion();
+ if (DEBUG_PROXY) {
+ Log.v(TAG, "clearUnsupportedPolicies: " + ((mReturn == null) ? "null" : mReturn));
+ }
+ if (mReturn == null) {
+ // Can this happen?
+ return null;
+ } else {
+ return (PolicySet)mReturn;
+ }
+ }
+
+ @Override
+ public boolean isActive(final PolicySet arg0) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mReturn = mService.isActive(arg0);
+ }
+ }, "isActive");
+ waitForCompletion();
+ if (DEBUG_PROXY) {
+ Log.v(TAG, "isActive: " + ((mReturn == null) ? "null" : mReturn));
+ }
+ if (mReturn == null) {
+ // Can this happen?
+ return false;
+ } else {
+ return (Boolean)mReturn;
+ }
+ }
+
+ @Override
+ public boolean isActiveAdmin() throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mReturn = mService.isActiveAdmin();
+ }
+ }, "isActiveAdmin");
+ waitForCompletion();
+ if (DEBUG_PROXY) {
+ Log.v(TAG, "isActiveAdmin: " + ((mReturn == null) ? "null" : mReturn));
+ }
+ if (mReturn == null) {
+ // Can this happen?
+ return false;
+ } else {
+ return (Boolean)mReturn;
+ }
+ }
+
+ @Override
+ public boolean isSupported(final PolicySet arg0) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mReturn = mService.isSupported(arg0);
+ }
+ }, "isSupported");
+ waitForCompletion();
+ if (DEBUG_PROXY) {
+ Log.v(TAG, "isSupported: " + ((mReturn == null) ? "null" : mReturn));
+ }
+ if (mReturn == null) {
+ // Can this happen?
+ return false;
+ } else {
+ return (Boolean)mReturn;
+ }
+ }
+
+ @Override
+ public void policiesRequired(final long arg0) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mService.policiesRequired(arg0);
+ }
+ }, "policiesRequired");
+ }
+
+ @Override
+ public void remoteWipe() throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mService.remoteWipe();
+ }
+ }, "remoteWipe");
+ }
+
+ @Override
+ public void setAccountHoldFlag(final long arg0, final boolean arg1) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mService.setAccountHoldFlag(arg0, arg1);
+ }
+ }, "setAccountHoldFlag");
+ }
+
+ @Override
+ public void updatePolicies(final long arg0) throws RemoteException {
+ setTask(new ProxyTask() {
+ public void run() throws RemoteException {
+ mService.updatePolicies(arg0);
+ }
+ }, "updatePolicies");
+ }
+
+ // Static methods that encapsulate the proxy calls above
+ public static boolean isActive(Context context, PolicySet policies) {
+ try {
+ return new PolicyServiceProxy(context).isActive(policies);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ public static void policiesRequired(Context context, long accountId) {
+ try {
+ new PolicyServiceProxy(context).policiesRequired(accountId);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("PolicyService transaction failed");
+ }
+ }
+
+ public static void updatePolicies(Context context, long accountId) {
+ try {
+ new PolicyServiceProxy(context).updatePolicies(accountId);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("PolicyService transaction failed");
+ }
+ }
+
+ public static void setAccountHoldFlag(Context context, Account account, boolean newState) {
+ try {
+ new PolicyServiceProxy(context).setAccountHoldFlag(account.mId, newState);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("PolicyService transaction failed");
+ }
+ }
+
+ public static boolean isActiveAdmin(Context context) {
+ try {
+ return new PolicyServiceProxy(context).isActiveAdmin();
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ public static void remoteWipe(Context context) {
+ try {
+ new PolicyServiceProxy(context).remoteWipe();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("PolicyService transaction failed");
+ }
+ }
+
+ public static boolean isSupported(Context context, PolicySet policies) {
+ try {
+ return new PolicyServiceProxy(context).isSupported(policies);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ public static PolicySet clearUnsupportedPolicies(Context context, PolicySet policies) {
+ try {
+ return new PolicyServiceProxy(context).clearUnsupportedPolicies(policies);
+ } catch (RemoteException e) {
+ }
+ throw new IllegalStateException("PolicyService transaction failed");
+ }
+
+}
+
diff --git a/src/com/android/emailcommon/service/PolicySet.aidl b/src/com/android/emailcommon/service/PolicySet.aidl
new file mode 100644
index 000000000..e825c62c3
--- /dev/null
+++ b/src/com/android/emailcommon/service/PolicySet.aidl
@@ -0,0 +1,19 @@
+/* Copyright (C) 2011 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.emailcommon.service;
+
+parcelable PolicySet;
+
diff --git a/src/com/android/emailcommon/service/PolicySet.java b/src/com/android/emailcommon/service/PolicySet.java
new file mode 100644
index 000000000..3e93bedf2
--- /dev/null
+++ b/src/com/android/emailcommon/service/PolicySet.java
@@ -0,0 +1,356 @@
+/* Copyright (C) 2011 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.emailcommon.service;
+
+import com.android.email.provider.EmailContent.Account;
+import com.android.email.provider.EmailContent.AccountColumns;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ContentValues;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+/**
+ * Class for tracking policies and reading/writing into accounts
+ */
+public class PolicySet implements Parcelable {
+
+ // Security (provisioning) flags
+ // bits 0..4: password length (0=no password required)
+ private static final int PASSWORD_LENGTH_MASK = 31;
+ private static final int PASSWORD_LENGTH_SHIFT = 0;
+ public static final int PASSWORD_LENGTH_MAX = 30;
+ // bits 5..8: password mode
+ private static final int PASSWORD_MODE_SHIFT = 5;
+ private static final int PASSWORD_MODE_MASK = 15 << PASSWORD_MODE_SHIFT;
+ public static final int PASSWORD_MODE_NONE = 0 << PASSWORD_MODE_SHIFT;
+ public static final int PASSWORD_MODE_SIMPLE = 1 << PASSWORD_MODE_SHIFT;
+ public static final int PASSWORD_MODE_STRONG = 2 << PASSWORD_MODE_SHIFT;
+ // bits 9..13: password failures -> wipe device (0=disabled)
+ private static final int PASSWORD_MAX_FAILS_SHIFT = 9;
+ private static final int PASSWORD_MAX_FAILS_MASK = 31 << PASSWORD_MAX_FAILS_SHIFT;
+ public static final int PASSWORD_MAX_FAILS_MAX = 31;
+ // bits 14..24: seconds to screen lock (0=not required)
+ private static final int SCREEN_LOCK_TIME_SHIFT = 14;
+ private static final int SCREEN_LOCK_TIME_MASK = 2047 << SCREEN_LOCK_TIME_SHIFT;
+ public static final int SCREEN_LOCK_TIME_MAX = 2047;
+ // bit 25: remote wipe capability required
+ private static final int REQUIRE_REMOTE_WIPE = 1 << 25;
+ // bit 26..35: password expiration (days; 0=not required)
+ private static final int PASSWORD_EXPIRATION_SHIFT = 26;
+ private static final long PASSWORD_EXPIRATION_MASK = 1023L << PASSWORD_EXPIRATION_SHIFT;
+ public static final int PASSWORD_EXPIRATION_MAX = 1023;
+ // bit 36..43: password history (length; 0=not required)
+ private static final int PASSWORD_HISTORY_SHIFT = 36;
+ private static final long PASSWORD_HISTORY_MASK = 255L << PASSWORD_HISTORY_SHIFT;
+ public static final int PASSWORD_HISTORY_MAX = 255;
+ // bit 44..48: min complex characters (0=not required)
+ private static final int PASSWORD_COMPLEX_CHARS_SHIFT = 44;
+ private static final long PASSWORD_COMPLEX_CHARS_MASK = 31L << PASSWORD_COMPLEX_CHARS_SHIFT;
+ public static final int PASSWORD_COMPLEX_CHARS_MAX = 31;
+ // bit 49: requires device encryption
+ private static final long REQUIRE_ENCRYPTION = 1L << 49;
+
+ /* Convert days to mSec (used for password expiration) */
+ private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000;
+ /* Small offset (2 minutes) added to policy expiration to make user testing easier. */
+ private static final long EXPIRATION_OFFSET_MSEC = 2 * 60 * 1000;
+
+ public final int mMinPasswordLength;
+ public final int mPasswordMode;
+ public final int mMaxPasswordFails;
+ public final int mMaxScreenLockTime;
+ public final boolean mRequireRemoteWipe;
+ public final int mPasswordExpirationDays;
+ public final int mPasswordHistory;
+ public final int mPasswordComplexChars;
+ public final boolean mRequireEncryption;
+
+ public int getMinPasswordLengthForTest() {
+ return mMinPasswordLength;
+ }
+
+ public int getPasswordModeForTest() {
+ return mPasswordMode;
+ }
+
+ public int getMaxPasswordFailsForTest() {
+ return mMaxPasswordFails;
+ }
+
+ public int getMaxScreenLockTimeForTest() {
+ return mMaxScreenLockTime;
+ }
+
+ public boolean isRequireRemoteWipeForTest() {
+ return mRequireRemoteWipe;
+ }
+
+ public boolean isRequireEncryptionForTest() {
+ return mRequireEncryption;
+ }
+
+ /**
+ * Create from raw values.
+ * @param minPasswordLength (0=not enforced)
+ * @param passwordMode
+ * @param maxPasswordFails (0=not enforced)
+ * @param maxScreenLockTime in seconds (0=not enforced)
+ * @param requireRemoteWipe
+ * @param passwordExpirationDays in days (0=not enforced)
+ * @param passwordHistory (0=not enforced)
+ * @param passwordComplexChars (0=not enforced)
+ * @throws IllegalArgumentException for illegal arguments.
+ */
+ public PolicySet(int minPasswordLength, int passwordMode, int maxPasswordFails,
+ int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays,
+ int passwordHistory, int passwordComplexChars, boolean requireEncryption)
+ throws IllegalArgumentException {
+ // If we're not enforcing passwords, make sure we clean up related values, since EAS
+ // can send non-zero values for any or all of these
+ if (passwordMode == PASSWORD_MODE_NONE) {
+ maxPasswordFails = 0;
+ maxScreenLockTime = 0;
+ minPasswordLength = 0;
+ passwordComplexChars = 0;
+ passwordHistory = 0;
+ passwordExpirationDays = 0;
+ } else {
+ if ((passwordMode != PASSWORD_MODE_SIMPLE) &&
+ (passwordMode != PASSWORD_MODE_STRONG)) {
+ throw new IllegalArgumentException("password mode");
+ }
+ // If we're only requiring a simple password, set complex chars to zero; note
+ // that EAS can erroneously send non-zero values in this case
+ if (passwordMode == PASSWORD_MODE_SIMPLE) {
+ passwordComplexChars = 0;
+ }
+ // The next four values have hard limits which cannot be supported if exceeded.
+ if (minPasswordLength > PASSWORD_LENGTH_MAX) {
+ throw new IllegalArgumentException("password length");
+ }
+ if (passwordExpirationDays > PASSWORD_EXPIRATION_MAX) {
+ throw new IllegalArgumentException("password expiration");
+ }
+ if (passwordHistory > PASSWORD_HISTORY_MAX) {
+ throw new IllegalArgumentException("password history");
+ }
+ if (passwordComplexChars > PASSWORD_COMPLEX_CHARS_MAX) {
+ throw new IllegalArgumentException("complex chars");
+ }
+ // This value can be reduced (which actually increases security) if necessary
+ if (maxPasswordFails > PASSWORD_MAX_FAILS_MAX) {
+ maxPasswordFails = PASSWORD_MAX_FAILS_MAX;
+ }
+ // This value can be reduced (which actually increases security) if necessary
+ if (maxScreenLockTime > SCREEN_LOCK_TIME_MAX) {
+ maxScreenLockTime = SCREEN_LOCK_TIME_MAX;
+ }
+ }
+ mMinPasswordLength = minPasswordLength;
+ mPasswordMode = passwordMode;
+ mMaxPasswordFails = maxPasswordFails;
+ mMaxScreenLockTime = maxScreenLockTime;
+ mRequireRemoteWipe = requireRemoteWipe;
+ mPasswordExpirationDays = passwordExpirationDays;
+ mPasswordHistory = passwordHistory;
+ mPasswordComplexChars = passwordComplexChars;
+ mRequireEncryption = requireEncryption;
+ }
+
+ /**
+ * Create from values encoded in an account
+ * @param account
+ */
+ public PolicySet(Account account) {
+ this(account.mSecurityFlags);
+ }
+
+ /**
+ * Create from values encoded in an account flags int
+ */
+ public PolicySet(long flags) {
+ mMinPasswordLength =
+ (int) ((flags & PASSWORD_LENGTH_MASK) >> PASSWORD_LENGTH_SHIFT);
+ mPasswordMode =
+ (int) (flags & PASSWORD_MODE_MASK);
+ mMaxPasswordFails =
+ (int) ((flags & PASSWORD_MAX_FAILS_MASK) >> PASSWORD_MAX_FAILS_SHIFT);
+ mMaxScreenLockTime =
+ (int) ((flags & SCREEN_LOCK_TIME_MASK) >> SCREEN_LOCK_TIME_SHIFT);
+ mRequireRemoteWipe = 0 != (flags & REQUIRE_REMOTE_WIPE);
+ mPasswordExpirationDays =
+ (int) ((flags & PASSWORD_EXPIRATION_MASK) >> PASSWORD_EXPIRATION_SHIFT);
+ mPasswordHistory =
+ (int) ((flags & PASSWORD_HISTORY_MASK) >> PASSWORD_HISTORY_SHIFT);
+ mPasswordComplexChars =
+ (int) ((flags & PASSWORD_COMPLEX_CHARS_MASK) >> PASSWORD_COMPLEX_CHARS_SHIFT);
+ mRequireEncryption = 0 != (flags & REQUIRE_ENCRYPTION);
+ }
+
+ /**
+ * Helper to map our internal encoding to DevicePolicyManager password modes.
+ */
+ public int getDPManagerPasswordQuality() {
+ switch (mPasswordMode) {
+ case PASSWORD_MODE_SIMPLE:
+ return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+ case PASSWORD_MODE_STRONG:
+ return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+ default:
+ return DevicePolicyManager .PASSWORD_QUALITY_UNSPECIFIED;
+ }
+ }
+
+ /**
+ * Helper to map expiration times to the millisecond values used by DevicePolicyManager.
+ */
+ public long getDPManagerPasswordExpirationTimeout() {
+ long result = mPasswordExpirationDays * DAYS_TO_MSEC;
+ // Add a small offset to the password expiration. This makes it easier to test
+ // by changing (for example) 1 day to 1 day + 5 minutes. If you set an expiration
+ // that is within the warning period, you should get a warning fairly quickly.
+ if (result > 0) {
+ result += EXPIRATION_OFFSET_MSEC;
+ }
+ return result;
+ }
+
+ /**
+ * Record flags (and a sync key for the flags) into an Account
+ * Note: the hash code is defined as the encoding used in Account
+ *
+ * @param account to write the values mSecurityFlags and mSecuritySyncKey
+ * @param syncKey the value to write into the account's mSecuritySyncKey
+ * @param update if true, also writes the account back to the provider (updating only
+ * the fields changed by this API)
+ * @param context a context for writing to the provider
+ * @return true if the actual policies changed, false if no change (note, sync key
+ * does not affect this)
+ */
+ public boolean writeAccount(Account account, String syncKey, boolean update,
+ Context context) {
+ long newFlags = getSecurityCode();
+ boolean dirty = (newFlags != account.mSecurityFlags);
+ account.mSecurityFlags = newFlags;
+ account.mSecuritySyncKey = syncKey;
+ if (update) {
+ if (account.isSaved()) {
+ ContentValues cv = new ContentValues();
+ cv.put(AccountColumns.SECURITY_FLAGS, account.mSecurityFlags);
+ cv.put(AccountColumns.SECURITY_SYNC_KEY, account.mSecuritySyncKey);
+ account.update(context, cv);
+ } else {
+ account.save(context);
+ }
+ }
+ return dirty;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof PolicySet) {
+ PolicySet other = (PolicySet)o;
+ return (this.getSecurityCode() == other.getSecurityCode());
+ }
+ return false;
+ }
+
+ /**
+ * Supports Parcelable
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Supports Parcelable
+ */
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ public PolicySet createFromParcel(Parcel in) {
+ return new PolicySet(in);
+ }
+
+ public PolicySet[] newArray(int size) {
+ return new PolicySet[size];
+ }
+ };
+
+ /**
+ * Supports Parcelable
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mMinPasswordLength);
+ dest.writeInt(mPasswordMode);
+ dest.writeInt(mMaxPasswordFails);
+ dest.writeInt(mMaxScreenLockTime);
+ dest.writeInt(mRequireRemoteWipe ? 1 : 0);
+ dest.writeInt(mPasswordExpirationDays);
+ dest.writeInt(mPasswordHistory);
+ dest.writeInt(mPasswordComplexChars);
+ dest.writeInt(mRequireEncryption ? 1 : 0);
+ }
+
+ /**
+ * Supports Parcelable
+ */
+ public PolicySet(Parcel in) {
+ mMinPasswordLength = in.readInt();
+ mPasswordMode = in.readInt();
+ mMaxPasswordFails = in.readInt();
+ mMaxScreenLockTime = in.readInt();
+ mRequireRemoteWipe = in.readInt() == 1;
+ mPasswordExpirationDays = in.readInt();
+ mPasswordHistory = in.readInt();
+ mPasswordComplexChars = in.readInt();
+ mRequireEncryption = in.readInt() == 1;
+ }
+
+ @Override
+ public int hashCode() {
+ long code = getSecurityCode();
+ return (int) code;
+ }
+
+ public long getSecurityCode() {
+ long flags = 0;
+ flags = (long)mMinPasswordLength << PASSWORD_LENGTH_SHIFT;
+ flags |= mPasswordMode;
+ flags |= (long)mMaxPasswordFails << PASSWORD_MAX_FAILS_SHIFT;
+ flags |= (long)mMaxScreenLockTime << SCREEN_LOCK_TIME_SHIFT;
+ if (mRequireRemoteWipe) flags |= REQUIRE_REMOTE_WIPE;
+ flags |= (long)mPasswordHistory << PASSWORD_HISTORY_SHIFT;
+ flags |= (long)mPasswordExpirationDays << PASSWORD_EXPIRATION_SHIFT;
+ flags |= (long)mPasswordComplexChars << PASSWORD_COMPLEX_CHARS_SHIFT;
+ if (mRequireEncryption) flags |= REQUIRE_ENCRYPTION;
+ return flags;
+ }
+
+ @Override
+ public String toString() {
+ return "{ " + "pw-len-min=" + mMinPasswordLength + " pw-mode=" + mPasswordMode
+ + " pw-fails-max=" + mMaxPasswordFails + " screenlock-max="
+ + mMaxScreenLockTime + " remote-wipe-req=" + mRequireRemoteWipe
+ + " pw-expiration=" + mPasswordExpirationDays
+ + " pw-history=" + mPasswordHistory
+ + " pw-complex-chars=" + mPasswordComplexChars
+ + " require-encryption=" + mRequireEncryption + "}";
+ }
+}
+
diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java
index 32441b094..e1254a5e3 100644
--- a/src/com/android/exchange/EasSyncService.java
+++ b/src/com/android/exchange/EasSyncService.java
@@ -17,8 +17,6 @@
package com.android.exchange;
-import com.android.email.SecurityPolicy;
-import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.Utility;
import com.android.email.mail.Address;
import com.android.email.mail.MeetingInfo;
@@ -37,6 +35,8 @@ import com.android.email.provider.EmailContent.SyncColumns;
import com.android.emailcommon.service.EmailServiceConstants;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.emailcommon.service.EmailServiceStatus;
+import com.android.emailcommon.service.PolicyServiceProxy;
+import com.android.emailcommon.service.PolicySet;
import com.android.exchange.adapter.AbstractSyncAdapter;
import com.android.exchange.adapter.AccountSyncAdapter;
import com.android.exchange.adapter.CalendarSyncAdapter;
@@ -46,11 +46,11 @@ import com.android.exchange.adapter.FolderSyncParser;
import com.android.exchange.adapter.GalParser;
import com.android.exchange.adapter.MeetingResponseParser;
import com.android.exchange.adapter.MoveItemsParser;
-import com.android.exchange.adapter.Parser.EasParserException;
import com.android.exchange.adapter.PingParser;
import com.android.exchange.adapter.ProvisionParser;
import com.android.exchange.adapter.Serializer;
import com.android.exchange.adapter.Tags;
+import com.android.exchange.adapter.Parser.EasParserException;
import com.android.exchange.provider.GalResult;
import com.android.exchange.utility.CalendarUtilities;
@@ -1435,24 +1435,23 @@ public class EasSyncService extends AbstractSyncService {
// by the server
ProvisionParser pp = canProvision();
if (pp != null) {
- SecurityPolicy sp = SecurityPolicy.getInstance(mContext);
// Get the policies from ProvisionParser
PolicySet ps = pp.getPolicySet();
// Update the account with a null policyKey (the key we've gotten is
// temporary and cannot be used for syncing)
ps.writeAccount(mAccount, null, true, mContext);
// Make sure that SecurityPolicy is up-to-date
- sp.updatePolicies(mAccount.mId);
+ PolicyServiceProxy.updatePolicies(mContext, mAccount.mId);
if (pp.getRemoteWipe()) {
// We've gotten a remote wipe command
ExchangeService.alwaysLog("!!! Remote wipe request received");
// Start by setting the account to security hold
- sp.setAccountHoldFlag(mContext, mAccount, true);
+ PolicyServiceProxy.setAccountHoldFlag(mContext, mAccount, true);
// Force a stop to any running syncs for this account (except this one)
ExchangeService.stopNonAccountMailboxSyncsForAccount(mAccount.mId);
// If we're not the admin, we can't do the wipe, so just return
- if (!sp.isActiveAdmin()) {
+ if (!PolicyServiceProxy.isActiveAdmin(mContext)) {
ExchangeService.alwaysLog("!!! Not device admin; can't wipe");
return false;
}
@@ -1468,9 +1467,9 @@ public class EasSyncService extends AbstractSyncService {
}
// Then, tell SecurityPolicy to wipe the device
ExchangeService.alwaysLog("!!! Executing remote wipe");
- sp.remoteWipe();
+ PolicyServiceProxy.remoteWipe(mContext);
return false;
- } else if (sp.isActive(ps)) {
+ } else if (PolicyServiceProxy.isActive(mContext, ps)) {
// See if the required policies are in force; if they are, acknowledge the policies
// to the server and get the final policy key
String policyKey = acknowledgeProvision(pp.getPolicyKey(), PROVISION_STATUS_OK);
@@ -1483,7 +1482,7 @@ public class EasSyncService extends AbstractSyncService {
}
} else {
// Notify that we are blocked because of policies
- sp.policiesRequired(mAccount.mId);
+ PolicyServiceProxy.policiesRequired(mContext, mAccount.mId);
}
}
return false;
@@ -1762,15 +1761,14 @@ public class EasSyncService extends AbstractSyncService {
String key = mAccount.mSecuritySyncKey;
if (!TextUtils.isEmpty(key)) {
PolicySet ps = new PolicySet(mAccount);
- SecurityPolicy sp = SecurityPolicy.getInstance(mContext);
- if (!sp.isActive(ps)) {
+ if (!PolicyServiceProxy.isActive(mContext, ps)) {
cv.clear();
cv.put(AccountColumns.SECURITY_FLAGS, 0);
cv.putNull(AccountColumns.SECURITY_SYNC_KEY);
long accountId = mAccount.mId;
mContentResolver.update(ContentUris.withAppendedId(
Account.CONTENT_URI, accountId), cv, null, null);
- sp.policiesRequired(accountId);
+ PolicyServiceProxy.policiesRequired(mContext, accountId);
}
}
diff --git a/src/com/android/exchange/adapter/ProvisionParser.java b/src/com/android/exchange/adapter/ProvisionParser.java
index c5ef7ae14..21eae349c 100644
--- a/src/com/android/exchange/adapter/ProvisionParser.java
+++ b/src/com/android/exchange/adapter/ProvisionParser.java
@@ -15,8 +15,8 @@
package com.android.exchange.adapter;
-import com.android.email.SecurityPolicy;
-import com.android.email.SecurityPolicy.PolicySet;
+import com.android.emailcommon.service.PolicyServiceProxy;
+import com.android.emailcommon.service.PolicySet;
import com.android.exchange.EasSyncService;
import org.xmlpull.v1.XmlPullParser;
@@ -61,8 +61,7 @@ public class ProvisionParser extends Parser {
}
public void clearUnsupportedPolicies() {
- mPolicySet = SecurityPolicy.getInstance(mService.mContext)
- .clearUnsupportedPolicies(mPolicySet);
+ mPolicySet = PolicyServiceProxy.clearUnsupportedPolicies(mService.mContext, mPolicySet);
mIsSupportable = true;
}
@@ -209,11 +208,12 @@ public class ProvisionParser extends Parser {
}
}
- mPolicySet = new SecurityPolicy.PolicySet(minPasswordLength, passwordMode,
+ mPolicySet = new PolicySet(minPasswordLength, passwordMode,
maxPasswordFails, maxScreenLockTime, true, passwordExpirationDays, passwordHistory,
passwordComplexChars, encryptionRequired);
+
// We can only determine whether encryption is supported on device by using isSupported here
- if (!SecurityPolicy.getInstance(mService.mContext).isSupported(mPolicySet)) {
+ if (!PolicyServiceProxy.isSupported(mService.mContext, mPolicySet)) {
log("SecurityPolicy reports PolicySet not supported.");
mIsSupportable = false;
}
diff --git a/tests/src/com/android/email/SecurityPolicyTests.java b/tests/src/com/android/email/SecurityPolicyTests.java
index 5719f884d..33edeb91d 100644
--- a/tests/src/com/android/email/SecurityPolicyTests.java
+++ b/tests/src/com/android/email/SecurityPolicyTests.java
@@ -16,15 +16,15 @@
package com.android.email;
-import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.provider.ContentCache;
import com.android.email.provider.EmailContent;
+import com.android.email.provider.EmailProvider;
+import com.android.email.provider.ProviderTestUtils;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
-import com.android.email.provider.EmailProvider;
-import com.android.email.provider.ProviderTestUtils;
+import com.android.emailcommon.service.PolicySet;
import android.app.admin.DevicePolicyManager;
import android.content.ContentUris;
diff --git a/tests/src/com/android/exchange/adapter/ProvisionParserTests.java b/tests/src/com/android/exchange/adapter/ProvisionParserTests.java
index e69d12506..7daf0cc9f 100644
--- a/tests/src/com/android/exchange/adapter/ProvisionParserTests.java
+++ b/tests/src/com/android/exchange/adapter/ProvisionParserTests.java
@@ -16,7 +16,7 @@
package com.android.exchange.adapter;
-import com.android.email.SecurityPolicy.PolicySet;
+import com.android.emailcommon.service.PolicySet;
import java.io.ByteArrayInputStream;
import java.io.IOException;