/** * Handle password expiration - if any accounts appear to have triggered this, put up warnings, or * even shut them down. * * <p>NOTE: If there are multiple accounts with password expiration policies, the device password * will be set to expire in the shortest required interval (most secure). The logic in this method * operates based on the aggregate setting - irrespective of which account caused the expiration. * In other words, all accounts (that require expiration) will run/stop based on the requirements * of the account with the shortest interval. */ private void onPasswordExpiring(Context context) { // 1. Do we have any accounts that matter here? long nextExpiringAccountId = findShortestExpiration(context); // 2. If not, exit immediately if (nextExpiringAccountId == -1) { return; } // 3. If yes, are we warning or expired? long expirationDate = getDPM().getPasswordExpiration(mAdminName); long timeUntilExpiration = expirationDate - System.currentTimeMillis(); boolean expired = timeUntilExpiration < 0; final NotificationController nc = NotificationControllerCreatorHolder.getInstance(context); if (!expired) { // 4. If warning, simply put up a generic notification and report that it came from // the shortest-expiring account. nc.showPasswordExpiringNotificationSynchronous(nextExpiringAccountId); } else { // 5. Actually expired - find all accounts that expire passwords, and wipe them boolean wiped = wipeExpiredAccounts(context); if (wiped) { nc.showPasswordExpiredNotificationSynchronous(nextExpiringAccountId); } } }
/** Convenience method; see javadoc below */ public static void setAccountHoldFlag(Context context, long accountId, boolean newState) { Account account = Account.restoreAccountWithId(context, accountId); if (account != null) { setAccountHoldFlag(context, account, newState); if (newState) { // Make sure there's a notification up final NotificationController nc = NotificationControllerCreatorHolder.getInstance(context); nc.showSecurityNeededNotification(account); } } }
/** * API: Sync service should call this any time a sync fails due to isActive() returning false. * This will kick off the notify-acquire-admin-state process and/or increase the security level. * The caller needs to write the required policies into this account before making this call. * Should not be called from UI thread - uses DB lookups to prepare new notifications * * @param accountId the account for which sync cannot proceed */ public void policiesRequired(long accountId) { Account account = Account.restoreAccountWithId(mContext, accountId); // In case the account has been deleted, just return if (account == null) return; if (account.mPolicyKey == 0) return; Policy policy = Policy.restorePolicyWithId(mContext, account.mPolicyKey); if (policy == null) return; if (DebugUtils.DEBUG) { LogUtils.d(TAG, "policiesRequired for " + account.mDisplayName + ": " + policy); } // Mark the account as "on hold". setAccountHoldFlag(mContext, account, true); // Put up an appropriate notification final NotificationController nc = NotificationControllerCreatorHolder.getInstance(mContext); if (policy.mProtocolPoliciesUnsupported == null) { nc.showSecurityNeededNotification(account); } else { nc.showSecurityUnsupportedNotification(account); } }
/** * Callback from EmailBroadcastProcessorService. This provides the workers for the * DeviceAdminReceiver calls. These should perform the work directly and not use async threads for * completion. */ public static void onDeviceAdminReceiverMessage(Context context, int message) { SecurityPolicy instance = SecurityPolicy.getInstance(context); switch (message) { case DEVICE_ADMIN_MESSAGE_ENABLED: instance.onAdminEnabled(true); break; case DEVICE_ADMIN_MESSAGE_DISABLED: instance.onAdminEnabled(false); break; case DEVICE_ADMIN_MESSAGE_PASSWORD_CHANGED: // TODO make a small helper for this // Clear security holds (if any) Account.clearSecurityHoldOnAllAccounts(context); // Cancel any active notifications (if any are posted) final NotificationController nc = NotificationControllerCreatorHolder.getInstance(context); nc.cancelPasswordExpirationNotifications(); break; case DEVICE_ADMIN_MESSAGE_PASSWORD_EXPIRING: instance.onPasswordExpiring(instance.mContext); break; } }
/** * Called from the notification's intent receiver to register that the notification can be cleared * now. */ public void clearNotification() { final NotificationController nc = NotificationControllerCreatorHolder.getInstance(mContext); nc.cancelSecurityNeededNotification(); }
public void setAccountPolicy(long accountId, Policy policy, String securityKey, boolean notify) { Account account = Account.restoreAccountWithId(mContext, accountId); // In case the account has been deleted, just return if (account == null) { return; } Policy oldPolicy = null; if (account.mPolicyKey > 0) { oldPolicy = Policy.restorePolicyWithId(mContext, account.mPolicyKey); } // If attachment policies have changed, fix up any affected attachment records if (oldPolicy != null && securityKey != null) { if ((oldPolicy.mDontAllowAttachments != policy.mDontAllowAttachments) || (oldPolicy.mMaxAttachmentSize != policy.mMaxAttachmentSize)) { Policy.setAttachmentFlagsForNewPolicy(mContext, account, policy); } } boolean policyChanged = (oldPolicy == null) || !oldPolicy.equals(policy); if (!policyChanged && (TextUtilities.stringOrNullEquals(securityKey, account.mSecuritySyncKey))) { LogUtils.d(Logging.LOG_TAG, "setAccountPolicy; policy unchanged"); } else { setAccountPolicy(mContext, account, policy, securityKey); policiesUpdated(); } boolean setHold = false; final NotificationController nc = NotificationControllerCreatorHolder.getInstance(mContext); if (policy.mProtocolPoliciesUnsupported != null) { // We can't support this, reasons in unsupportedRemotePolicies LogUtils.d( Logging.LOG_TAG, "Notify policies for " + account.mDisplayName + " not supported."); setHold = true; if (notify) { nc.showSecurityUnsupportedNotification(account); } // Erase data Uri uri = EmailProvider.uiUri("uiaccountdata", accountId); mContext.getContentResolver().delete(uri, null, null); } else if (isActive(policy)) { if (policyChanged) { LogUtils.d(Logging.LOG_TAG, "Notify policies for " + account.mDisplayName + " changed."); if (notify) { // Notify that policies changed nc.showSecurityChangedNotification(account); } } else { LogUtils.d(Logging.LOG_TAG, "Policy is active and unchanged; do not notify."); } } else { setHold = true; LogUtils.d( Logging.LOG_TAG, "Notify policies for " + account.mDisplayName + " are not being enforced."); if (notify) { // Put up a notification nc.showSecurityNeededNotification(account); } } // Set/clear the account hold. setAccountHoldFlag(mContext, account, setHold); }