SecurityPolicyTests.java revision f5418f1f93b02e7fab9f15eb201800b65510998e
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email;
18
19import com.android.email.provider.ContentCache;
20import com.android.email.provider.EmailProvider;
21import com.android.email.provider.ProviderTestUtils;
22import com.android.emailcommon.provider.Account;
23import com.android.emailcommon.provider.EmailContent;
24import com.android.emailcommon.provider.EmailContent.Message;
25import com.android.emailcommon.provider.Mailbox;
26import com.android.emailcommon.provider.Policy;
27import com.android.emailcommon.service.LegacyPolicySet;
28
29import android.app.admin.DevicePolicyManager;
30import android.content.Context;
31import android.content.ContextWrapper;
32import android.test.ProviderTestCase2;
33import android.test.suitebuilder.annotation.MediumTest;
34import android.test.suitebuilder.annotation.SmallTest;
35
36/**
37 * This is a series of unit tests for backup/restore of the SecurityPolicy class.
38 *
39 * You can run this entire test case with:
40 *   runtest -c com.android.email.SecurityPolicyTests email
41 */
42
43@MediumTest
44public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
45
46    private Context mMockContext;
47    private SecurityPolicy mSecurityPolicy;
48
49    public SecurityPolicyTests() {
50        super(EmailProvider.class, EmailContent.AUTHORITY);
51    }
52
53    private static final Policy EMPTY_POLICY = new Policy();
54
55    @Override
56    protected void setUp() throws Exception {
57        super.setUp();
58        mMockContext = new MockContext2(getMockContext(), mContext);
59        // Invalidate all caches, since we reset the database for each test
60        ContentCache.invalidateAllCachesForTest();
61    }
62
63    /**
64     * Delete any dummy accounts we set up for this test
65     */
66    @Override
67    protected void tearDown() throws Exception {
68        super.tearDown();
69    }
70
71    /**
72     * Private context wrapper used to add back getPackageName() for these tests.
73     *
74     * This class also implements {@link Context} method(s) that are called during tests.
75     */
76    private static class MockContext2 extends ContextWrapper {
77
78        private final Context mRealContext;
79
80        public MockContext2(Context mockContext, Context realContext) {
81            super(mockContext);
82            mRealContext = realContext;
83        }
84
85        @Override
86        public Context getApplicationContext() {
87            return this;
88        }
89
90        @Override
91        public String getPackageName() {
92            return mRealContext.getPackageName();
93        }
94
95        @Override
96        public Object getSystemService(String name) {
97            return mRealContext.getSystemService(name);
98        }
99    }
100
101    /**
102     * Create a Policy using the arguments formerly used to create a PolicySet; this minimizes the
103     * changes needed for re-using the PolicySet unit test logic
104     */
105    private Policy setupPolicy(int minPasswordLength, int passwordMode, int maxPasswordFails,
106            int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays,
107            int passwordHistory, int passwordComplexChars, boolean requireEncryption,
108            boolean requireEncryptionExternal) throws IllegalArgumentException {
109        Policy policy = new Policy();
110        policy.mPasswordMinLength = minPasswordLength;
111        policy.mPasswordMode = passwordMode;
112        policy.mPasswordMaxFails = maxPasswordFails;
113        policy.mMaxScreenLockTime = maxScreenLockTime;
114        policy.mRequireRemoteWipe = requireRemoteWipe;
115        policy.mPasswordExpirationDays = passwordExpirationDays;
116        policy.mPasswordHistory = passwordHistory;
117        policy.mPasswordComplexChars = passwordComplexChars;
118        policy.mRequireEncryption = requireEncryption;
119        policy.mRequireEncryptionExternal = requireEncryptionExternal;
120        return policy;
121    }
122
123    /**
124     * Test business logic of aggregating accounts with policies
125     */
126    public void testAggregator() {
127        mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
128
129        // with no accounts, should return empty set
130        assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy());
131
132        // with accounts having no security, empty set
133        ProviderTestUtils.setupAccount("no-sec-1", true, mMockContext);
134        ProviderTestUtils.setupAccount("no-sec-2", true, mMockContext);
135        assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy());
136
137        // with a single account in security mode, should return same security as in account
138        // first test with partially-populated policies
139        Account a3 = ProviderTestUtils.setupAccount("sec-3", true, mMockContext);
140        Policy p3ain = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
141                false, false);
142        Policy.setAccountPolicy(mMockContext, a3, p3ain, null);
143        Policy p3aout = mSecurityPolicy.computeAggregatePolicy();
144        assertNotNull(p3aout);
145        assertEquals(p3ain, p3aout);
146
147        // Repeat that test with fully-populated policies
148        Policy p3bin = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3,
149                false, false);
150        Policy.setAccountPolicy(mMockContext, a3, p3bin, null);
151        Policy p3bout = mSecurityPolicy.computeAggregatePolicy();
152        assertNotNull(p3bout);
153        assertEquals(p3bin, p3bout);
154
155        // add another account which mixes it up (some fields will change, others will not)
156        // pw length and pw mode - max logic - will change because larger #s here
157        // fail count and lock timer - min logic - will *not* change because larger #s here
158        // wipe required - OR logic - will *not* change here because false
159        // expiration - will not change because 0 (unspecified)
160        // max complex chars - max logic - will change
161        // encryption required - OR logic - will *not* change here because false
162        // encryption external req'd - OR logic - will *not* change here because false
163        Policy p4in = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7,
164                false, false);
165        Account a4 = ProviderTestUtils.setupAccount("sec-4", true, mMockContext);
166        Policy.setAccountPolicy(mMockContext, a4, p4in, null);
167        Policy p4out = mSecurityPolicy.computeAggregatePolicy();
168        assertNotNull(p4out);
169        assertEquals(20, p4out.mPasswordMinLength);
170        assertEquals(Policy.PASSWORD_MODE_STRONG, p4out.mPasswordMode);
171        assertEquals(15, p4out.mPasswordMaxFails);
172        assertEquals(16, p4out.mMaxScreenLockTime);
173        assertEquals(6, p4out.mPasswordExpirationDays);
174        assertEquals(5, p4out.mPasswordHistory);
175        assertEquals(7, p4out.mPasswordComplexChars);
176        assertFalse(p4out.mRequireRemoteWipe);
177        assertFalse(p4out.mRequireEncryption);
178        assertFalse(p4out.mRequireEncryptionExternal);
179
180        // add another account which mixes it up (the remaining fields will change)
181        // pw length and pw mode - max logic - will *not* change because smaller #s here
182        // fail count and lock timer - min logic - will change because smaller #s here
183        // wipe required - OR logic - will change here because true
184        // expiration time - min logic - will change because lower here
185        // history & complex chars - will not change because 0 (unspecified)
186        // encryption required - OR logic - will change here because true
187        // encryption external req'd - OR logic - will *not* change here because false
188        Policy p5in = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0,
189                true, false);
190        Account a5 = ProviderTestUtils.setupAccount("sec-5", true, mMockContext);
191        Policy.setAccountPolicy(mMockContext, a5, p5in, null);
192        Policy p5out = mSecurityPolicy.computeAggregatePolicy();
193        assertNotNull(p5out);
194        assertEquals(20, p5out.mPasswordMinLength);
195        assertEquals(Policy.PASSWORD_MODE_STRONG, p5out.mPasswordMode);
196        assertEquals(5, p5out.mPasswordMaxFails);
197        assertEquals(6, p5out.mMaxScreenLockTime);
198        assertEquals(1, p5out.mPasswordExpirationDays);
199        assertEquals(5, p5out.mPasswordHistory);
200        assertEquals(7, p5out.mPasswordComplexChars);
201        assertTrue(p5out.mRequireRemoteWipe);
202        assertFalse(p5out.mRequireEncryptionExternal);
203
204        // add another account that continues to mutate fields
205        // encryption external req'd - OR logic - will change here because true
206        Policy p6in = setupPolicy(0, Policy.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0,
207                false, true);
208        Account a6 = ProviderTestUtils.setupAccount("sec-6", true, mMockContext);
209        Policy.setAccountPolicy(mMockContext, a6, p6in, null);
210        Policy p6out = mSecurityPolicy.computeAggregatePolicy();
211        assertNotNull(p6out);
212        assertTrue(p6out.mRequireEncryptionExternal);
213    }
214
215    /**
216     * Test equality.  Note, the tests for inequality are poor, as each field should
217     * be tested individually.
218     */
219    @SmallTest
220    public void testEquals() {
221        Policy p1 =
222            setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
223        Policy p2 =
224            setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
225        Policy p3 =
226            setupPolicy(2, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false, false);
227        assertTrue(p1.equals(p2));
228        assertFalse(p2.equals(p3));
229    }
230
231    /**
232     * Test the API to set/clear policy hold flags in an account
233     */
234    public void testSetClearHoldFlag() {
235        Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext);
236        a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL;
237        a1.save(mMockContext);
238        Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext);
239        a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD;
240        a2.save(mMockContext);
241
242        // confirm clear until set
243        Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
244        assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags);
245        SecurityPolicy.setAccountHoldFlag(mMockContext, a1, true);
246        assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1.mFlags);
247        Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
248        assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1b.mFlags);
249
250        // confirm set until cleared
251        Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
252        assertEquals(Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD, a2a.mFlags);
253        SecurityPolicy.setAccountHoldFlag(mMockContext, a2, false);
254        assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2.mFlags);
255        Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
256        assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2b.mFlags);
257    }
258
259    private static class MockController extends Controller {
260        protected MockController(Context context) {
261            super(context);
262        }
263
264        protected void backupAccounts(Context context) {
265            // For testing, we don't want to back up our accounts
266        }
267    }
268
269    /**
270     * Test the response to disabling DeviceAdmin status
271     */
272    public void testDisableAdmin() {
273        Account a1 = ProviderTestUtils.setupAccount("disable-1", true, mMockContext);
274        Policy p1 = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
275                false, false);
276        Policy.setAccountPolicy(mMockContext, a1, p1, "security-sync-key-1");
277
278        Account a2 = ProviderTestUtils.setupAccount("disable-2", true, mMockContext);
279        Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
280                false, false);
281        Policy.setAccountPolicy(mMockContext, a2, p2, "security-sync-key-2");
282
283        Account a3 = ProviderTestUtils.setupAccount("disable-3", true, mMockContext);
284        Policy.clearAccountPolicy(mMockContext, a3);
285
286        mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
287
288        // Confirm that "enabling" device admin does not change security status (policy & sync key)
289        Policy before = mSecurityPolicy.getAggregatePolicy();
290        mSecurityPolicy.onAdminEnabled(true);        // "enabled" should not change anything
291        Policy after1 = mSecurityPolicy.getAggregatePolicy();
292        assertEquals(before, after1);
293        Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
294        assertNotNull(a1a.mSecuritySyncKey);
295        assertTrue(a1a.mPolicyKey > 0);
296        Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
297        assertNotNull(a2a.mSecuritySyncKey);
298        assertTrue(a2a.mPolicyKey > 0);
299        Account a3a = Account.restoreAccountWithId(mMockContext, a3.mId);
300        assertNull(a3a.mSecuritySyncKey);
301        assertTrue(a3a.mPolicyKey == 0);
302
303        // Simulate revoke of device admin; directly call deleteSecuredAccounts, which is normally
304        // called from a background thread
305        MockController mockController = new MockController(mMockContext);
306        Controller.injectMockControllerForTest(mockController);
307        try {
308            mSecurityPolicy.deleteSecuredAccounts(mMockContext);
309            Policy after2 = mSecurityPolicy.getAggregatePolicy();
310            assertEquals(EMPTY_POLICY, after2);
311            Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
312            assertNull(a1b);
313            Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
314            assertNull(a2b);
315            Account a3b = Account.restoreAccountWithId(mMockContext, a3.mId);
316            assertNull(a3b.mSecuritySyncKey);
317        } finally {
318            Controller.injectMockControllerForTest(null);
319        }
320    }
321
322    /**
323     * Test the scanner that finds expiring accounts
324     */
325    public void testFindExpiringAccount() {
326        ProviderTestUtils.setupAccount("expiring-1", true, mMockContext);
327
328        // With no expiring accounts, this should return null.
329        long nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
330        assertEquals(-1, nextExpiringAccountId);
331
332        // Add a single expiring account
333        Account a2 =
334            ProviderTestUtils.setupAccount("expiring-2", true, mMockContext);
335        Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
336                false, false);
337        Policy.setAccountPolicy(mMockContext, a2, p2, null);
338
339        // The expiring account should be returned
340        nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
341        assertEquals(a2.mId, nextExpiringAccountId);
342
343        // Add an account with a longer expiration
344        Account a3 = ProviderTestUtils.setupAccount("expiring-3", true, mMockContext);
345        Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0,
346                false, false);
347        Policy.setAccountPolicy(mMockContext, a3, p3, null);
348
349        // The original expiring account (a2) should be returned
350        nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
351        assertEquals(a2.mId, nextExpiringAccountId);
352
353        // Add an account with a shorter expiration
354        Account a4 = ProviderTestUtils.setupAccount("expiring-4", true, mMockContext);
355        Policy p4 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0,
356                false, false);
357        Policy.setAccountPolicy(mMockContext, a4, p4, null);
358
359        // The new expiring account (a4) should be returned
360        nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
361        assertEquals(a4.mId, nextExpiringAccountId);
362    }
363
364    /**
365     * Lightweight subclass of the Controller class allows injection of mock context
366     */
367    public static class TestController extends Controller {
368
369        protected TestController(Context providerContext, Context systemContext) {
370            super(systemContext);
371            setProviderContext(providerContext);
372        }
373    }
374
375    /**
376     * Test the scanner that wipes expiring accounts
377     */
378    public void testWipeExpiringAccounts() {
379        mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
380        TestController testController = new TestController(mMockContext, getContext());
381
382        // Two accounts - a1 is normal, a2 has security (but no expiration)
383        Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext);
384        Account a2 = ProviderTestUtils.setupAccount("expired-2", true, mMockContext);
385        Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
386                false, false);
387        Policy.setAccountPolicy(mMockContext, a2, p2, null);
388
389        // Add a mailbox & messages to each account
390        long account1Id = a1.mId;
391        long account2Id = a2.mId;
392        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
393        long box1Id = box1.mId;
394        ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mMockContext);
395        ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, true, mMockContext);
396        Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account2Id, true, mMockContext);
397        long box2Id = box2.mId;
398        ProviderTestUtils.setupMessage("message3", account2Id, box2Id, false, true, mMockContext);
399        ProviderTestUtils.setupMessage("message4", account2Id, box2Id, false, true, mMockContext);
400
401        // Run the expiration code - should do nothing
402        boolean wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController);
403        assertFalse(wiped);
404        // check mailboxes & messages not wiped
405        assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI));
406        assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
407        assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
408
409        // Add 3rd account that really expires
410        Account a3 = ProviderTestUtils.setupAccount("expired-3", true, mMockContext);
411        Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
412                false, false);
413        Policy.setAccountPolicy(mMockContext, a3, p3, null);
414
415        // Add mailbox & messages to 3rd account
416        long account3Id = a3.mId;
417        Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account3Id, true, mMockContext);
418        long box3Id = box3.mId;
419        ProviderTestUtils.setupMessage("message5", account3Id, box3Id, false, true, mMockContext);
420        ProviderTestUtils.setupMessage("message6", account3Id, box3Id, false, true, mMockContext);
421
422        // check new counts
423        assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
424        assertEquals(3, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
425        assertEquals(6, EmailContent.count(mMockContext, Message.CONTENT_URI));
426
427        // Run the expiration code - wipe acct #3
428        wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController);
429        assertTrue(wiped);
430        // check new counts - account survives but data is wiped
431        assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
432        assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
433        assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
434
435        // Check security hold states - only #3 should be in hold
436        Account account = Account.restoreAccountWithId(mMockContext, account1Id);
437        assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
438        account = Account.restoreAccountWithId(mMockContext, account2Id);
439        assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
440        account = Account.restoreAccountWithId(mMockContext, account3Id);
441        assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD);
442    }
443
444    /**
445     * Test the code that clears unsupported policies
446     * TODO inject a mock DPM so we can directly control & test all cases, no matter what device
447     */
448    public void testClearUnsupportedPolicies() {
449        Policy p1 =
450            setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
451        Policy p2 =
452            setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true, false);
453        Policy p3 =
454            setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, true);
455
456        mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
457        DevicePolicyManager dpm = mSecurityPolicy.getDPM();
458        boolean hasEncryption =
459            dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
460
461        Policy p1Result = mSecurityPolicy.clearUnsupportedPolicies(p1);
462        Policy p2Result = mSecurityPolicy.clearUnsupportedPolicies(p2);
463        Policy p3Result = mSecurityPolicy.clearUnsupportedPolicies(p3);
464
465        // No changes expected when encryptionRequested bits were false
466        assertEquals(p1, p1Result);
467        if (hasEncryption) {
468            // No changes expected
469            // NOTE:  TODO: Modify to check for external encryption cleared on devices that
470            // won't support it (e.g. having only unencrypted, removable storage.)
471            assertEquals(p2, p2Result);
472            assertEquals(p3, p3Result);
473        } else {
474            // If encryption is unsupported, encryption policy bits are cleared
475            Policy policyExpect =
476                setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false,
477                        false);
478            assertEquals(policyExpect, p2Result);
479            assertEquals(policyExpect, p3Result);
480        }
481    }
482
483    /**
484     * Test the code that converts from exchange-style quality to DPM/Lockscreen style quality.
485     */
486    public void testGetDPManagerPasswordQuality() {
487        // Policy.PASSWORD_MODE_NONE -> DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
488        Policy p1 = setupPolicy(0, Policy.PASSWORD_MODE_NONE,
489                0, 0, false, 0, 0, 0, false, false);
490        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
491                p1.getDPManagerPasswordQuality());
492
493        // PASSWORD_MODE_SIMPLE -> PASSWORD_QUALITY_NUMERIC
494        Policy p2 = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE,
495                0, 0, false, 0, 0, 0, false, false);
496        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
497                p2.getDPManagerPasswordQuality());
498
499        // PASSWORD_MODE_STRONG -> PASSWORD_QUALITY_ALPHANUMERIC
500        Policy p3 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG,
501                0, 0, false, 0, 0, 0, false, false);
502        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
503                p3.getDPManagerPasswordQuality());
504
505        // PASSWORD_MODE_STRONG + complex chars -> PASSWORD_QUALITY_COMPLEX
506        Policy p4 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG,
507                0, 0, false, 0, 0 , 2, false, false);
508        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX,
509                p4.getDPManagerPasswordQuality());
510    }
511
512    private boolean policySetEqualsPolicy(PolicySet ps, Policy policy) {
513        if ((ps.mPasswordMode >> LegacyPolicySet.PASSWORD_MODE_SHIFT) != policy.mPasswordMode) {
514            return false;
515        }
516        if (ps.mMinPasswordLength != policy.mPasswordMinLength) return false;
517        if (ps.mPasswordComplexChars != policy.mPasswordComplexChars) return false;
518        if (ps.mPasswordHistory != policy.mPasswordHistory) return false;
519        if (ps.mPasswordExpirationDays != policy.mPasswordExpirationDays) return false;
520        if (ps.mMaxPasswordFails != policy.mPasswordMaxFails) return false;
521        if (ps.mMaxScreenLockTime != policy.mMaxScreenLockTime) return false;
522        if (ps.mRequireRemoteWipe != policy.mRequireRemoteWipe) return false;
523        if (ps.mRequireEncryption != policy.mRequireEncryption) return false;
524        if (ps.mRequireEncryptionExternal != policy.mRequireEncryptionExternal) return false;
525        return true;
526    }
527
528    public void testPolicyFlagsToPolicy() {
529        // Policy flags; the three sets included here correspond to policies for three test
530        // accounts that, between them, use all of the possible policies
531        long flags = 67096612L;
532        PolicySet ps = new PolicySet(flags);
533        Policy policy = LegacyPolicySet.flagsToPolicy(flags);
534        assertTrue(policySetEqualsPolicy(ps, policy));
535        flags = 52776591691846L;
536        ps = new PolicySet(flags);
537        policy = LegacyPolicySet.flagsToPolicy(flags);
538        assertTrue(policySetEqualsPolicy(ps, policy));
539        flags = 1689605957029924L;
540        ps = new PolicySet(flags);
541        policy = LegacyPolicySet.flagsToPolicy(flags);
542        assertTrue(policySetEqualsPolicy(ps, policy));
543    }
544
545    /**
546     * The old PolicySet class fields and constructor; we use this to test conversion to the
547     * new Policy table scheme
548     */
549    private static class PolicySet {
550        private final int mMinPasswordLength;
551        private final int mPasswordMode;
552        private final int mMaxPasswordFails;
553        private final int mMaxScreenLockTime;
554        private final boolean mRequireRemoteWipe;
555        private final int mPasswordExpirationDays;
556        private final int mPasswordHistory;
557        private final int mPasswordComplexChars;
558        private final boolean mRequireEncryption;
559        private final boolean mRequireEncryptionExternal;
560
561        /**
562         * Create from values encoded in an account flags int
563         */
564        private PolicySet(long flags) {
565            mMinPasswordLength = (int) ((flags & LegacyPolicySet.PASSWORD_LENGTH_MASK)
566                    >> LegacyPolicySet.PASSWORD_LENGTH_SHIFT);
567            mPasswordMode =
568                (int) (flags & LegacyPolicySet.PASSWORD_MODE_MASK);
569            mMaxPasswordFails = (int) ((flags & LegacyPolicySet.PASSWORD_MAX_FAILS_MASK)
570                    >> LegacyPolicySet.PASSWORD_MAX_FAILS_SHIFT);
571            mMaxScreenLockTime = (int) ((flags & LegacyPolicySet.SCREEN_LOCK_TIME_MASK)
572                    >> LegacyPolicySet.SCREEN_LOCK_TIME_SHIFT);
573            mRequireRemoteWipe = 0 != (flags & LegacyPolicySet.REQUIRE_REMOTE_WIPE);
574            mPasswordExpirationDays = (int) ((flags & LegacyPolicySet.PASSWORD_EXPIRATION_MASK)
575                    >> LegacyPolicySet.PASSWORD_EXPIRATION_SHIFT);
576            mPasswordHistory = (int) ((flags & LegacyPolicySet.PASSWORD_HISTORY_MASK)
577                    >> LegacyPolicySet.PASSWORD_HISTORY_SHIFT);
578            mPasswordComplexChars = (int) ((flags & LegacyPolicySet.PASSWORD_COMPLEX_CHARS_MASK)
579                    >> LegacyPolicySet.PASSWORD_COMPLEX_CHARS_SHIFT);
580            mRequireEncryption = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION);
581            mRequireEncryptionExternal = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION_EXTERNAL);
582        }
583    }
584}
585