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