WorkLockActivity.java revision f793d87b805f204473d130ce29ece72ff1b3cec6
1/*
2 * Copyright (C) 2017 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.systemui.keyguard;
18
19import static android.app.ActivityManager.TaskDescription;
20
21import android.annotation.ColorInt;
22import android.annotation.UserIdInt;
23import android.app.Activity;
24import android.app.ActivityManager;
25import android.app.ActivityOptions;
26import android.app.KeyguardManager;
27import android.app.PendingIntent;
28import android.app.admin.DevicePolicyManager;
29import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.graphics.Color;
34import android.os.Bundle;
35import android.os.RemoteException;
36import android.os.UserHandle;
37import android.util.Log;
38import android.view.View;
39
40/**
41 * Bouncer between work activities and the activity used to confirm credentials before unlocking
42 * a managed profile.
43 * <p>
44 * Shows a solid color when started, based on the organization color of the user it is supposed to
45 * be blocking. Once focused, it switches to a screen to confirm credentials and auto-dismisses if
46 * credentials are accepted.
47 */
48public class WorkLockActivity extends Activity {
49    private static final String TAG = "WorkLockActivity";
50
51    /**
52     * ID of the locked user that this activity blocks access to.
53     */
54    @UserIdInt
55    private int mUserId;
56
57    /**
58     * {@see KeyguardManager}
59     */
60    private KeyguardManager mKgm;
61
62    /**
63     * {@see DevicePolicyManager}
64     */
65    private DevicePolicyManager mDpm;
66
67    @Override
68    public void onCreate(Bundle savedInstanceState) {
69        super.onCreate(savedInstanceState);
70
71        mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
72        mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
73        mKgm = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
74
75        final IntentFilter lockFilter = new IntentFilter();
76        lockFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
77        registerReceiverAsUser(mLockEventReceiver, UserHandle.ALL, lockFilter,
78                /* permission */ null, /* scheduler */ null);
79
80        // Once the receiver is registered, check whether anything happened between now and the time
81        // when this activity was launched. If it did and the user is unlocked now, just quit.
82        if (!mKgm.isDeviceLocked(mUserId)) {
83            finish();
84            return;
85        }
86
87        // Get the organization color; this is a 24-bit integer provided by a DPC, guaranteed to
88        // be completely opaque.
89        final @ColorInt int color = mDpm.getOrganizationColorForUser(mUserId);
90
91        // Draw captions overlaid on the content view, so the whole window is one solid color.
92        setOverlayWithDecorCaptionEnabled(true);
93
94        // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
95        // redaction switched on.
96        final View blankView = new View(this);
97        blankView.setBackgroundColor(color);
98        setContentView(blankView);
99    }
100
101    /**
102     * Respond to focus events by showing the prompt to confirm credentials.
103     * <p>
104     * We don't have anything particularly interesting to show here (just a solid-colored page) so
105     * there is no sense in sitting in the foreground doing nothing.
106     */
107    @Override
108    public void onWindowFocusChanged(boolean hasFocus) {
109        if (hasFocus) {
110            showConfirmCredentialActivity();
111        }
112    }
113
114    @Override
115    public void onDestroy() {
116        unregisterReceiver(mLockEventReceiver);
117        super.onDestroy();
118    }
119
120    @Override
121    public void onBackPressed() {
122        // Ignore back presses.
123        return;
124    }
125
126    @Override
127    public void setTaskDescription(TaskDescription taskDescription) {
128        // Use the previous activity's task description.
129    }
130
131    private final BroadcastReceiver mLockEventReceiver = new BroadcastReceiver() {
132        @Override
133        public void onReceive(Context context, Intent intent) {
134            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, mUserId);
135            if (userId == mUserId && !mKgm.isDeviceLocked(mUserId)) {
136                finish();
137            }
138        }
139    };
140
141    private void showConfirmCredentialActivity() {
142        if (isFinishing() || !mKgm.isDeviceLocked(mUserId)) {
143            // Don't show the confirm credentials screen if we are already unlocked / unlocking.
144            return;
145        }
146
147        final Intent credential = mKgm.createConfirmDeviceCredentialIntent(null, null, mUserId);
148        if (credential == null) {
149            return;
150        }
151
152        final ActivityOptions options = ActivityOptions.makeBasic();
153        options.setLaunchTaskId(getTaskId());
154
155        // Bring this activity back to the foreground after confirming credentials.
156        final PendingIntent target = PendingIntent.getActivity(this, /* request */ -1, getIntent(),
157                PendingIntent.FLAG_CANCEL_CURRENT |
158                PendingIntent.FLAG_ONE_SHOT |
159                PendingIntent.FLAG_IMMUTABLE, options.toBundle());
160
161        credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
162        try {
163            ActivityManager.getService().startConfirmDeviceCredentialIntent(credential);
164        } catch (RemoteException e) {
165            Log.e(TAG, "Failed to start confirm credential intent", e);
166        }
167    }
168}
169