AccountSecurity.java revision 469f2987dc11d153434e50eb04dd6b83b924d09d
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
17package com.android.email.activity.setup;
18
19import com.android.email.R;
20import com.android.email.SecurityPolicy;
21import com.android.email.activity.ActivityHelper;
22import com.android.email.provider.EmailContent.Account;
23import com.android.email.provider.EmailContent.HostAuth;
24
25import android.app.Activity;
26import android.app.admin.DevicePolicyManager;
27import android.content.Context;
28import android.content.Intent;
29import android.os.Bundle;
30
31/**
32 * Psuedo-activity (no UI) to bootstrap the user up to a higher desired security level.  This
33 * bootstrap requires the following steps.
34 *
35 * 1.  Confirm the account of interest has any security policies defined - exit early if not
36 * 2.  If not actively administrating the device, ask Device Policy Manager to start that
37 * 3.  When we are actively administrating, check current policies and see if they're sufficient
38 * 4.  If not, set policies
39 * 5.  If necessary, request for user to update device password
40 * 6.  If necessary, request for user to activate device encryption
41 */
42public class AccountSecurity extends Activity {
43
44    private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity.setup.ACCOUNT_ID";
45
46    private static final int REQUEST_ENABLE = 1;
47    private static final int REQUEST_PASSWORD = 2;
48    private static final int REQUEST_ENCRYPTION = 3;
49
50    /**
51     * Used for generating intent for this activity (which is intended to be launched
52     * from a notification.)
53     *
54     * @param context Calling context for building the intent
55     * @param accountId The account of interest
56     * @return an Intent which can be used to view that account
57     */
58    public static Intent actionUpdateSecurityIntent(Context context, long accountId) {
59        Intent intent = new Intent(context, AccountSecurity.class);
60        intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
61        return intent;
62    }
63
64    @Override
65    public void onCreate(Bundle savedInstanceState) {
66        super.onCreate(savedInstanceState);
67        ActivityHelper.debugSetWindowFlags(this);
68
69        Intent i = getIntent();
70        long accountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
71        SecurityPolicy security = SecurityPolicy.getInstance(this);
72        security.clearNotification(accountId);
73        if (accountId != -1) {
74            // TODO: spin up a thread to do this in the background, because of DB ops
75            Account account = Account.restoreAccountWithId(this, accountId);
76            if (account != null) {
77                if (account.mSecurityFlags != 0) {
78                    // This account wants to control security
79                    if (!security.isActiveAdmin()) {
80                        // retrieve name of server for the format string
81                        HostAuth hostAuth =
82                                HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv);
83                        if (hostAuth != null) {
84                            // try to become active - must happen here in activity, to get result
85                            Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
86                            intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
87                                    security.getAdminComponent());
88                            intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
89                                this.getString(R.string.account_security_policy_explanation_fmt,
90                                        hostAuth.mAddress));
91                            startActivityForResult(intent, REQUEST_ENABLE);
92                            // keep this activity on stack to process result
93                            return;
94                        }
95                    } else {
96                        // already active - try to set actual policies, finish, and return
97                        boolean startedActivity = setActivePolicies();
98                        if (startedActivity) {
99                            // keep this activity on stack to process result
100                            return;
101                        }
102                    }
103                }
104            }
105        }
106        finish();
107    }
108
109    /**
110     * Handle the eventual result of the user allowing us to become an active device admin
111     */
112    @Override
113    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
114        boolean startedActivity = false;
115        switch (requestCode) {
116            case REQUEST_PASSWORD:
117            case REQUEST_ENCRYPTION:
118                // Force the result code and just check the DPM to check for actual success
119                resultCode = Activity.RESULT_OK;
120              //$FALL-THROUGH$
121            case REQUEST_ENABLE:
122                if (resultCode == Activity.RESULT_OK) {
123                    // now active - try to set actual policies
124                    startedActivity = setActivePolicies();
125                } else {
126                    // failed - repost notification, and exit
127                    final long accountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1);
128                    if (accountId != -1) {
129                        new Thread() {
130                            @Override
131                            public void run() {
132                                SecurityPolicy.getInstance(AccountSecurity.this)
133                                        .policiesRequired(accountId);
134                            }
135                        }.start();
136                    }
137                }
138        }
139        if (!startedActivity) {
140            finish();
141        }
142        super.onActivityResult(requestCode, resultCode, data);
143    }
144
145    /**
146     * Now that we are connected as an active device admin, try to set the device to the
147     * correct security level, and ask for a password if necessary.
148     * @return true if we started another activity (and should not finish(), as we're waiting for
149     * their result.)
150     */
151    private boolean setActivePolicies() {
152        SecurityPolicy sp = SecurityPolicy.getInstance(this);
153        // check current security level - if sufficient, we're done!
154        if (sp.isActive(null)) {
155            Account.clearSecurityHoldOnAllAccounts(this);
156            return false;
157        }
158        // set current security level
159        sp.setActivePolicies();
160        // check current security level - if sufficient, we're done!
161        int inactiveReasons = sp.getInactiveReasons(null);
162        if (inactiveReasons == 0) {
163            Account.clearSecurityHoldOnAllAccounts(this);
164            return false;
165        }
166        // If password or encryption required, launch relevant intent
167        if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_PASSWORD) != 0) {
168            // launch the activity to have the user set a new password.
169            Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
170            startActivityForResult(intent, REQUEST_PASSWORD);
171            return true;
172        } else if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_ENCRYPTION) != 0) {
173            // launch the activity to start up encryption.
174            Intent intent = new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION);
175            startActivityForResult(intent, REQUEST_ENCRYPTION);
176            return true;
177        }
178        return false;
179    }
180}
181