1aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank/*
2aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * Copyright (C) 2011 The Android Open Source Project
3aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank *
4aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * Licensed under the Apache License, Version 2.0 (the "License");
5aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * you may not use this file except in compliance with the License.
6aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * You may obtain a copy of the License at
7aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank *
8aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank *      http://www.apache.org/licenses/LICENSE-2.0
9aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank *
10aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * Unless required by applicable law or agreed to in writing, software
11aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * distributed under the License is distributed on an "AS IS" BASIS,
12aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * See the License for the specific language governing permissions and
14aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * limitations under the License.
15aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank */
16aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
17aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankpackage com.android.emailcommon.provider;
18aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.app.admin.DevicePolicyManager;
19aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.content.ContentProviderOperation;
20b2a909598ba78783b05c58508310f864c56c897bMarc Blankimport android.content.ContentResolver;
21aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.content.ContentUris;
22aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.content.ContentValues;
23aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.content.Context;
24aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.content.OperationApplicationException;
25aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.database.Cursor;
26aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.net.Uri;
27aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.os.Parcel;
28aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.os.Parcelable;
29aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.os.RemoteException;
30aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport android.util.Log;
31aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
32505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komaloimport com.android.emailcommon.utility.Utility;
33745b33b8ff55e9a9c4871f07f9d97db893f784b2Makoto Onukiimport com.google.common.annotations.VisibleForTesting;
34505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo
35aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport java.util.ArrayList;
36aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
37aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank/**
38aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * The Policy class represents a set of security requirements that are associated with an Account.
39aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * The requirements may be either device-specific (e.g. password) or application-specific (e.g.
40aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank * a limit on the sync window for the Account)
41aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank */
42aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankpublic final class Policy extends EmailContent implements EmailContent.PolicyColumns, Parcelable {
432bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank    public static final boolean DEBUG_POLICY = false;  // DO NOT SUBMIT WITH THIS SET TO TRUE
44aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final String TAG = "Email/Policy";
45aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
46aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final String TABLE_NAME = "Policy";
47aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @SuppressWarnings("hiding")
48aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/policy");
49aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
50aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /* Convert days to mSec (used for password expiration) */
51aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000;
52aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /* Small offset (2 minutes) added to policy expiration to make user testing easier. */
53aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    private static final long EXPIRATION_OFFSET_MSEC = 2 * 60 * 1000;
54aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
55aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int PASSWORD_MODE_NONE = 0;
56aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int PASSWORD_MODE_SIMPLE = 1;
57aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int PASSWORD_MODE_STRONG = 2;
58aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
59aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordMode;
60aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordMinLength;
61aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordMaxFails;
62aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordExpirationDays;
63aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordHistory;
64aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mPasswordComplexChars;
65aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int mMaxScreenLockTime;
66aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public boolean mRequireRemoteWipe;
67aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public boolean mRequireEncryption;
68aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public boolean mRequireEncryptionExternal;
69f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public boolean mRequireManualSyncWhenRoaming;
70f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public boolean mDontAllowCamera;
71f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public boolean mDontAllowAttachments;
72f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public boolean mDontAllowHtml;
73f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public int mMaxAttachmentSize;
74f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public int mMaxTextTruncationSize;
75f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public int mMaxHtmlTruncationSize;
76f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public int mMaxEmailLookback;
77f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public int mMaxCalendarLookback;
78f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public boolean mPasswordRecoveryEnabled;
79aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
80aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_ID_COLUMN = 0;
81aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_MODE_COLUMN = 1;
82aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_MIN_LENGTH_COLUMN = 2;
83aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_EXPIRATION_DAYS_COLUMN = 3;
84aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_HISTORY_COLUMN = 4;
85aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_COMPLEX_CHARS_COLUMN = 5;
86aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_PASSWORD_MAX_FAILS_COLUMN = 6;
87aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_MAX_SCREEN_LOCK_TIME_COLUMN = 7;
88aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_REQUIRE_REMOTE_WIPE_COLUMN = 8;
89aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_REQUIRE_ENCRYPTION_COLUMN = 9;
90aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final int CONTENT_REQUIRE_ENCRYPTION_EXTERNAL_COLUMN = 10;
91f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_REQUIRE_MANUAL_SYNC_WHEN_ROAMING = 11;
92f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_DONT_ALLOW_CAMERA_COLUMN = 12;
93f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_DONT_ALLOW_ATTACHMENTS_COLUMN = 13;
94f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_DONT_ALLOW_HTML_COLUMN = 14;
95f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_MAX_ATTACHMENT_SIZE_COLUMN = 15;
96f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_MAX_TEXT_TRUNCATION_SIZE_COLUMN = 16;
97f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_MAX_HTML_TRUNCATION_SIZE_COLUMN = 17;
98f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_MAX_EMAIL_LOOKBACK_COLUMN = 18;
99f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN = 19;
100f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank    public static final int CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN = 20;
101aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
102aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final String[] CONTENT_PROJECTION = new String[] {RECORD_ID,
103aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        PolicyColumns.PASSWORD_MODE, PolicyColumns.PASSWORD_MIN_LENGTH,
104aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        PolicyColumns.PASSWORD_EXPIRATION_DAYS, PolicyColumns.PASSWORD_HISTORY,
105aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        PolicyColumns.PASSWORD_COMPLEX_CHARS, PolicyColumns.PASSWORD_MAX_FAILS,
106aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        PolicyColumns.MAX_SCREEN_LOCK_TIME, PolicyColumns.REQUIRE_REMOTE_WIPE,
107f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.REQUIRE_ENCRYPTION, PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL,
108f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING, PolicyColumns.DONT_ALLOW_CAMERA,
109f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.DONT_ALLOW_ATTACHMENTS, PolicyColumns.DONT_ALLOW_HTML,
110f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.MAX_ATTACHMENT_SIZE, PolicyColumns.MAX_TEXT_TRUNCATION_SIZE,
111f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.MAX_HTML_TRUNCATION_SIZE, PolicyColumns.MAX_EMAIL_LOOKBACK,
112f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        PolicyColumns.MAX_CALENDAR_LOOKBACK, PolicyColumns.PASSWORD_RECOVERY_ENABLED
113aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    };
114aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
115aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final Policy NO_POLICY = new Policy();
116aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
117b2a909598ba78783b05c58508310f864c56c897bMarc Blank    private static final String[] ATTACHMENT_RESET_PROJECTION =
118b2a909598ba78783b05c58508310f864c56c897bMarc Blank        new String[] {EmailContent.RECORD_ID, AttachmentColumns.SIZE, AttachmentColumns.FLAGS};
119b2a909598ba78783b05c58508310f864c56c897bMarc Blank    private static final int ATTACHMENT_RESET_PROJECTION_ID = 0;
120b2a909598ba78783b05c58508310f864c56c897bMarc Blank    private static final int ATTACHMENT_RESET_PROJECTION_SIZE = 1;
121b2a909598ba78783b05c58508310f864c56c897bMarc Blank    private static final int ATTACHMENT_RESET_PROJECTION_FLAGS = 2;
122b2a909598ba78783b05c58508310f864c56c897bMarc Blank
123aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public Policy() {
124aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mBaseUri = CONTENT_URI;
125aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // By default, the password mode is "none"
126aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMode = PASSWORD_MODE_NONE;
127aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // All server policies require the ability to wipe the device
128aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireRemoteWipe = true;
129aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
130aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
131aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static Policy restorePolicyWithId(Context context, long id) {
132aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return EmailContent.restoreContentWithId(context, Policy.class, Policy.CONTENT_URI,
133aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                Policy.CONTENT_PROJECTION, id);
134aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
135aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
136aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static long getAccountIdWithPolicyKey(Context context, long id) {
137aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return Utility.getFirstRowLong(context, Account.CONTENT_URI, Account.ID_PROJECTION,
138aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                AccountColumns.POLICY_KEY + "=?", new String[] {Long.toString(id)}, null,
139505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo                Account.ID_PROJECTION_COLUMN, Account.NO_ACCOUNT);
140aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
141aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
142aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    // We override this method to insure that we never write invalid policy data to the provider
143d09cff08882e553afce919865a2cc60b657d4659Ben Komalo    @Override
144aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public Uri save(Context context) {
145aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        normalize();
146aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return super.save(context);
147aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
148aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
149505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo    public static void clearAccountPolicy(Context context, Account account) {
150fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank        setAccountPolicy(context, account, null, null);
151fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank    }
152fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank
153aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
154505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo     * Convenience method for {@link #setAccountPolicy(Context, Account, Policy, String)}.
155505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo     */
156745b33b8ff55e9a9c4871f07f9d97db893f784b2Makoto Onuki    @VisibleForTesting
157505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo    public static void setAccountPolicy(Context context, long accountId, Policy policy,
158505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo            String securitySyncKey) {
159505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo        setAccountPolicy(context, Account.restoreAccountWithId(context, accountId),
160505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo                policy, securitySyncKey);
161505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo    }
162505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo
163505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo    /**
164fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank     * Set the policy for an account atomically; this also removes any other policy associated with
165fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank     * the account and sets the policy key for the account.  If policy is null, the policyKey is
166b169192c8a59f8b61b019c80fda2183194ac5c00Marc Blank     * set to 0 and the securitySyncKey to null.  Also, update the account object to reflect the
167b169192c8a59f8b61b019c80fda2183194ac5c00Marc Blank     * current policyKey and securitySyncKey
168aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * @param context the caller's context
169aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * @param account the account whose policy is to be set
170fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank     * @param policy the policy to set, or null if we're clearing the policy
171fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank     * @param securitySyncKey the security sync key for this account (ignored if policy is null)
172aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
173505ac4b09bbe13ff099e40d94e45963e46a9261fBen Komalo    public static void setAccountPolicy(Context context, Account account, Policy policy,
174fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            String securitySyncKey) {
175aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (DEBUG_POLICY) {
176fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            Log.d(TAG, "Set policy for account " + account.mDisplayName + ": " +
177fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    ((policy == null) ? "none" : policy.toString()));
178aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
179aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
180aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
181fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank        // Make sure this is a valid policy set
182fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank        if (policy != null) {
183fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            policy.normalize();
184fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            // Add the new policy (no account will yet reference this)
185fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            ops.add(ContentProviderOperation.newInsert(
186fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    Policy.CONTENT_URI).withValues(policy.toContentValues()).build());
187fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            // Make the policyKey of the account our newly created policy, and set the sync key
188fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            ops.add(ContentProviderOperation.newUpdate(
189fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    ContentUris.withAppendedId(Account.CONTENT_URI, account.mId))
190fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .withValueBackReference(AccountColumns.POLICY_KEY, 0)
191fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .withValue(AccountColumns.SECURITY_SYNC_KEY, securitySyncKey)
192fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .build());
193fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank        } else {
194fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank            ops.add(ContentProviderOperation.newUpdate(
195fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    ContentUris.withAppendedId(Account.CONTENT_URI, account.mId))
196fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .withValue(AccountColumns.SECURITY_SYNC_KEY, null)
197fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .withValue(AccountColumns.POLICY_KEY, 0)
198fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    .build());
199aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
200fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank
201aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // Delete the previous policy associated with this account, if any
202aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (account.mPolicyKey > 0) {
203aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            ops.add(ContentProviderOperation.newDelete(
204fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                    ContentUris.withAppendedId(
205fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank                            Policy.CONTENT_URI, account.mPolicyKey)).build());
206aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
207fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank
208aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        try {
209aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops);
210b169192c8a59f8b61b019c80fda2183194ac5c00Marc Blank            account.refresh(context);
211aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        } catch (RemoteException e) {
212fae5ebbfd202b930296a1bbc67459152f1a6c6ceMarc Blank           // This is fatal to a remote process
213aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            throw new IllegalStateException("Exception setting account policy.");
214aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        } catch (OperationApplicationException e) {
215aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            // Can't happen; our provider doesn't throw this exception
216aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
217aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
218aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
219b2a909598ba78783b05c58508310f864c56c897bMarc Blank    /**
220b2a909598ba78783b05c58508310f864c56c897bMarc Blank     * Review all attachment records for this account, and reset the "don't allow download" flag
221b2a909598ba78783b05c58508310f864c56c897bMarc Blank     * as required by the account's new security policies
222b2a909598ba78783b05c58508310f864c56c897bMarc Blank     * @param context the caller's context
223b2a909598ba78783b05c58508310f864c56c897bMarc Blank     * @param account the account whose attachments need to be reviewed
224b2a909598ba78783b05c58508310f864c56c897bMarc Blank     * @param policy the new policy for this account
225b2a909598ba78783b05c58508310f864c56c897bMarc Blank     */
226b2a909598ba78783b05c58508310f864c56c897bMarc Blank    public static void setAttachmentFlagsForNewPolicy(Context context, Account account,
227b2a909598ba78783b05c58508310f864c56c897bMarc Blank            Policy policy) {
228b2a909598ba78783b05c58508310f864c56c897bMarc Blank        // A nasty bit of work; start with all attachments for a given account
229b2a909598ba78783b05c58508310f864c56c897bMarc Blank        ContentResolver resolver = context.getContentResolver();
230b2a909598ba78783b05c58508310f864c56c897bMarc Blank        Cursor c = resolver.query(Attachment.CONTENT_URI, ATTACHMENT_RESET_PROJECTION,
231b2a909598ba78783b05c58508310f864c56c897bMarc Blank                AttachmentColumns.ACCOUNT_KEY + "=?", new String[] {Long.toString(account.mId)},
232b2a909598ba78783b05c58508310f864c56c897bMarc Blank                null);
233b2a909598ba78783b05c58508310f864c56c897bMarc Blank        ContentValues cv = new ContentValues();
234b2a909598ba78783b05c58508310f864c56c897bMarc Blank        try {
235b2a909598ba78783b05c58508310f864c56c897bMarc Blank            // Get maximum allowed size (0 if we don't allow attachments at all)
236b2a909598ba78783b05c58508310f864c56c897bMarc Blank            int policyMax = policy.mDontAllowAttachments ? 0 : (policy.mMaxAttachmentSize > 0) ?
237b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    policy.mMaxAttachmentSize : Integer.MAX_VALUE;
238b2a909598ba78783b05c58508310f864c56c897bMarc Blank            while (c.moveToNext()) {
239b2a909598ba78783b05c58508310f864c56c897bMarc Blank                int flags = c.getInt(ATTACHMENT_RESET_PROJECTION_FLAGS);
240b2a909598ba78783b05c58508310f864c56c897bMarc Blank                int size = c.getInt(ATTACHMENT_RESET_PROJECTION_SIZE);
241b2a909598ba78783b05c58508310f864c56c897bMarc Blank                boolean wasRestricted = (flags & Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD) != 0;
242b2a909598ba78783b05c58508310f864c56c897bMarc Blank                boolean isRestricted = size > policyMax;
243b2a909598ba78783b05c58508310f864c56c897bMarc Blank                if (isRestricted != wasRestricted) {
244b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    if (isRestricted) {
245b2a909598ba78783b05c58508310f864c56c897bMarc Blank                        flags |= Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD;
246b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    } else {
247b2a909598ba78783b05c58508310f864c56c897bMarc Blank                        flags &= ~Attachment.FLAG_POLICY_DISALLOWS_DOWNLOAD;
248b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    }
249b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    long id = c.getLong(ATTACHMENT_RESET_PROJECTION_ID);
250b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    cv.put(AttachmentColumns.FLAGS, flags);
251b2a909598ba78783b05c58508310f864c56c897bMarc Blank                    resolver.update(ContentUris.withAppendedId(Attachment.CONTENT_URI, id),
252b2a909598ba78783b05c58508310f864c56c897bMarc Blank                            cv, null, null);
253b2a909598ba78783b05c58508310f864c56c897bMarc Blank                }
254b2a909598ba78783b05c58508310f864c56c897bMarc Blank            }
255b2a909598ba78783b05c58508310f864c56c897bMarc Blank        } finally {
256b2a909598ba78783b05c58508310f864c56c897bMarc Blank            c.close();
257b2a909598ba78783b05c58508310f864c56c897bMarc Blank        }
258b2a909598ba78783b05c58508310f864c56c897bMarc Blank    }
259b2a909598ba78783b05c58508310f864c56c897bMarc Blank
260aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
261aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Normalize the Policy.  If the password mode is "none", zero out all password-related fields;
262aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * zero out complex characters for simple passwords.
263aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
264aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public void normalize() {
265aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordMode == PASSWORD_MODE_NONE) {
266aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mPasswordMaxFails = 0;
267aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mMaxScreenLockTime = 0;
268aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mPasswordMinLength = 0;
269aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mPasswordComplexChars = 0;
270aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mPasswordHistory = 0;
271aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            mPasswordExpirationDays = 0;
272aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        } else {
273aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            if ((mPasswordMode != PASSWORD_MODE_SIMPLE) &&
274aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                    (mPasswordMode != PASSWORD_MODE_STRONG)) {
275aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                throw new IllegalArgumentException("password mode");
276aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            }
277aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            // If we're only requiring a simple password, set complex chars to zero; note
278aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            // that EAS can erroneously send non-zero values in this case
279aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            if (mPasswordMode == PASSWORD_MODE_SIMPLE) {
280aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                mPasswordComplexChars = 0;
281aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            }
282aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
283aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
284aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
285aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
286aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public boolean equals(Object other) {
287aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (!(other instanceof Policy)) return false;
288aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        Policy otherPolicy = (Policy)other;
289aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mRequireEncryption != otherPolicy.mRequireEncryption) return false;
290aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mRequireEncryptionExternal != otherPolicy.mRequireEncryptionExternal) return false;
291aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mRequireRemoteWipe != otherPolicy.mRequireRemoteWipe) return false;
292aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mMaxScreenLockTime != otherPolicy.mMaxScreenLockTime) return false;
293aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordComplexChars != otherPolicy.mPasswordComplexChars) return false;
294aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordExpirationDays != otherPolicy.mPasswordExpirationDays) return false;
295aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordHistory != otherPolicy.mPasswordHistory) return false;
296aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordMaxFails != otherPolicy.mPasswordMaxFails) return false;
297aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordMinLength != otherPolicy.mPasswordMinLength) return false;
298aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (mPasswordMode != otherPolicy.mPasswordMode) return false;
299f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mRequireManualSyncWhenRoaming != otherPolicy.mRequireManualSyncWhenRoaming) {
300f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank            return false;
301f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        }
302f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mDontAllowCamera != otherPolicy.mDontAllowCamera) return false;
303f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mDontAllowAttachments != otherPolicy.mDontAllowAttachments) return false;
304f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mDontAllowHtml != otherPolicy.mDontAllowHtml) return false;
305f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mMaxAttachmentSize != otherPolicy.mMaxAttachmentSize) return false;
306f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mMaxTextTruncationSize != otherPolicy.mMaxTextTruncationSize) return false;
307f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mMaxHtmlTruncationSize != otherPolicy.mMaxHtmlTruncationSize) return false;
308f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mMaxEmailLookback != otherPolicy.mMaxEmailLookback) return false;
309f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mMaxCalendarLookback != otherPolicy.mMaxCalendarLookback) return false;
310f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        if (mPasswordRecoveryEnabled != otherPolicy.mPasswordRecoveryEnabled) return false;
311aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return true;
312aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
313aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
314aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
315aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int hashCode() {
316aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        int code = mRequireEncryption ? 1 : 0;
317aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mRequireEncryptionExternal ? 1 : 0) << 1;
318aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mRequireRemoteWipe ? 1 : 0) << 2;
319aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mMaxScreenLockTime << 3);
320aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordComplexChars << 6);
321aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordExpirationDays << 12);
322aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordHistory << 15);
323aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordMaxFails << 18);
324aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordMinLength << 22);
325aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        code += (mPasswordMode << 26);
326f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        // Don't need to include the other fields
327aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return code;
328aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
329aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
330aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
331aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public void restore(Cursor cursor) {
332aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mBaseUri = CONTENT_URI;
333aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mId = cursor.getLong(CONTENT_ID_COLUMN);
334aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMode = cursor.getInt(CONTENT_PASSWORD_MODE_COLUMN);
335aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMinLength = cursor.getInt(CONTENT_PASSWORD_MIN_LENGTH_COLUMN);
336aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMaxFails = cursor.getInt(CONTENT_PASSWORD_MAX_FAILS_COLUMN);
337aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordHistory = cursor.getInt(CONTENT_PASSWORD_HISTORY_COLUMN);
338aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordExpirationDays = cursor.getInt(CONTENT_PASSWORD_EXPIRATION_DAYS_COLUMN);
339aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordComplexChars = cursor.getInt(CONTENT_PASSWORD_COMPLEX_CHARS_COLUMN);
340aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mMaxScreenLockTime = cursor.getInt(CONTENT_MAX_SCREEN_LOCK_TIME_COLUMN);
341aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireRemoteWipe = cursor.getInt(CONTENT_REQUIRE_REMOTE_WIPE_COLUMN) == 1;
342aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireEncryption = cursor.getInt(CONTENT_REQUIRE_ENCRYPTION_COLUMN) == 1;
343aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireEncryptionExternal =
344aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            cursor.getInt(CONTENT_REQUIRE_ENCRYPTION_EXTERNAL_COLUMN) == 1;
345f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mRequireManualSyncWhenRoaming =
346f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank            cursor.getInt(CONTENT_REQUIRE_MANUAL_SYNC_WHEN_ROAMING) == 1;
347f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowCamera = cursor.getInt(CONTENT_DONT_ALLOW_CAMERA_COLUMN) == 1;
348f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowAttachments = cursor.getInt(CONTENT_DONT_ALLOW_ATTACHMENTS_COLUMN) == 1;
349f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowHtml = cursor.getInt(CONTENT_DONT_ALLOW_HTML_COLUMN) == 1;
350f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxAttachmentSize = cursor.getInt(CONTENT_MAX_ATTACHMENT_SIZE_COLUMN);
351f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxTextTruncationSize = cursor.getInt(CONTENT_MAX_TEXT_TRUNCATION_SIZE_COLUMN);
352f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxHtmlTruncationSize = cursor.getInt(CONTENT_MAX_HTML_TRUNCATION_SIZE_COLUMN);
353f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxEmailLookback = cursor.getInt(CONTENT_MAX_EMAIL_LOOKBACK_COLUMN);
354f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxCalendarLookback = cursor.getInt(CONTENT_MAX_CALENDAR_LOOKBACK_COLUMN);
355f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mPasswordRecoveryEnabled = cursor.getInt(CONTENT_PASSWORD_RECOVERY_ENABLED_COLUMN) == 1;
356aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
357aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
358aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
359aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public ContentValues toContentValues() {
360aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        ContentValues values = new ContentValues();
361aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_MODE, mPasswordMode);
362aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_MIN_LENGTH, mPasswordMinLength);
363aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_MAX_FAILS, mPasswordMaxFails);
364aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_HISTORY, mPasswordHistory);
365aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_EXPIRATION_DAYS, mPasswordExpirationDays);
366aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.PASSWORD_COMPLEX_CHARS, mPasswordComplexChars);
367aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.MAX_SCREEN_LOCK_TIME, mMaxScreenLockTime);
368aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.REQUIRE_REMOTE_WIPE, mRequireRemoteWipe);
369aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.REQUIRE_ENCRYPTION, mRequireEncryption);
370aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        values.put(PolicyColumns.REQUIRE_ENCRYPTION_EXTERNAL, mRequireEncryptionExternal);
371f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.REQUIRE_MANUAL_SYNC_WHEN_ROAMING, mRequireManualSyncWhenRoaming);
372f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.DONT_ALLOW_CAMERA, mDontAllowCamera);
373f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.DONT_ALLOW_ATTACHMENTS, mDontAllowAttachments);
374f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.DONT_ALLOW_HTML, mDontAllowHtml);
375f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.MAX_ATTACHMENT_SIZE, mMaxAttachmentSize);
376f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.MAX_TEXT_TRUNCATION_SIZE, mMaxTextTruncationSize);
377f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.MAX_HTML_TRUNCATION_SIZE, mMaxHtmlTruncationSize);
378f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.MAX_EMAIL_LOOKBACK, mMaxEmailLookback);
379f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.MAX_CALENDAR_LOOKBACK, mMaxCalendarLookback);
380f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        values.put(PolicyColumns.PASSWORD_RECOVERY_ENABLED, mPasswordRecoveryEnabled);
381aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return values;
382aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
383aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
384aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
385aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Helper to map our internal encoding to DevicePolicyManager password modes.
386aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
387aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int getDPManagerPasswordQuality() {
388aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        switch (mPasswordMode) {
389aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            case PASSWORD_MODE_SIMPLE:
390aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
391aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            case PASSWORD_MODE_STRONG:
392aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                if (mPasswordComplexChars == 0) {
393aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                    return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
394aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                } else {
395aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                    return DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
396aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                }
397aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            default:
398aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                return DevicePolicyManager .PASSWORD_QUALITY_UNSPECIFIED;
399aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
400aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
401aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
402aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
403aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Helper to map expiration times to the millisecond values used by DevicePolicyManager.
404aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
405aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public long getDPManagerPasswordExpirationTimeout() {
406aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        long result = mPasswordExpirationDays * DAYS_TO_MSEC;
407aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // Add a small offset to the password expiration.  This makes it easier to test
408aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // by changing (for example) 1 day to 1 day + 5 minutes.  If you set an expiration
409aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // that is within the warning period, you should get a warning fairly quickly.
410aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        if (result > 0) {
411aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            result += EXPIRATION_OFFSET_MSEC;
412aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
413aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return result;
414aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
415aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
416aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    private void appendPolicy(StringBuilder sb, String code, int value) {
417aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        sb.append(code);
418aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        sb.append(":");
419aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        sb.append(value);
420aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        sb.append(" ");
421aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
422aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
423d09cff08882e553afce919865a2cc60b657d4659Ben Komalo    @Override
424aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public String toString() {
425aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        StringBuilder sb = new StringBuilder("[");
426d09cff08882e553afce919865a2cc60b657d4659Ben Komalo        if (equals(NO_POLICY)) {
427aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            sb.append("No policies]");
428aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        } else {
429aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            if (mPasswordMode == PASSWORD_MODE_NONE) {
43071c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("Pwd none ");
431aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            } else {
432aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "Pwd strong", mPasswordMode == PASSWORD_MODE_STRONG ? 1 : 0);
433aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "len", mPasswordMinLength);
434aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "cmpx", mPasswordComplexChars);
435aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "expy", mPasswordExpirationDays);
436aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "hist", mPasswordHistory);
437aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "fail", mPasswordMaxFails);
438aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank                appendPolicy(sb, "idle", mMaxScreenLockTime);
439aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            }
44071c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mRequireEncryption) {
44171c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("encrypt ");
44271c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
44371c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mRequireEncryptionExternal) {
44471c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("encryptsd ");
44571c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
44671c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mDontAllowCamera) {
44771c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("nocamera ");
44871c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
44971c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mDontAllowAttachments) {
45071c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("noatts ");
45171c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
45271c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mRequireManualSyncWhenRoaming) {
45371c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                sb.append("nopushroam ");
45471c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
45571c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            if (mMaxAttachmentSize > 0) {
45671c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank                appendPolicy(sb, "attmax", mMaxAttachmentSize);
45771c9683087c348a117a6dd9c6f6eab96cbc46139Marc Blank            }
458aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            sb.append("]");
459aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
460aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return sb.toString();
461aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
462aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
463aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
464aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Supports Parcelable
465aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
466aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
467aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public int describeContents() {
468aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        return 0;
469aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
470aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
471aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
472aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Supports Parcelable
473aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
474aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
475aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        public Policy createFromParcel(Parcel in) {
476aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            return new Policy(in);
477aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
478aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
479aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        public Policy[] newArray(int size) {
480aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank            return new Policy[size];
481aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        }
482aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    };
483aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
484aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
485aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Supports Parcelable
486aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
487aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    @Override
488aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public void writeToParcel(Parcel dest, int flags) {
489aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        // mBaseUri is not parceled
490aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeLong(mId);
491aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordMode);
492aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordMinLength);
493aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordMaxFails);
494aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordHistory);
495aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordExpirationDays);
496aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mPasswordComplexChars);
497aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mMaxScreenLockTime);
498aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mRequireRemoteWipe ? 1 : 0);
499aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mRequireEncryption ? 1 : 0);
500aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        dest.writeInt(mRequireEncryptionExternal ? 1 : 0);
501f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mRequireManualSyncWhenRoaming ? 1 : 0);
502f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mDontAllowCamera ? 1 : 0);
503f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mDontAllowAttachments ? 1 : 0);
504f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mDontAllowHtml ? 1 : 0);
505f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mMaxAttachmentSize);
506f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mMaxTextTruncationSize);
507f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mMaxHtmlTruncationSize);
508f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mMaxEmailLookback);
509f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mMaxCalendarLookback);
510f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        dest.writeInt(mPasswordRecoveryEnabled ? 1 : 0);
511aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
512aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank
513aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    /**
514aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     * Supports Parcelable
515aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank     */
516aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    public Policy(Parcel in) {
517aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mBaseUri = CONTENT_URI;
518aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mId = in.readLong();
519aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMode = in.readInt();
520aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMinLength = in.readInt();
521aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordMaxFails = in.readInt();
522aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordHistory = in.readInt();
523aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordExpirationDays = in.readInt();
524aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mPasswordComplexChars = in.readInt();
525aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mMaxScreenLockTime = in.readInt();
526aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireRemoteWipe = in.readInt() == 1;
527aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireEncryption = in.readInt() == 1;
528aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank        mRequireEncryptionExternal = in.readInt() == 1;
529f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mRequireManualSyncWhenRoaming = in.readInt() == 1;
530f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowCamera = in.readInt() == 1;
531f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowAttachments = in.readInt() == 1;
532f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mDontAllowHtml = in.readInt() == 1;
533f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxAttachmentSize = in.readInt();
534f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxTextTruncationSize = in.readInt();
535f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxHtmlTruncationSize = in.readInt();
536f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxEmailLookback = in.readInt();
537f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mMaxCalendarLookback = in.readInt();
538f91a03f5203bb64ae0726596d65ac90c35088666Marc Blank        mPasswordRecoveryEnabled = in.readInt() == 1;
539aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank    }
540aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank}