1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.email.activity.setup; 18 19 import com.android.email.R; 20 import com.android.email.SecurityPolicy; 21 import com.android.email.provider.EmailContent.Account; 22 import com.android.email.provider.EmailContent.HostAuth; 23 24 import android.app.Activity; 25 import android.app.admin.DevicePolicyManager; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.os.Bundle; 29 30 /** 31 * Psuedo-activity (no UI) to bootstrap the user up to a higher desired security level. This 32 * bootstrap requires the following steps. 33 * 34 * 1. Confirm the account of interest has any security policies defined - exit early if not 35 * 2. If not actively administrating the device, ask Device Policy Manager to start that 36 * 3. When we are actively administrating, check current policies and see if they're sufficient 37 * 4. If not, set policies 38 * 5. If necessary, request for user to update device password 39 */ 40 public class AccountSecurity extends Activity { 41 42 private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity.setup.ACCOUNT_ID"; 43 44 private static final int REQUEST_ENABLE = 1; 45 46 /** 47 * Used for generating intent for this activity (which is intended to be launched 48 * from a notification.) 49 * 50 * @param context Calling context for building the intent 51 * @param accountId The account of interest 52 * @return an Intent which can be used to view that account 53 */ 54 public static Intent actionUpdateSecurityIntent(Context context, long accountId) { 55 Intent intent = new Intent(context, AccountSecurity.class); 56 intent.putExtra(EXTRA_ACCOUNT_ID, accountId); 57 return intent; 58 } 59 60 @Override 61 public void onCreate(Bundle savedInstanceState) { 62 super.onCreate(savedInstanceState); 63 64 Intent i = getIntent(); 65 long accountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1); 66 SecurityPolicy security = SecurityPolicy.getInstance(this); 67 security.clearNotification(accountId); 68 if (accountId != -1) { 69 // TODO: spin up a thread to do this in the background, because of DB ops 70 Account account = Account.restoreAccountWithId(this, accountId); 71 if (account != null) { 72 if (account.mSecurityFlags != 0) { 73 // This account wants to control security 74 if (!security.isActiveAdmin()) { 75 // retrieve name of server for the format string 76 HostAuth hostAuth = 77 HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv); 78 if (hostAuth != null) { 79 // try to become active - must happen here in activity, to get result 80 Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); 81 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, 82 security.getAdminComponent()); 83 intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, 84 this.getString(R.string.account_security_policy_explanation_fmt, 85 hostAuth.mAddress)); 86 startActivityForResult(intent, REQUEST_ENABLE); 87 // keep this activity on stack to process result 88 return; 89 } 90 } else { 91 // already active - try to set actual policies, finish, and return 92 setActivePolicies(); 93 } 94 } 95 } 96 } 97 finish(); 98 } 99 100 /** 101 * Handle the eventual result of the user allowing us to become an active device admin 102 */ 103 @Override 104 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 105 switch (requestCode) { 106 case REQUEST_ENABLE: 107 if (resultCode == Activity.RESULT_OK) { 108 // now active - try to set actual policies 109 setActivePolicies(); 110 } else { 111 // failed - repost notification, and exit 112 final long accountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1); 113 if (accountId != -1) { 114 new Thread() { 115 @Override 116 public void run() { 117 SecurityPolicy.getInstance(AccountSecurity.this) 118 .policiesRequired(accountId); 119 } 120 }.start(); 121 } 122 } 123 } 124 finish(); 125 super.onActivityResult(requestCode, resultCode, data); 126 } 127 128 /** 129 * Now that we are connected as an active device admin, try to set the device to the 130 * correct security level, and ask for a password if necessary. 131 */ 132 private void setActivePolicies() { 133 SecurityPolicy sp = SecurityPolicy.getInstance(this); 134 // check current security level - if sufficient, we're done! 135 if (sp.isActive(null)) { 136 sp.clearAccountHoldFlags(); 137 return; 138 } 139 // set current security level 140 sp.setActivePolicies(); 141 // check current security level - if sufficient, we're done! 142 if (sp.isActive(null)) { 143 sp.clearAccountHoldFlags(); 144 return; 145 } 146 // if not sufficient, launch the activity to have the user set a new password. 147 Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 148 startActivity(intent); 149 } 150 151 } 152