1 /* 2 * Copyright (C) 2020 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 package com.android.keyguard; 17 18 import android.annotation.Nullable; 19 import android.app.admin.IKeyguardCallback; 20 import android.app.admin.IKeyguardClient; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.ServiceConnection; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.util.Log; 30 import android.view.SurfaceControlViewHost; 31 import android.view.SurfaceHolder; 32 import android.view.SurfaceView; 33 import android.view.ViewGroup; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.keyguard.dagger.KeyguardBouncerScope; 37 import com.android.systemui.dagger.qualifiers.Main; 38 39 import java.util.NoSuchElementException; 40 41 import javax.inject.Inject; 42 43 /** 44 * Encapsulates all logic for secondary lockscreen state management. 45 */ 46 public class AdminSecondaryLockScreenController { 47 private static final String TAG = "AdminSecondaryLockScreenController"; 48 private static final int REMOTE_CONTENT_READY_TIMEOUT_MILLIS = 500; 49 private final KeyguardUpdateMonitor mUpdateMonitor; 50 private final Context mContext; 51 private final ViewGroup mParent; 52 private AdminSecurityView mView; 53 private Handler mHandler; 54 private IKeyguardClient mClient; 55 private KeyguardSecurityCallback mKeyguardCallback; 56 57 private final ServiceConnection mConnection = new ServiceConnection() { 58 @Override 59 public void onServiceConnected(ComponentName className, IBinder service) { 60 mClient = IKeyguardClient.Stub.asInterface(service); 61 if (mView.isAttachedToWindow() && mClient != null) { 62 onSurfaceReady(); 63 64 try { 65 service.linkToDeath(mKeyguardClientDeathRecipient, 0); 66 } catch (RemoteException e) { 67 // Failed to link to death, just dismiss and unbind the service for now. 68 Log.e(TAG, "Lost connection to secondary lockscreen service", e); 69 dismiss(KeyguardUpdateMonitor.getCurrentUser()); 70 } 71 } 72 } 73 74 @Override 75 public void onServiceDisconnected(ComponentName className) { 76 mClient = null; 77 } 78 }; 79 80 private final IBinder.DeathRecipient mKeyguardClientDeathRecipient = () -> { 81 hide(); // hide also takes care of unlinking to death. 82 Log.d(TAG, "KeyguardClient service died"); 83 }; 84 85 private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() { 86 @Override 87 public void onDismiss() { 88 mHandler.post(() -> { 89 dismiss(UserHandle.getCallingUserId()); 90 }); 91 } 92 93 @Override 94 public void onRemoteContentReady( 95 @Nullable SurfaceControlViewHost.SurfacePackage surfacePackage) { 96 if (mHandler != null) { 97 mHandler.removeCallbacksAndMessages(null); 98 } 99 if (surfacePackage != null) { 100 mView.setChildSurfacePackage(surfacePackage); 101 } else { 102 mHandler.post(() -> { 103 dismiss(KeyguardUpdateMonitor.getCurrentUser()); 104 }); 105 } 106 } 107 }; 108 109 private final KeyguardUpdateMonitorCallback mUpdateCallback = 110 new KeyguardUpdateMonitorCallback() { 111 @Override 112 public void onSecondaryLockscreenRequirementChanged(int userId) { 113 Intent newIntent = mUpdateMonitor.getSecondaryLockscreenRequirement(userId); 114 if (newIntent == null) { 115 dismiss(userId); 116 } 117 } 118 }; 119 120 @VisibleForTesting 121 protected SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { 122 @Override 123 public void surfaceCreated(SurfaceHolder holder) { 124 final int userId = KeyguardUpdateMonitor.getCurrentUser(); 125 mUpdateMonitor.registerCallback(mUpdateCallback); 126 127 if (mClient != null) { 128 onSurfaceReady(); 129 } 130 mHandler.postDelayed( 131 () -> { 132 // If the remote content is not readied within the timeout period, 133 // move on without the secondary lockscreen. 134 dismiss(userId); 135 Log.w(TAG, "Timed out waiting for secondary lockscreen content."); 136 }, 137 REMOTE_CONTENT_READY_TIMEOUT_MILLIS); 138 } 139 140 @Override 141 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} 142 143 @Override 144 public void surfaceDestroyed(SurfaceHolder holder) { 145 mUpdateMonitor.removeCallback(mUpdateCallback); 146 } 147 }; 148 AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent, KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback, @Main Handler handler)149 private AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent, 150 KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback, 151 @Main Handler handler) { 152 mContext = context; 153 mHandler = handler; 154 mParent = parent; 155 mUpdateMonitor = updateMonitor; 156 mKeyguardCallback = callback; 157 mView = new AdminSecurityView(mContext, mSurfaceHolderCallback); 158 } 159 160 /** 161 * Displays the Admin security Surface view. 162 */ show(Intent serviceIntent)163 public void show(Intent serviceIntent) { 164 if (mClient == null) { 165 mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); 166 } 167 if (!mView.isAttachedToWindow()) { 168 mParent.addView(mView); 169 } 170 } 171 172 /** 173 * Hides the Admin security Surface view. 174 */ hide()175 public void hide() { 176 if (mView.isAttachedToWindow()) { 177 mParent.removeView(mView); 178 } 179 if (mClient != null) { 180 try { 181 mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0); 182 } catch (NoSuchElementException e) { 183 Log.w(TAG, "IKeyguardClient death recipient already released"); 184 } 185 mContext.unbindService(mConnection); 186 mClient = null; 187 } 188 } 189 onSurfaceReady()190 private void onSurfaceReady() { 191 try { 192 IBinder hostToken = mView.getHostToken(); 193 // Should never be null when SurfaceView is attached to window. 194 if (hostToken != null) { 195 mClient.onCreateKeyguardSurface(hostToken, mCallback); 196 } else { 197 hide(); 198 } 199 } catch (RemoteException e) { 200 Log.e(TAG, "Error in onCreateKeyguardSurface", e); 201 dismiss(KeyguardUpdateMonitor.getCurrentUser()); 202 } 203 } 204 dismiss(int userId)205 private void dismiss(int userId) { 206 mHandler.removeCallbacksAndMessages(null); 207 if (mView.isAttachedToWindow() && userId == KeyguardUpdateMonitor.getCurrentUser()) { 208 hide(); 209 if (mKeyguardCallback != null) { 210 mKeyguardCallback.dismiss(/* securityVerified= */ true, userId, 211 /* bypassSecondaryLockScreen= */true); 212 } 213 } 214 } 215 216 /** 217 * Custom {@link SurfaceView} used to allow a device admin to present an additional security 218 * screen. 219 */ 220 private class AdminSecurityView extends SurfaceView { 221 private SurfaceHolder.Callback mSurfaceHolderCallback; 222 AdminSecurityView(Context context, SurfaceHolder.Callback surfaceHolderCallback)223 AdminSecurityView(Context context, SurfaceHolder.Callback surfaceHolderCallback) { 224 super(context); 225 mSurfaceHolderCallback = surfaceHolderCallback; 226 setZOrderOnTop(true); 227 } 228 229 @Override onAttachedToWindow()230 protected void onAttachedToWindow() { 231 super.onAttachedToWindow(); 232 getHolder().addCallback(mSurfaceHolderCallback); 233 } 234 235 @Override onDetachedFromWindow()236 protected void onDetachedFromWindow() { 237 super.onDetachedFromWindow(); 238 getHolder().removeCallback(mSurfaceHolderCallback); 239 } 240 } 241 242 @KeyguardBouncerScope 243 public static class Factory { 244 private final Context mContext; 245 private final KeyguardSecurityContainer mParent; 246 private final KeyguardUpdateMonitor mUpdateMonitor; 247 private final Handler mHandler; 248 249 @Inject Factory(Context context, KeyguardSecurityContainer parent, KeyguardUpdateMonitor updateMonitor, @Main Handler handler)250 public Factory(Context context, KeyguardSecurityContainer parent, 251 KeyguardUpdateMonitor updateMonitor, @Main Handler handler) { 252 mContext = context; 253 mParent = parent; 254 mUpdateMonitor = updateMonitor; 255 mHandler = handler; 256 } 257 create(KeyguardSecurityCallback callback)258 public AdminSecondaryLockScreenController create(KeyguardSecurityCallback callback) { 259 return new AdminSecondaryLockScreenController(mContext, mParent, mUpdateMonitor, 260 callback, mHandler); 261 } 262 } 263 } 264