Email split, part deux: PolicyService
* Split PolicySet from SecurityPolicy and move to emailcommon * Define PolicyService that sync adapter services can use to interact with the Email DPM administrator * Implement PolicyServiceProxy for exchange * Implement PolicyService in email * Modify imports, references, etc. as required Bug: 3442973 Change-Id: I92015e21f780a68754b318da89fbb33570f334a2
This commit is contained in:
parent
0d4fc55861
commit
9ba506c4dd
|
@ -20,7 +20,8 @@ LOCAL_MODULE_TAGS := optional
|
||||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
src/com/android/emailcommon/service/IEmailService.aidl \
|
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
|
LOCAL_STATIC_JAVA_LIBRARIES := android-common
|
||||||
# Revive this when the app is unbundled.
|
# Revive this when the app is unbundled.
|
||||||
|
|
|
@ -358,6 +358,18 @@
|
||||||
android:resource="@xml/syncadapter_pop_imap" />
|
android:resource="@xml/syncadapter_pop_imap" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<!-- Require provider permission to use our Policy and Account services -->
|
||||||
|
<service
|
||||||
|
android:name=".service.PolicyService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||||
|
>
|
||||||
|
<intent-filter>
|
||||||
|
<action
|
||||||
|
android:name="com.android.email.POLICY_INTENT" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<!--EXCHANGE-REMOVE-SECTION-START-->
|
<!--EXCHANGE-REMOVE-SECTION-START-->
|
||||||
<!--Required stanza to register the EAS EmailSyncAdapterService with SyncManager -->
|
<!--Required stanza to register the EAS EmailSyncAdapterService with SyncManager -->
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.android.email.provider.EmailContent;
|
||||||
import com.android.email.provider.EmailContent.Account;
|
import com.android.email.provider.EmailContent.Account;
|
||||||
import com.android.email.provider.EmailContent.AccountColumns;
|
import com.android.email.provider.EmailContent.AccountColumns;
|
||||||
import com.android.email.service.EmailBroadcastProcessorService;
|
import com.android.email.service.EmailBroadcastProcessorService;
|
||||||
|
import com.android.emailcommon.service.PolicySet;
|
||||||
|
|
||||||
import android.app.admin.DeviceAdminInfo;
|
import android.app.admin.DeviceAdminInfo;
|
||||||
import android.app.admin.DeviceAdminReceiver;
|
import android.app.admin.DeviceAdminReceiver;
|
||||||
|
@ -31,8 +32,6 @@ import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -418,12 +417,22 @@ public class SecurityPolicy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method; see javadoc below
|
||||||
|
*/
|
||||||
|
public static void setAccountHoldFlag(Context context, long accountId, boolean newState) {
|
||||||
|
Account account = Account.restoreAccountWithId(context, accountId);
|
||||||
|
if (account != null) {
|
||||||
|
setAccountHoldFlag(context, account, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API: Set/Clear the "hold" flag in any account. This flag serves a dual purpose:
|
* API: Set/Clear the "hold" flag in any account. This flag serves a dual purpose:
|
||||||
* Setting it gives us an indication that it was blocked, and clearing it gives EAS a
|
* Setting it gives us an indication that it was blocked, and clearing it gives EAS a
|
||||||
* signal to try syncing again.
|
* signal to try syncing again.
|
||||||
* @param context
|
* @param context
|
||||||
* @param account The account to update
|
* @param account the account whose hold flag is to be set/cleared
|
||||||
* @param newState true = security hold, false = free to sync
|
* @param newState true = security hold, false = free to sync
|
||||||
*/
|
*/
|
||||||
public static void setAccountHoldFlag(Context context, Account account, boolean newState) {
|
public static void setAccountHoldFlag(Context context, Account account, boolean newState) {
|
||||||
|
@ -485,336 +494,6 @@ public class SecurityPolicy {
|
||||||
Log.d(Email.LOG_TAG, "Could not remote wipe because not device admin.");
|
Log.d(Email.LOG_TAG, "Could not remote wipe because not device admin.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for tracking policies and reading/writing into accounts
|
|
||||||
*/
|
|
||||||
public static 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;
|
|
||||||
|
|
||||||
/*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<PolicySet> CREATOR
|
|
||||||
= new Parcelable.Creator<PolicySet>() {
|
|
||||||
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.
|
* If we are not the active device admin, try to become so.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,13 +19,13 @@ package com.android.email.activity.setup;
|
||||||
import com.android.email.Email;
|
import com.android.email.Email;
|
||||||
import com.android.email.R;
|
import com.android.email.R;
|
||||||
import com.android.email.Utility;
|
import com.android.email.Utility;
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
|
||||||
import com.android.email.mail.MessagingException;
|
import com.android.email.mail.MessagingException;
|
||||||
import com.android.email.mail.Sender;
|
import com.android.email.mail.Sender;
|
||||||
import com.android.email.mail.Store;
|
import com.android.email.mail.Store;
|
||||||
import com.android.email.provider.EmailContent.Account;
|
import com.android.email.provider.EmailContent.Account;
|
||||||
import com.android.email.provider.EmailContent.HostAuth;
|
import com.android.email.provider.EmailContent.HostAuth;
|
||||||
import com.android.emailcommon.service.EmailServiceProxy;
|
import com.android.emailcommon.service.EmailServiceProxy;
|
||||||
|
import com.android.emailcommon.service.PolicySet;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
|
|
@ -19,13 +19,13 @@ package com.android.email.activity.setup;
|
||||||
import com.android.email.Email;
|
import com.android.email.Email;
|
||||||
import com.android.email.ExchangeUtils;
|
import com.android.email.ExchangeUtils;
|
||||||
import com.android.email.R;
|
import com.android.email.R;
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
|
||||||
import com.android.email.Utility;
|
import com.android.email.Utility;
|
||||||
import com.android.email.activity.ActivityHelper;
|
import com.android.email.activity.ActivityHelper;
|
||||||
import com.android.email.mail.Store;
|
import com.android.email.mail.Store;
|
||||||
import com.android.email.provider.EmailContent;
|
import com.android.email.provider.EmailContent;
|
||||||
import com.android.email.provider.EmailContent.Account;
|
import com.android.email.provider.EmailContent.Account;
|
||||||
import com.android.email.service.MailService;
|
import com.android.email.service.MailService;
|
||||||
|
import com.android.emailcommon.service.PolicySet;
|
||||||
|
|
||||||
import android.accounts.AccountAuthenticatorResponse;
|
import android.accounts.AccountAuthenticatorResponse;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package com.android.email.activity.setup;
|
package com.android.email.activity.setup;
|
||||||
|
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
|
||||||
import com.android.email.provider.EmailContent.Account;
|
import com.android.email.provider.EmailContent.Account;
|
||||||
|
import com.android.emailcommon.service.PolicySet;
|
||||||
|
|
||||||
import android.accounts.AccountAuthenticatorResponse;
|
import android.accounts.AccountAuthenticatorResponse;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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<PolicySet> CREATOR
|
||||||
|
= new Parcelable.Creator<PolicySet>() {
|
||||||
|
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 + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
package com.android.exchange;
|
package com.android.exchange;
|
||||||
|
|
||||||
import com.android.email.SecurityPolicy;
|
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
|
||||||
import com.android.email.Utility;
|
import com.android.email.Utility;
|
||||||
import com.android.email.mail.Address;
|
import com.android.email.mail.Address;
|
||||||
import com.android.email.mail.MeetingInfo;
|
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.EmailServiceConstants;
|
||||||
import com.android.emailcommon.service.EmailServiceProxy;
|
import com.android.emailcommon.service.EmailServiceProxy;
|
||||||
import com.android.emailcommon.service.EmailServiceStatus;
|
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.AbstractSyncAdapter;
|
||||||
import com.android.exchange.adapter.AccountSyncAdapter;
|
import com.android.exchange.adapter.AccountSyncAdapter;
|
||||||
import com.android.exchange.adapter.CalendarSyncAdapter;
|
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.GalParser;
|
||||||
import com.android.exchange.adapter.MeetingResponseParser;
|
import com.android.exchange.adapter.MeetingResponseParser;
|
||||||
import com.android.exchange.adapter.MoveItemsParser;
|
import com.android.exchange.adapter.MoveItemsParser;
|
||||||
import com.android.exchange.adapter.Parser.EasParserException;
|
|
||||||
import com.android.exchange.adapter.PingParser;
|
import com.android.exchange.adapter.PingParser;
|
||||||
import com.android.exchange.adapter.ProvisionParser;
|
import com.android.exchange.adapter.ProvisionParser;
|
||||||
import com.android.exchange.adapter.Serializer;
|
import com.android.exchange.adapter.Serializer;
|
||||||
import com.android.exchange.adapter.Tags;
|
import com.android.exchange.adapter.Tags;
|
||||||
|
import com.android.exchange.adapter.Parser.EasParserException;
|
||||||
import com.android.exchange.provider.GalResult;
|
import com.android.exchange.provider.GalResult;
|
||||||
import com.android.exchange.utility.CalendarUtilities;
|
import com.android.exchange.utility.CalendarUtilities;
|
||||||
|
|
||||||
|
@ -1435,24 +1435,23 @@ public class EasSyncService extends AbstractSyncService {
|
||||||
// by the server
|
// by the server
|
||||||
ProvisionParser pp = canProvision();
|
ProvisionParser pp = canProvision();
|
||||||
if (pp != null) {
|
if (pp != null) {
|
||||||
SecurityPolicy sp = SecurityPolicy.getInstance(mContext);
|
|
||||||
// Get the policies from ProvisionParser
|
// Get the policies from ProvisionParser
|
||||||
PolicySet ps = pp.getPolicySet();
|
PolicySet ps = pp.getPolicySet();
|
||||||
// Update the account with a null policyKey (the key we've gotten is
|
// Update the account with a null policyKey (the key we've gotten is
|
||||||
// temporary and cannot be used for syncing)
|
// temporary and cannot be used for syncing)
|
||||||
ps.writeAccount(mAccount, null, true, mContext);
|
ps.writeAccount(mAccount, null, true, mContext);
|
||||||
// Make sure that SecurityPolicy is up-to-date
|
// Make sure that SecurityPolicy is up-to-date
|
||||||
sp.updatePolicies(mAccount.mId);
|
PolicyServiceProxy.updatePolicies(mContext, mAccount.mId);
|
||||||
if (pp.getRemoteWipe()) {
|
if (pp.getRemoteWipe()) {
|
||||||
// We've gotten a remote wipe command
|
// We've gotten a remote wipe command
|
||||||
ExchangeService.alwaysLog("!!! Remote wipe request received");
|
ExchangeService.alwaysLog("!!! Remote wipe request received");
|
||||||
// Start by setting the account to security hold
|
// 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)
|
// Force a stop to any running syncs for this account (except this one)
|
||||||
ExchangeService.stopNonAccountMailboxSyncsForAccount(mAccount.mId);
|
ExchangeService.stopNonAccountMailboxSyncsForAccount(mAccount.mId);
|
||||||
|
|
||||||
// If we're not the admin, we can't do the wipe, so just return
|
// 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");
|
ExchangeService.alwaysLog("!!! Not device admin; can't wipe");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1468,9 +1467,9 @@ public class EasSyncService extends AbstractSyncService {
|
||||||
}
|
}
|
||||||
// Then, tell SecurityPolicy to wipe the device
|
// Then, tell SecurityPolicy to wipe the device
|
||||||
ExchangeService.alwaysLog("!!! Executing remote wipe");
|
ExchangeService.alwaysLog("!!! Executing remote wipe");
|
||||||
sp.remoteWipe();
|
PolicyServiceProxy.remoteWipe(mContext);
|
||||||
return false;
|
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
|
// See if the required policies are in force; if they are, acknowledge the policies
|
||||||
// to the server and get the final policy key
|
// to the server and get the final policy key
|
||||||
String policyKey = acknowledgeProvision(pp.getPolicyKey(), PROVISION_STATUS_OK);
|
String policyKey = acknowledgeProvision(pp.getPolicyKey(), PROVISION_STATUS_OK);
|
||||||
|
@ -1483,7 +1482,7 @@ public class EasSyncService extends AbstractSyncService {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Notify that we are blocked because of policies
|
// Notify that we are blocked because of policies
|
||||||
sp.policiesRequired(mAccount.mId);
|
PolicyServiceProxy.policiesRequired(mContext, mAccount.mId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1762,15 +1761,14 @@ public class EasSyncService extends AbstractSyncService {
|
||||||
String key = mAccount.mSecuritySyncKey;
|
String key = mAccount.mSecuritySyncKey;
|
||||||
if (!TextUtils.isEmpty(key)) {
|
if (!TextUtils.isEmpty(key)) {
|
||||||
PolicySet ps = new PolicySet(mAccount);
|
PolicySet ps = new PolicySet(mAccount);
|
||||||
SecurityPolicy sp = SecurityPolicy.getInstance(mContext);
|
if (!PolicyServiceProxy.isActive(mContext, ps)) {
|
||||||
if (!sp.isActive(ps)) {
|
|
||||||
cv.clear();
|
cv.clear();
|
||||||
cv.put(AccountColumns.SECURITY_FLAGS, 0);
|
cv.put(AccountColumns.SECURITY_FLAGS, 0);
|
||||||
cv.putNull(AccountColumns.SECURITY_SYNC_KEY);
|
cv.putNull(AccountColumns.SECURITY_SYNC_KEY);
|
||||||
long accountId = mAccount.mId;
|
long accountId = mAccount.mId;
|
||||||
mContentResolver.update(ContentUris.withAppendedId(
|
mContentResolver.update(ContentUris.withAppendedId(
|
||||||
Account.CONTENT_URI, accountId), cv, null, null);
|
Account.CONTENT_URI, accountId), cv, null, null);
|
||||||
sp.policiesRequired(accountId);
|
PolicyServiceProxy.policiesRequired(mContext, accountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
package com.android.exchange.adapter;
|
package com.android.exchange.adapter;
|
||||||
|
|
||||||
import com.android.email.SecurityPolicy;
|
import com.android.emailcommon.service.PolicyServiceProxy;
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
import com.android.emailcommon.service.PolicySet;
|
||||||
import com.android.exchange.EasSyncService;
|
import com.android.exchange.EasSyncService;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
@ -61,8 +61,7 @@ public class ProvisionParser extends Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearUnsupportedPolicies() {
|
public void clearUnsupportedPolicies() {
|
||||||
mPolicySet = SecurityPolicy.getInstance(mService.mContext)
|
mPolicySet = PolicyServiceProxy.clearUnsupportedPolicies(mService.mContext, mPolicySet);
|
||||||
.clearUnsupportedPolicies(mPolicySet);
|
|
||||||
mIsSupportable = true;
|
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,
|
maxPasswordFails, maxScreenLockTime, true, passwordExpirationDays, passwordHistory,
|
||||||
passwordComplexChars, encryptionRequired);
|
passwordComplexChars, encryptionRequired);
|
||||||
|
|
||||||
// We can only determine whether encryption is supported on device by using isSupported here
|
// 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.");
|
log("SecurityPolicy reports PolicySet not supported.");
|
||||||
mIsSupportable = false;
|
mIsSupportable = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
|
|
||||||
package com.android.email;
|
package com.android.email;
|
||||||
|
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
|
||||||
import com.android.email.provider.ContentCache;
|
import com.android.email.provider.ContentCache;
|
||||||
import com.android.email.provider.EmailContent;
|
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.Account;
|
||||||
import com.android.email.provider.EmailContent.AccountColumns;
|
import com.android.email.provider.EmailContent.AccountColumns;
|
||||||
import com.android.email.provider.EmailContent.Mailbox;
|
import com.android.email.provider.EmailContent.Mailbox;
|
||||||
import com.android.email.provider.EmailContent.Message;
|
import com.android.email.provider.EmailContent.Message;
|
||||||
import com.android.email.provider.EmailProvider;
|
import com.android.emailcommon.service.PolicySet;
|
||||||
import com.android.email.provider.ProviderTestUtils;
|
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package com.android.exchange.adapter;
|
package com.android.exchange.adapter;
|
||||||
|
|
||||||
import com.android.email.SecurityPolicy.PolicySet;
|
import com.android.emailcommon.service.PolicySet;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
Loading…
Reference in New Issue