SecurityPolicy.java revision 5893e9e008d46cf4be0c7f709a6e77e2652c3ddd
1345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler/*
2345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * Copyright (C) 2010 The Android Open Source Project
3345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler *
4345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License");
5345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * you may not use this file except in compliance with the License.
6345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * You may obtain a copy of the License at
7345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler *
8345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler *      http://www.apache.org/licenses/LICENSE-2.0
9345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler *
10345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * Unless required by applicable law or agreed to in writing, software
11345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS,
12345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * See the License for the specific language governing permissions and
14345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * limitations under the License.
15345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler */
16345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
17345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerpackage com.android.email;
18345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
193d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport com.android.email.activity.setup.AccountSecurity;
203d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport com.android.email.provider.EmailContent;
21345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerimport com.android.email.provider.EmailContent.Account;
223d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport com.android.email.provider.EmailContent.AccountColumns;
233d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport com.android.email.service.MailService;
24345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
25345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerimport android.app.DeviceAdmin;
26d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadlerimport android.app.DevicePolicyManager;
273d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport android.app.Notification;
283d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport android.app.NotificationManager;
293d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport android.app.PendingIntent;
30d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadlerimport android.content.ComponentName;
312a5eeea9213005060256054ec773e72406415ce4Andrew Stadlerimport android.content.ContentResolver;
322a5eeea9213005060256054ec773e72406415ce4Andrew Stadlerimport android.content.ContentUris;
333d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport android.content.ContentValues;
34345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerimport android.content.Context;
35345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerimport android.content.Intent;
36345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerimport android.database.Cursor;
373d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadlerimport android.net.Uri;
38345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
39345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler/**
40345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler * Utility functions to support reading and writing security policies
413d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler *
423d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler * STOPSHIP - these TODO items are all part of finishing the feature
433d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler * TODO: When accounts are deleted, reduce policy and/or give up admin status
443d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler * TODO: Provide a way to check for policy issues at synchronous times such as entering
453d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler *       message list or folder list.
46345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler */
47345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadlerpublic class SecurityPolicy {
48345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
49d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    /** STOPSHIP - ok to check in true for now, but must be false for shipping */
50d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    /** DO NOT CHECK IN WHILE 'true' */
5109b45fdcffd7fc4e5ef2ac498576d713eaf2c3dbMarc Blank    // Until everything is connected, allow syncs to work
522a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    private static final boolean DEBUG_ALWAYS_ACTIVE = false;
53d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
54345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private static SecurityPolicy sInstance = null;
55345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private Context mContext;
56d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    private DevicePolicyManager mDPM;
57d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    private ComponentName mAdminName;
58d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    private PolicySet mAggregatePolicy;
593d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    private boolean mNotificationActive;
603d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    private boolean mAdminEnabled;
61d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
62d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    private static final PolicySet NO_POLICY_SET =
63d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false);
64345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
65345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
66345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * This projection on Account is for scanning/reading
67345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
68345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private static final String[] ACCOUNT_SECURITY_PROJECTION = new String[] {
692a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        AccountColumns.ID, AccountColumns.SECURITY_FLAGS
70345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    };
71345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private static final int ACCOUNT_SECURITY_COLUMN_FLAGS = 1;
72345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    // Note, this handles the NULL case to deal with older accounts where the column was added
73345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private static final String WHERE_ACCOUNT_SECURITY_NONZERO =
74345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        Account.SECURITY_FLAGS + " IS NOT NULL AND " + Account.SECURITY_FLAGS + "!=0";
75345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
762a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    /**
772a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * This projection on Account is for clearing the "security hold" column.  Also includes
782a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * the security flags column, so we can use it for selecting.
792a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     */
802a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    private static final String[] ACCOUNT_FLAGS_PROJECTION = new String[] {
812a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        AccountColumns.ID, AccountColumns.FLAGS, AccountColumns.SECURITY_FLAGS
822a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    };
832a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    private static final int ACCOUNT_FLAGS_COLUMN_ID = 0;
842a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    private static final int ACCOUNT_FLAGS_COLUMN_FLAGS = 1;
852a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
86d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler   /**
87d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    * These are hardcoded limits based on knowledge of the current DevicePolicyManager
88d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    * and screen lock mechanisms.  Wherever possible, these should be replaced with queries of
89d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    * dynamic capabilities of the device (e.g. what password modes are supported?)
90d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    */
91d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler   private static final int LIMIT_MIN_PASSWORD_LENGTH = 16;
92d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler   private static final int LIMIT_PASSWORD_MODE = PolicySet.PASSWORD_MODE_STRONG;
93d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler   private static final int LIMIT_SCREENLOCK_TIME = PolicySet.SCREEN_LOCK_TIME_MAX;
94d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
95345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
96345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * Get the security policy instance
97345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
98345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    public synchronized static SecurityPolicy getInstance(Context context) {
99345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        if (sInstance == null) {
100345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            sInstance = new SecurityPolicy(context);
101345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
102345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        return sInstance;
103345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
104345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
105345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
106345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * Private constructor (one time only)
107345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
108345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    private SecurityPolicy(Context context) {
109345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        mContext = context;
110d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        mDPM = null;
111d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        mAdminName = new ComponentName(context, PolicyAdmin.class);
112d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        mAggregatePolicy = null;
1133d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        mNotificationActive = false;
114345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
115345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
116345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
117345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * For testing only: Inject context into already-created instance
118345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
119345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /* package */ void setContext(Context context) {
120345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        mContext = context;
121345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
122345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
123345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
124345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * Compute the aggregate policy for all accounts that require it, and record it.
125345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
126345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * The business logic is as follows:
127345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *  min password length         take the max
128345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *  password mode               take the max (strongest mode)
129345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *  max password fails          take the min
130345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *  max screen lock time        take the min
131345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *  require remote wipe         take the max (logical or)
132345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
133d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * @return a policy representing the strongest aggregate.  If no policy sets are defined,
134d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * a lightweight "nothing required" policy will be returned.  Never null.
135345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
136345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /* package */ PolicySet computeAggregatePolicy() {
137345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        boolean policiesFound = false;
138345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
139345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        int minPasswordLength = Integer.MIN_VALUE;
140345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        int passwordMode = Integer.MIN_VALUE;
141345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        int maxPasswordFails = Integer.MAX_VALUE;
142345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        int maxScreenLockTime = Integer.MAX_VALUE;
143345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        boolean requireRemoteWipe = false;
144345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
145345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        Cursor c = mContext.getContentResolver().query(Account.CONTENT_URI,
146345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                ACCOUNT_SECURITY_PROJECTION, WHERE_ACCOUNT_SECURITY_NONZERO, null, null);
147345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        try {
148345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            while (c.moveToNext()) {
149345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                int flags = c.getInt(ACCOUNT_SECURITY_COLUMN_FLAGS);
150345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                if (flags != 0) {
151345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    PolicySet p = new PolicySet(flags);
1523d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    minPasswordLength = Math.max(p.mMinPasswordLength, minPasswordLength);
1533d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    passwordMode  = Math.max(p.mPasswordMode, passwordMode);
154345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    if (p.mMaxPasswordFails > 0) {
155345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        maxPasswordFails = Math.min(p.mMaxPasswordFails, maxPasswordFails);
156345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    }
157345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    if (p.mMaxScreenLockTime > 0) {
158345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        maxScreenLockTime = Math.min(p.mMaxScreenLockTime, maxScreenLockTime);
159345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    }
160345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    requireRemoteWipe |= p.mRequireRemoteWipe;
161345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    policiesFound = true;
162345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                }
163345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
164345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        } finally {
165345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            c.close();
166345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
167345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        if (policiesFound) {
1683d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // final cleanup pass converts any untouched min/max values to zero (not specified)
1693d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (minPasswordLength == Integer.MIN_VALUE) minPasswordLength = 0;
1703d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (passwordMode == Integer.MIN_VALUE) passwordMode = 0;
1713d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (maxPasswordFails == Integer.MAX_VALUE) maxPasswordFails = 0;
1723d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (maxScreenLockTime == Integer.MAX_VALUE) maxScreenLockTime = 0;
1733d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
174345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            return new PolicySet(minPasswordLength, passwordMode, maxPasswordFails,
175345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    maxScreenLockTime, requireRemoteWipe);
176345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        } else {
177d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            return NO_POLICY_SET;
178345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
179345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
180345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
181345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
182d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * Get the dpm.  This mainly allows us to make some utility calls without it, for testing.
183d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     */
184d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    private synchronized DevicePolicyManager getDPM() {
185d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        if (mDPM == null) {
186d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            mDPM = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
187d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
188d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        return mDPM;
189d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    }
190d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
191d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    /**
192d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * API: Query used to determine if a given policy is "possible" (irrespective of current
193345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * device state.  This is used when creating new accounts.
194345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
195d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * TODO: This is hardcoded based on knowledge of the current DevicePolicyManager
196d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * and screen lock mechanisms.  It would be nice to replace these tests with something
197d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * more dynamic.
198345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
199345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * @param policies the policies requested
200345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * @return true if the policies are supported, false if not supported
201345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
202345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    public boolean isSupported(PolicySet policies) {
203d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        if (policies.mMinPasswordLength > LIMIT_MIN_PASSWORD_LENGTH) {
204d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            return false;
205d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
206d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        if (policies.mPasswordMode > LIMIT_PASSWORD_MODE ) {
207d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            return false;
208d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
209d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        // No limit on password fail count
210d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        if (policies.mMaxScreenLockTime > LIMIT_SCREENLOCK_TIME ) {
211d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            return false;
212d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
213d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        // No limit on remote wipe capable
214d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
215345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        return true;
216345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
217345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
218345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
219d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * API: Report that policies may have been updated due to rewriting values in an Account.
2203d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * @param accountId the account that has been updated
221d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     */
2223d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public synchronized void updatePolicies(long accountId) {
223d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        mAggregatePolicy = null;
224d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    }
225d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
226d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler    /**
227d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * API: Query used to determine if a given policy is "active" (the device is operating at
2283d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * the required security level).
229345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
2303d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * This can be used when syncing a specific account, by passing a specific set of policies
2313d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * for that account.  Or, it can be used at any time to compare the device
2323d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * state against the aggregate set of device policies stored in all accounts.
2333d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     *
2343d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * This method is for queries only, and does not trigger any change in device state.
2353d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     *
2363d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * @param policies the policies requested, or null to check aggregate stored policies
237345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * @return true if the policies are active, false if not active
238345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
239345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    public boolean isActive(PolicySet policies) {
240d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        DevicePolicyManager dpm = getDPM();
241d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        if (dpm.isAdminActive(mAdminName)) {
2423d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // select aggregate set if needed
2433d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (policies == null) {
2443d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                synchronized (this) {
2453d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    if (mAggregatePolicy == null) {
2463d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                        mAggregatePolicy = computeAggregatePolicy();
2473d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    }
2483d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    policies = mAggregatePolicy;
249d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                }
250d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
251d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            // quick check for the "empty set" of no policies
2523d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (policies == NO_POLICY_SET) {
253d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                return true;
254d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
255d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            // check each policy explicitly
2563d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (policies.mMinPasswordLength > 0) {
2573d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                if (dpm.getPasswordMinimumLength(mAdminName) < policies.mMinPasswordLength) {
258d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return false;
259d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                }
260d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
2613d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (policies.mPasswordMode > 0) {
2623d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                if (dpm.getPasswordQuality(mAdminName) < policies.getDPManagerPasswordQuality()) {
263d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return false;
264d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                }
265d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                if (!dpm.isActivePasswordSufficient()) {
266d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return false;
267d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                }
268d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
2693d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (policies.mMaxScreenLockTime > 0) {
270d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                // Note, we use seconds, dpm uses milliseconds
2713d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                if (dpm.getMaximumTimeToLock(mAdminName) > policies.mMaxScreenLockTime * 1000) {
272d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return false;
273d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                }
274d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
275d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            // password failures are counted locally - no test required here
276d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            // no check required for remote wipe (it's supported, if we're the admin)
2772a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
2782a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            // making it this far means we passed!
2792a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            return true;
280d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
281d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        // return false, not active - unless debugging enabled
282d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        return DEBUG_ALWAYS_ACTIVE;
283345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
284345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
285345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
2863d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Set the requested security level based on the aggregate set of requests
2873d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
2883d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public void setActivePolicies() {
2893d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        DevicePolicyManager dpm = getDPM();
2903d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        if (dpm.isAdminActive(mAdminName)) {
2913d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // compute aggregate set if needed
2923d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            PolicySet policies;
2933d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            synchronized (this) {
2943d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                if (mAggregatePolicy == null) {
2953d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    mAggregatePolicy = computeAggregatePolicy();
2963d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                }
2973d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                policies = mAggregatePolicy;
2983d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            }
2993d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // set each policy in the policy manager
3003d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // password mode & length
3013d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            dpm.setPasswordQuality(mAdminName, policies.getDPManagerPasswordQuality());
3023d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            dpm.setPasswordMinimumLength(mAdminName, policies.mMinPasswordLength);
3033d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // screen lock time
3043d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            dpm.setMaximumTimeToLock(mAdminName, policies.mMaxScreenLockTime * 1000);
3053d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // local wipe (failed passwords limit)
3063d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            dpm.setMaximumFailedPasswordsForWipe(mAdminName, policies.mMaxPasswordFails);
3073d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        }
3083d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
3093d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
3103d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
3112a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * API: Set/Clear the "hold" flag in any account.  This flag serves a dual purpose:
3122a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * Setting it gives us an indication that it was blocked, and clearing it gives EAS a
3132a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * signal to try syncing again.
3142a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     */
3152a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    public void setAccountHoldFlag(Account account, boolean newState) {
3162a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        if (newState) {
3172a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            account.mFlags |= Account.FLAGS_SECURITY_HOLD;
3182a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        } else {
3192a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            account.mFlags &= ~Account.FLAGS_SECURITY_HOLD;
3202a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        }
3212a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        ContentValues cv = new ContentValues();
3222a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        cv.put(AccountColumns.FLAGS, account.mFlags);
3232a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        account.update(mContext, cv);
3242a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    }
3252a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
3262a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    /**
3272a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * Clear all account hold flags that are set.  This will trigger watchers, and in particular
3282a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     * will cause EAS to try and resync the account(s).
3292a5eeea9213005060256054ec773e72406415ce4Andrew Stadler     */
3302a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    public void clearAccountHoldFlags() {
3312a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        ContentResolver resolver = mContext.getContentResolver();
3322a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        Cursor c = resolver.query(Account.CONTENT_URI, ACCOUNT_FLAGS_PROJECTION,
3332a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                WHERE_ACCOUNT_SECURITY_NONZERO, null, null);
3342a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        try {
3352a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            while (c.moveToNext()) {
3362a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                int flags = c.getInt(ACCOUNT_FLAGS_COLUMN_FLAGS);
3372a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                if (0 != (flags & Account.FLAGS_SECURITY_HOLD)) {
3382a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                    ContentValues cv = new ContentValues();
3392a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                    cv.put(AccountColumns.FLAGS, flags & ~Account.FLAGS_SECURITY_HOLD);
3402a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                    long accountId = c.getLong(ACCOUNT_FLAGS_COLUMN_ID);
3412a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                    Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId);
3422a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                    resolver.update(uri, cv, null, null);
3432a5eeea9213005060256054ec773e72406415ce4Andrew Stadler                }
3442a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            }
3452a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        } finally {
3462a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            c.close();
3472a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        }
3482a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    }
3492a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
3502a5eeea9213005060256054ec773e72406415ce4Andrew Stadler    /**
3513d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * API: Sync service should call this any time a sync fails due to isActive() returning false.
352d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler     * This will kick off the notify-acquire-admin-state process and/or increase the security level.
353345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * The caller needs to write the required policies into this account before making this call.
3543d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Should not be called from UI thread - uses DB lookups to prepare new notifications
355345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     *
356345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * @param accountId the account for which sync cannot proceed
357345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
358345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    public void policiesRequired(long accountId) {
3592a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        Account account = EmailContent.Account.restoreAccountWithId(mContext, accountId);
3602a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
3612a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        // Mark the account as "on hold".
3622a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        setAccountHoldFlag(account, true);
3632a5eeea9213005060256054ec773e72406415ce4Andrew Stadler
3642a5eeea9213005060256054ec773e72406415ce4Andrew Stadler        // Put up a notification (unless there already is one)
3653d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        synchronized (this) {
3663d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (mNotificationActive) {
3673d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                // no need to do anything - we've already been notified, and we've already
3683d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                // put up a notification
3693d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                return;
3703d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            } else {
3713d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                // Prepare & post a notification
3723d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                // record that we're watching this one
3733d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                mNotificationActive = true;
3743d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            }
3753d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        }
3763d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        // At this point, we will put up a notification
3773d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
3783d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        String tickerText = mContext.getString(R.string.security_notification_ticker_fmt,
3793d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                account.getDisplayName());
3803d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        String contentTitle = mContext.getString(R.string.security_notification_content_title);
3813d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        String contentText = account.getDisplayName();
3823d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        String ringtoneString = account.getRingtone();
3833d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        Uri ringTone = (ringtoneString == null) ? null : Uri.parse(ringtoneString);
3843d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        boolean vibrate = 0 != (account.mFlags & Account.FLAGS_VIBRATE);
3853d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
3863d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        Intent intent = AccountSecurity.actionUpdateSecurityIntent(mContext, accountId);
3873d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        PendingIntent pending =
3883d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
3893d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
3903d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        Notification notification = new Notification(R.drawable.stat_notify_email_generic,
3913d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                tickerText, System.currentTimeMillis());
3923d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notification.setLatestEventInfo(mContext, contentTitle, contentText, pending);
3933d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
3943d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        // Use the account's notification rules for sound & vibrate (but always notify)
3953d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notification.sound = ringTone;
3963d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        if (vibrate) {
3973d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            notification.defaults |= Notification.DEFAULT_VIBRATE;
3983d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        }
3993d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
4003d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notification.defaults |= Notification.DEFAULT_LIGHTS;
4013d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
4023d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        NotificationManager notificationManager =
4033d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
4043d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notificationManager.notify(MailService.NOTIFICATION_ID_SECURITY_NEEDED, notification);
4053d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
4063d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
4073d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
4083d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Called from the notification's intent receiver to register that the notification can be
4093d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * cleared now.
4103d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
4113d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public synchronized void clearNotification(long accountId) {
4123d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        NotificationManager notificationManager =
4133d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
4143d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        notificationManager.cancel(MailService.NOTIFICATION_ID_SECURITY_NEEDED);
4153d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        mNotificationActive = false;
4163d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
4173d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
4183d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
4193d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * API: Remote wipe (from server).  This is final, there is no confirmation.
4203d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
4213d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public void remoteWipe(long accountId) {
4223d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        DevicePolicyManager dpm = getDPM();
4233d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        if (dpm.isAdminActive(mAdminName)) {
4243d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            dpm.wipeData(0);
4253d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        }
426345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
427345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
428345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
429345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     * Class for tracking policies and reading/writing into accounts
430345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
431345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    public static class PolicySet {
432345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
433345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        // Security (provisioning) flags
434345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            // bits 0..4: password length (0=no password required)
435345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_LENGTH_MASK = 31;
436345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_LENGTH_SHIFT = 0;
437345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int PASSWORD_LENGTH_MAX = 31;
438345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            // bits 5..8: password mode
439345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_MODE_SHIFT = 5;
440345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_MODE_MASK = 15 << PASSWORD_MODE_SHIFT;
441345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int PASSWORD_MODE_NONE = 0 << PASSWORD_MODE_SHIFT;
442345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int PASSWORD_MODE_SIMPLE = 1 << PASSWORD_MODE_SHIFT;
443345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int PASSWORD_MODE_STRONG = 2 << PASSWORD_MODE_SHIFT;
444345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            // bits 9..13: password failures -> wipe device (0=disabled)
445345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_MAX_FAILS_SHIFT = 9;
446345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int PASSWORD_MAX_FAILS_MASK = 31 << PASSWORD_MAX_FAILS_SHIFT;
447345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int PASSWORD_MAX_FAILS_MAX = 31;
448345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            // bits 14..24: seconds to screen lock (0=not required)
449345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int SCREEN_LOCK_TIME_SHIFT = 14;
450345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int SCREEN_LOCK_TIME_MASK = 2047 << SCREEN_LOCK_TIME_SHIFT;
451345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public static final int SCREEN_LOCK_TIME_MAX = 2047;
452345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            // bit 25: remote wipe capability required
453345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        private static final int REQUIRE_REMOTE_WIPE = 1 << 25;
454345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
455345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public final int mMinPasswordLength;
456345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public final int mPasswordMode;
457345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public final int mMaxPasswordFails;
458345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public final int mMaxScreenLockTime;
459345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public final boolean mRequireRemoteWipe;
460345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
461345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
462345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Create from raw values.
463345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param minPasswordLength (0=not enforced)
464345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param passwordMode
465345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param maxPasswordFails (0=not enforced)
466d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler         * @param maxScreenLockTime in seconds (0=not enforced)
467345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param requireRemoteWipe
4683d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         * @throws IllegalArgumentException when any arguments are outside of legal ranges.
469345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
470345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public PolicySet(int minPasswordLength, int passwordMode, int maxPasswordFails,
4713d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                int maxScreenLockTime, boolean requireRemoteWipe) throws IllegalArgumentException {
472345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (minPasswordLength > PASSWORD_LENGTH_MAX) {
473345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                throw new IllegalArgumentException("password length");
474345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
475345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (passwordMode < PASSWORD_MODE_NONE
476345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    || passwordMode > PASSWORD_MODE_STRONG) {
477345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                throw new IllegalArgumentException("password mode");
478345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
479345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (maxPasswordFails > PASSWORD_MAX_FAILS_MAX) {
480345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                throw new IllegalArgumentException("password max fails");
481345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
482345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (maxScreenLockTime > SCREEN_LOCK_TIME_MAX) {
483345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                throw new IllegalArgumentException("max screen lock time");
484345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
485345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
486345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMinPasswordLength = minPasswordLength;
487345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mPasswordMode = passwordMode;
488345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMaxPasswordFails = maxPasswordFails;
489345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMaxScreenLockTime = maxScreenLockTime;
490345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mRequireRemoteWipe = requireRemoteWipe;
491345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
492345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
493345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
494345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Create from values encoded in an account
495345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param account
496345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
497345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public PolicySet(Account account) {
498345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            this(account.mSecurityFlags);
499345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
500345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
501345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
502345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Create from values encoded in an account flags int
503345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
504345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public PolicySet(int flags) {
505345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMinPasswordLength =
506345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                (flags & PASSWORD_LENGTH_MASK) >> PASSWORD_LENGTH_SHIFT;
507345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mPasswordMode =
508345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                (flags & PASSWORD_MODE_MASK);
509345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMaxPasswordFails =
510345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                (flags & PASSWORD_MAX_FAILS_MASK) >> PASSWORD_MAX_FAILS_SHIFT;
511345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mMaxScreenLockTime =
512345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                (flags & SCREEN_LOCK_TIME_MASK) >> SCREEN_LOCK_TIME_SHIFT;
513345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            mRequireRemoteWipe = 0 != (flags & REQUIRE_REMOTE_WIPE);
514345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
515345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
516345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
5173d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         * Helper to map our internal encoding to DevicePolicyManager password modes.
518d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler         */
5193d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        public int getDPManagerPasswordQuality() {
520d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            switch (mPasswordMode) {
521d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                case PASSWORD_MODE_SIMPLE:
522d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
523d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                case PASSWORD_MODE_STRONG:
524d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
525d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                default:
526d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler                    return DevicePolicyManager .PASSWORD_QUALITY_UNSPECIFIED;
527d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler            }
528d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        }
529d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler
530d62860821c2dbc14ab493b888cb129bd5addd53dAndrew Stadler        /**
531345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Record flags (and a sync key for the flags) into an Account
532345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Note: the hash code is defined as the encoding used in Account
5333d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         *
534345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param account to write the values mSecurityFlags and mSecuritySyncKey
535345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * @param syncKey the value to write into the account's mSecuritySyncKey
5363d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         * @param update if true, also writes the account back to the provider (updating only
5373d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         *  the fields changed by this API)
5383d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         * @param context a context for writing to the provider
5393d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         * @return true if the actual policies changed, false if no change (note, sync key
5403d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler         *  does not affect this)
541345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
5423d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        public boolean writeAccount(Account account, String syncKey, boolean update,
5433d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                Context context) {
5443d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            int newFlags = hashCode();
5453d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            boolean dirty = (newFlags != account.mSecurityFlags);
5463d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            account.mSecurityFlags = newFlags;
5473d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            account.mSecuritySyncKey = syncKey;
5483d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            if (update) {
5493d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                if (account.isSaved()) {
5503d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    ContentValues cv = new ContentValues();
5513d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    cv.put(AccountColumns.SECURITY_FLAGS, account.mSecurityFlags);
5523d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    cv.put(AccountColumns.SECURITY_SYNC_KEY, account.mSecuritySyncKey);
5533d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    account.update(context, cv);
5543d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                } else {
5553d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                    account.save(context);
5563d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler                }
5573d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            }
5583d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            return dirty;
559345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
560345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
561345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
562345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public boolean equals(Object o) {
563345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (o instanceof PolicySet) {
564345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                PolicySet other = (PolicySet)o;
565345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                return (this.mMinPasswordLength == other.mMinPasswordLength)
566345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        && (this.mPasswordMode == other.mPasswordMode)
567345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        && (this.mMaxPasswordFails == other.mMaxPasswordFails)
568345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        && (this.mMaxScreenLockTime == other.mMaxScreenLockTime)
569345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                        && (this.mRequireRemoteWipe == other.mRequireRemoteWipe);
570345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
571345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            return false;
572345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
573345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
574345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
575345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Note: the hash code is defined as the encoding used in Account
576345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
577345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
578345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public int hashCode() {
579345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            int flags = 0;
580345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            flags = mMinPasswordLength << PASSWORD_LENGTH_SHIFT;
581345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            flags |= mPasswordMode;
582345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            flags |= mMaxPasswordFails << PASSWORD_MAX_FAILS_SHIFT;
583345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            flags |= mMaxScreenLockTime << SCREEN_LOCK_TIME_SHIFT;
584345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            if (mRequireRemoteWipe) {
585345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                flags |= REQUIRE_REMOTE_WIPE;
586345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            }
587345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            return flags;
588345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
589345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
590345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
591345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public String toString() {
592345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler            return "{ " + "pw-len-min=" + mMinPasswordLength + " pw-mode=" + mPasswordMode
593345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    + " pw-fails-max=" + mMaxPasswordFails + " screenlock-max="
594345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler                    + mMaxScreenLockTime + " remote-wipe-req=" + mRequireRemoteWipe + "}";
595345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
596345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
597345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
598345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    /**
5993d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * If we are not the active device admin, try to become so.
6003d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     *
6013d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * @return true if we are already active, false if we are not
602345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler     */
6033d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public boolean isActiveAdmin() {
6043d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        DevicePolicyManager dpm = getDPM();
6053d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        return dpm.isAdminActive(mAdminName);
6063d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
607345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
6083d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
6093d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Report admin component name - for making calls into device policy manager
6103d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
6113d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public ComponentName getAdminComponent() {
6123d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        return mAdminName;
6133d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
6143d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
6153d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
6163d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Internal handler for enabled/disabled transitions.  Handles DeviceAdmin.onEnabled and
6173d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * and DeviceAdmin.onDisabled.
6183d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
6193d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    private void onAdminEnabled(boolean isEnabled) {
6203d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        if (isEnabled && !mAdminEnabled) {
6213d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // TODO: transition to enabled state
6223d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        } else if (!isEnabled && mAdminEnabled) {
6233d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            // TODO: transition to disabled state
6243d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        }
6253d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler        mAdminEnabled = isEnabled;
6263d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    }
6273d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler
6283d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    /**
6293d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Device Policy administrator.  This is primarily a listener for device state changes.
6303d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     * Note:  This is instantiated by incoming messages.
6315893e9e008d46cf4be0c7f709a6e77e2652c3dddAndrew Stadler     * Note:  We do not implement onPasswordFailed() because the default behavior of the
6325893e9e008d46cf4be0c7f709a6e77e2652c3dddAndrew Stadler     *        DevicePolicyManager - complete local wipe after 'n' failures - is sufficient.
6333d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler     */
6343d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler    public static class PolicyAdmin extends DeviceAdmin {
635345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
636345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
637345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Called after the administrator is first enabled.
638345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
639345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
640345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public void onEnabled(Context context, Intent intent) {
6413d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            SecurityPolicy.getInstance(context).onAdminEnabled(true);
642345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
643345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
644345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
645345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Called prior to the administrator being disabled.
646345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
647345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
648345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public void onDisabled(Context context, Intent intent) {
6493d2b3b3b3554be2ac23d9a49fee00faa9693e857Andrew Stadler            SecurityPolicy.getInstance(context).onAdminEnabled(false);
650345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
651345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler
652345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        /**
653345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         * Called after the user has changed their password.
654345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler         */
655345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        @Override
656345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        public void onPasswordChanged(Context context, Intent intent) {
6572a5eeea9213005060256054ec773e72406415ce4Andrew Stadler            SecurityPolicy.getInstance(context).clearAccountHoldFlags();
658345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler        }
659345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler    }
660345fb8b737c1632fb2a7e69ac44b8612be6237edAndrew Stadler}
661