/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.email; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.ContextWrapper; import android.test.ProviderTestCase2; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; import com.android.email.provider.ContentCache; import com.android.email.provider.EmailProvider; import com.android.email.provider.ProviderTestUtils; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.provider.Policy; import com.android.emailcommon.service.LegacyPolicySet; /** * This is a series of unit tests for backup/restore of the SecurityPolicy class. * * You can run this entire test case with: * runtest -c com.android.email.SecurityPolicyTests email */ @MediumTest public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> { private Context mMockContext; private SecurityPolicy mSecurityPolicy; public SecurityPolicyTests() { super(EmailProvider.class, EmailContent.AUTHORITY); } private static final Policy EMPTY_POLICY = new Policy(); @Override protected void setUp() throws Exception { super.setUp(); mMockContext = new MockContext2(getMockContext(), mContext); // Invalidate all caches, since we reset the database for each test ContentCache.invalidateAllCaches(); Controller.getInstance(mMockContext).markForTest(true); } /** * Delete any dummy accounts we set up for this test */ @Override protected void tearDown() throws Exception { Controller.getInstance(mMockContext).markForTest(false); super.tearDown(); } /** * Private context wrapper used to add back getPackageName() for these tests. * * This class also implements {@link Context} method(s) that are called during tests. */ private static class MockContext2 extends ContextWrapper { private final Context mRealContext; public MockContext2(Context mockContext, Context realContext) { super(mockContext); mRealContext = realContext; } @Override public Context getApplicationContext() { return this; } @Override public String getPackageName() { return mRealContext.getPackageName(); } @Override public Object getSystemService(String name) { return mRealContext.getSystemService(name); } } /** * Create a Policy using the arguments formerly used to create a PolicySet; this minimizes the * changes needed for re-using the PolicySet unit test logic */ private Policy setupPolicy(int minPasswordLength, int passwordMode, int maxPasswordFails, int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays, int passwordHistory, int passwordComplexChars, boolean requireEncryption, boolean dontAllowCamera) throws IllegalArgumentException { Policy policy = new Policy(); policy.mPasswordMinLength = minPasswordLength; policy.mPasswordMode = passwordMode; policy.mPasswordMaxFails = maxPasswordFails; policy.mMaxScreenLockTime = maxScreenLockTime; policy.mRequireRemoteWipe = requireRemoteWipe; policy.mPasswordExpirationDays = passwordExpirationDays; policy.mPasswordHistory = passwordHistory; policy.mPasswordComplexChars = passwordComplexChars; policy.mRequireEncryption = requireEncryption; policy.mDontAllowCamera = dontAllowCamera; return policy; } /** * Test business logic of aggregating accounts with policies */ public void testAggregator() { mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); // with no accounts, should return empty set assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy()); // with accounts having no security, empty set ProviderTestUtils.setupAccount("no-sec-1", true, mMockContext); ProviderTestUtils.setupAccount("no-sec-2", true, mMockContext); assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy()); // with a single account in security mode, should return same security as in account // first test with partially-populated policies Account a3 = ProviderTestUtils.setupAccount("sec-3", true, mMockContext); Policy p3ain = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); Policy.setAccountPolicy(mMockContext, a3, p3ain, null); Policy p3aout = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p3aout); assertEquals(p3ain, p3aout); // Repeat that test with fully-populated policies Policy p3bin = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3, false, false); Policy.setAccountPolicy(mMockContext, a3, p3bin, null); Policy p3bout = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p3bout); assertEquals(p3bin, p3bout); // add another account which mixes it up (some fields will change, others will not) // pw length and pw mode - max logic - will change because larger #s here // fail count and lock timer - min logic - will *not* change because larger #s here // wipe required - OR logic - will *not* change here because false // expiration - will not change because 0 (unspecified) // max complex chars - max logic - will change // encryption required - OR logic - will *not* change here because false // don't allow camera - OR logic - will change here because it's true Policy p4in = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7, false, true); Account a4 = ProviderTestUtils.setupAccount("sec-4", true, mMockContext); Policy.setAccountPolicy(mMockContext, a4, p4in, null); Policy p4out = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p4out); assertEquals(20, p4out.mPasswordMinLength); assertEquals(Policy.PASSWORD_MODE_STRONG, p4out.mPasswordMode); assertEquals(15, p4out.mPasswordMaxFails); assertEquals(16, p4out.mMaxScreenLockTime); assertEquals(6, p4out.mPasswordExpirationDays); assertEquals(5, p4out.mPasswordHistory); assertEquals(7, p4out.mPasswordComplexChars); assertFalse(p4out.mRequireRemoteWipe); assertFalse(p4out.mRequireEncryption); assertFalse(p4out.mRequireEncryptionExternal); assertTrue(p4out.mDontAllowCamera); // add another account which mixes it up (the remaining fields will change) // pw length and pw mode - max logic - will *not* change because smaller #s here // fail count and lock timer - min logic - will change because smaller #s here // wipe required - OR logic - will change here because true // expiration time - min logic - will change because lower here // history & complex chars - will not change because 0 (unspecified) // encryption required - OR logic - will change here because true // don't allow camera - OR logic - will *not* change here because it's already true Policy p5in = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0, true, false); Account a5 = ProviderTestUtils.setupAccount("sec-5", true, mMockContext); Policy.setAccountPolicy(mMockContext, a5, p5in, null); Policy p5out = mSecurityPolicy.computeAggregatePolicy(); assertNotNull(p5out); assertEquals(20, p5out.mPasswordMinLength); assertEquals(Policy.PASSWORD_MODE_STRONG, p5out.mPasswordMode); assertEquals(5, p5out.mPasswordMaxFails); assertEquals(6, p5out.mMaxScreenLockTime); assertEquals(1, p5out.mPasswordExpirationDays); assertEquals(5, p5out.mPasswordHistory); assertEquals(7, p5out.mPasswordComplexChars); assertTrue(p5out.mRequireRemoteWipe); assertFalse(p5out.mRequireEncryptionExternal); assertTrue(p5out.mDontAllowCamera); } private long assertAccountPolicyConsistent(long accountId, long oldKey) { Account account = Account.restoreAccountWithId(mMockContext, accountId); long policyKey = account.mPolicyKey; assertTrue(policyKey > 0); // Found a policy. Ensure it matches. Policy policy = Policy.restorePolicyWithId(mMockContext, policyKey); assertNotNull(policy); assertEquals(account.mPolicyKey, policy.mId); assertEquals( accountId, Policy.getAccountIdWithPolicyKey(mMockContext, policy.mId)); // Assert the old one isn't there. if (oldKey > 0) { assertNull("old policy not cleaned up", Policy.restorePolicyWithId(mMockContext, oldKey)); } return policyKey; } @SmallTest public void testSettingAccountPolicy() { Account account = ProviderTestUtils.setupAccount("testaccount", true, mMockContext); long accountId = account.mId; Policy initial = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); Policy.setAccountPolicy(mMockContext, accountId, initial, null); long oldKey = assertAccountPolicyConsistent(account.mId, 0); Policy updated = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); Policy.setAccountPolicy(mMockContext, accountId, updated, null); oldKey = assertAccountPolicyConsistent(account.mId, oldKey); // Remove the policy Policy.clearAccountPolicy( mMockContext, Account.restoreAccountWithId(mMockContext, accountId)); assertNull("old policy not cleaned up", Policy.restorePolicyWithId(mMockContext, oldKey)); } /** * Test equality. Note, the tests for inequality are poor, as each field should * be tested individually. */ @SmallTest public void testEquals() { Policy p1 = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false); Policy p2 = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false); Policy p3 = setupPolicy(2, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false, false); Policy p4 = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, true); assertTrue(p1.equals(p2)); assertFalse(p2.equals(p3)); assertFalse(p1.equals(p4)); } /** * Test the API to set/clear policy hold flags in an account */ public void testSetClearHoldFlag() { Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext); a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL; a1.save(mMockContext); Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext); a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD; a2.save(mMockContext); // confirm clear until set Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId); assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags); SecurityPolicy.setAccountHoldFlag(mMockContext, a1, true); assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1.mFlags); Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId); assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1b.mFlags); // confirm set until cleared Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId); assertEquals(Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD, a2a.mFlags); SecurityPolicy.setAccountHoldFlag(mMockContext, a2, false); assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2.mFlags); Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId); assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2b.mFlags); } /** * Test the response to disabling DeviceAdmin status */ public void testDisableAdmin() { Account a1 = ProviderTestUtils.setupAccount("disable-1", true, mMockContext); Policy p1 = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); Policy.setAccountPolicy(mMockContext, a1, p1, "security-sync-key-1"); Account a2 = ProviderTestUtils.setupAccount("disable-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0, false, false); Policy.setAccountPolicy(mMockContext, a2, p2, "security-sync-key-2"); Account a3 = ProviderTestUtils.setupAccount("disable-3", true, mMockContext); Policy.clearAccountPolicy(mMockContext, a3); mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); // Confirm that "enabling" device admin does not change security status (policy & sync key) Policy before = mSecurityPolicy.getAggregatePolicy(); mSecurityPolicy.onAdminEnabled(true); // "enabled" should not change anything Policy after1 = mSecurityPolicy.getAggregatePolicy(); assertEquals(before, after1); Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId); assertNotNull(a1a.mSecuritySyncKey); assertTrue(a1a.mPolicyKey > 0); Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId); assertNotNull(a2a.mSecuritySyncKey); assertTrue(a2a.mPolicyKey > 0); Account a3a = Account.restoreAccountWithId(mMockContext, a3.mId); assertNull(a3a.mSecuritySyncKey); assertTrue(a3a.mPolicyKey == 0); mSecurityPolicy.deleteSecuredAccounts(mMockContext); Policy after2 = mSecurityPolicy.getAggregatePolicy(); assertEquals(EMPTY_POLICY, after2); Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId); assertNull(a1b); Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId); assertNull(a2b); Account a3b = Account.restoreAccountWithId(mMockContext, a3.mId); assertNull(a3b.mSecuritySyncKey); } /** * Test the scanner that finds expiring accounts */ public void testFindExpiringAccount() { ProviderTestUtils.setupAccount("expiring-1", true, mMockContext); // With no expiring accounts, this should return null. long nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); assertEquals(-1, nextExpiringAccountId); // Add a single expiring account Account a2 = ProviderTestUtils.setupAccount("expiring-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0, false, true); Policy.setAccountPolicy(mMockContext, a2, p2, null); // The expiring account should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); assertEquals(a2.mId, nextExpiringAccountId); // Add an account with a longer expiration Account a3 = ProviderTestUtils.setupAccount("expiring-3", true, mMockContext); Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0, false, true); Policy.setAccountPolicy(mMockContext, a3, p3, null); // The original expiring account (a2) should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); assertEquals(a2.mId, nextExpiringAccountId); // Add an account with a shorter expiration Account a4 = ProviderTestUtils.setupAccount("expiring-4", true, mMockContext); Policy p4 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0, false, true); Policy.setAccountPolicy(mMockContext, a4, p4, null); // The new expiring account (a4) should be returned nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext); assertEquals(a4.mId, nextExpiringAccountId); } /** * Lightweight subclass of the Controller class allows injection of mock context */ public static class TestController extends Controller { protected TestController(Context providerContext, Context systemContext) { super(systemContext); setProviderContext(providerContext); markForTest(true); } } /** * Test the scanner that wipes expiring accounts */ public void testWipeExpiringAccounts() { mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); TestController testController = new TestController(mMockContext, getContext()); // Two accounts - a1 is normal, a2 has security (but no expiration) Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext); Account a2 = ProviderTestUtils.setupAccount("expired-2", true, mMockContext); Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0, false, true); Policy.setAccountPolicy(mMockContext, a2, p2, null); // Add a mailbox & messages to each account long account1Id = a1.mId; long account2Id = a2.mId; Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); long box1Id = box1.mId; ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mMockContext); ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, true, mMockContext); Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account2Id, true, mMockContext); long box2Id = box2.mId; ProviderTestUtils.setupMessage("message3", account2Id, box2Id, false, true, mMockContext); ProviderTestUtils.setupMessage("message4", account2Id, box2Id, false, true, mMockContext); // Run the expiration code - should do nothing boolean wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController); assertFalse(wiped); // check mailboxes & messages not wiped assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI)); assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI)); assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI)); // Add 3rd account that really expires Account a3 = ProviderTestUtils.setupAccount("expired-3", true, mMockContext); Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0, false, true); Policy.setAccountPolicy(mMockContext, a3, p3, null); // Add mailbox & messages to 3rd account long account3Id = a3.mId; Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account3Id, true, mMockContext); long box3Id = box3.mId; ProviderTestUtils.setupMessage("message5", account3Id, box3Id, false, true, mMockContext); ProviderTestUtils.setupMessage("message6", account3Id, box3Id, false, true, mMockContext); // check new counts assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI)); assertEquals(3, EmailContent.count(mMockContext, Mailbox.CONTENT_URI)); assertEquals(6, EmailContent.count(mMockContext, Message.CONTENT_URI)); // Run the expiration code - wipe acct #3 wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController); assertTrue(wiped); // check new counts - account survives but data is wiped assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI)); assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI)); assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI)); // Check security hold states - only #3 should be in hold Account account = Account.restoreAccountWithId(mMockContext, account1Id); assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD); account = Account.restoreAccountWithId(mMockContext, account2Id); assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD); account = Account.restoreAccountWithId(mMockContext, account3Id); assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD); } /** * Test the code that clears unsupported policies * TODO inject a mock DPM so we can directly control & test all cases, no matter what device */ public void testClearUnsupportedPolicies() { Policy p1 = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false); Policy p2 = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true, false); mSecurityPolicy = SecurityPolicy.getInstance(mMockContext); DevicePolicyManager dpm = mSecurityPolicy.getDPM(); boolean hasEncryption = dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED; Policy p1Result = mSecurityPolicy.clearUnsupportedPolicies(p1); Policy p2Result = mSecurityPolicy.clearUnsupportedPolicies(p2); // No changes expected when encryptionRequested was false assertEquals(p1, p1Result); if (hasEncryption) { // No changes expected assertEquals(p2, p2Result); } else { // If encryption is unsupported, encryption policy bits are cleared Policy policyExpect = setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false); assertEquals(policyExpect, p2Result); } } /** * Test the code that converts from exchange-style quality to DPM/Lockscreen style quality. */ public void testGetDPManagerPasswordQuality() { // Policy.PASSWORD_MODE_NONE -> DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED Policy p1 = setupPolicy(0, Policy.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false, false); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, p1.getDPManagerPasswordQuality()); // PASSWORD_MODE_SIMPLE -> PASSWORD_QUALITY_NUMERIC Policy p2 = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, p2.getDPManagerPasswordQuality()); // PASSWORD_MODE_STRONG -> PASSWORD_QUALITY_ALPHANUMERIC Policy p3 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0, 0, false, false); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, p3.getDPManagerPasswordQuality()); // PASSWORD_MODE_STRONG + complex chars -> PASSWORD_QUALITY_COMPLEX Policy p4 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0 , 2, false, false); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, p4.getDPManagerPasswordQuality()); } private boolean policySetEqualsPolicy(PolicySet ps, Policy policy) { if ((ps.mPasswordMode >> LegacyPolicySet.PASSWORD_MODE_SHIFT) != policy.mPasswordMode) { return false; } if (ps.mMinPasswordLength != policy.mPasswordMinLength) return false; if (ps.mPasswordComplexChars != policy.mPasswordComplexChars) return false; if (ps.mPasswordHistory != policy.mPasswordHistory) return false; if (ps.mPasswordExpirationDays != policy.mPasswordExpirationDays) return false; if (ps.mMaxPasswordFails != policy.mPasswordMaxFails) return false; if (ps.mMaxScreenLockTime != policy.mMaxScreenLockTime) return false; if (ps.mRequireRemoteWipe != policy.mRequireRemoteWipe) return false; if (ps.mRequireEncryption != policy.mRequireEncryption) return false; if (ps.mRequireEncryptionExternal != policy.mRequireEncryptionExternal) return false; return true; } public void testPolicyFlagsToPolicy() { // Policy flags; the three sets included here correspond to policies for three test // accounts that, between them, use all of the possible policies long flags = 67096612L; PolicySet ps = new PolicySet(flags); Policy policy = LegacyPolicySet.flagsToPolicy(flags); assertTrue(policySetEqualsPolicy(ps, policy)); flags = 52776591691846L; ps = new PolicySet(flags); policy = LegacyPolicySet.flagsToPolicy(flags); assertTrue(policySetEqualsPolicy(ps, policy)); flags = 1689605957029924L; ps = new PolicySet(flags); policy = LegacyPolicySet.flagsToPolicy(flags); assertTrue(policySetEqualsPolicy(ps, policy)); } /** * The old PolicySet class fields and constructor; we use this to test conversion to the * new Policy table scheme */ private static class PolicySet { private final int mMinPasswordLength; private final int mPasswordMode; private final int mMaxPasswordFails; private final int mMaxScreenLockTime; private final boolean mRequireRemoteWipe; private final int mPasswordExpirationDays; private final int mPasswordHistory; private final int mPasswordComplexChars; private final boolean mRequireEncryption; private final boolean mRequireEncryptionExternal; /** * Create from values encoded in an account flags int */ private PolicySet(long flags) { mMinPasswordLength = (int) ((flags & LegacyPolicySet.PASSWORD_LENGTH_MASK) >> LegacyPolicySet.PASSWORD_LENGTH_SHIFT); mPasswordMode = (int) (flags & LegacyPolicySet.PASSWORD_MODE_MASK); mMaxPasswordFails = (int) ((flags & LegacyPolicySet.PASSWORD_MAX_FAILS_MASK) >> LegacyPolicySet.PASSWORD_MAX_FAILS_SHIFT); mMaxScreenLockTime = (int) ((flags & LegacyPolicySet.SCREEN_LOCK_TIME_MASK) >> LegacyPolicySet.SCREEN_LOCK_TIME_SHIFT); mRequireRemoteWipe = 0 != (flags & LegacyPolicySet.REQUIRE_REMOTE_WIPE); mPasswordExpirationDays = (int) ((flags & LegacyPolicySet.PASSWORD_EXPIRATION_MASK) >> LegacyPolicySet.PASSWORD_EXPIRATION_SHIFT); mPasswordHistory = (int) ((flags & LegacyPolicySet.PASSWORD_HISTORY_MASK) >> LegacyPolicySet.PASSWORD_HISTORY_SHIFT); mPasswordComplexChars = (int) ((flags & LegacyPolicySet.PASSWORD_COMPLEX_CHARS_MASK) >> LegacyPolicySet.PASSWORD_COMPLEX_CHARS_SHIFT); mRequireEncryption = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION); mRequireEncryptionExternal = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION_EXTERNAL); } } }