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