WorkLockActivity.java revision 3fef1f284390a2ff7a58e0dcd56cb90bf83d2017
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        // Match task description to the task stack we are replacing so it's still recognizably the
95        // original task stack with the same icon and title text.
96        setTaskDescription(new TaskDescription(null, null, color));
97
98        // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
99        // redaction switched on.
100        final View blankView = new View(this);
101        blankView.setBackgroundColor(color);
102        setContentView(blankView);
103
104        // Respond to input events by showing the prompt to confirm credentials.
105        blankView.setOnClickListener((View v) -> {
106            showConfirmCredentialActivity();
107        });
108    }
109
110    @Override
111    public void onDestroy() {
112        unregisterReceiver(mLockEventReceiver);
113        super.onDestroy();
114    }
115
116    @Override
117    public void onBackPressed() {
118        // Ignore back presses.
119        return;
120    }
121
122    private final BroadcastReceiver mLockEventReceiver = new BroadcastReceiver() {
123        @Override
124        public void onReceive(Context context, Intent intent) {
125            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, mUserId);
126            if (userId == mUserId && !mKgm.isDeviceLocked(mUserId)) {
127                finish();
128            }
129        }
130    };
131
132    private void showConfirmCredentialActivity() {
133        if (isFinishing() || !mKgm.isDeviceLocked(mUserId)) {
134            // Don't show the confirm credentials screen if we are already unlocked / unlocking.
135            return;
136        }
137
138        final Intent credential = mKgm.createConfirmDeviceCredentialIntent(null, null, mUserId);
139        if (credential == null) {
140            return;
141        }
142
143        final ActivityOptions options = ActivityOptions.makeBasic();
144        options.setLaunchTaskId(getTaskId());
145
146        // Bring this activity back to the foreground after confirming credentials.
147        final PendingIntent target = PendingIntent.getActivity(this, /* request */ -1, getIntent(),
148                PendingIntent.FLAG_CANCEL_CURRENT |
149                PendingIntent.FLAG_ONE_SHOT |
150                PendingIntent.FLAG_IMMUTABLE, options.toBundle());
151
152        credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
153        try {
154            ActivityManager.getService().startConfirmDeviceCredentialIntent(credential);
155        } catch (RemoteException e) {
156            Log.e(TAG, "Failed to start confirm credential intent", e);
157        }
158    }
159}
160