• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 
17 package android.car.builtin.keyguard;
18 
19 import static android.os.PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON;
20 import static android.os.PowerManager.WAKE_REASON_POWER_BUTTON;
21 
22 import android.annotation.NonNull;
23 import android.annotation.RequiresApi;
24 import android.annotation.SystemApi;
25 import android.car.builtin.annotation.AddedIn;
26 import android.car.builtin.annotation.PlatformVersion;
27 import android.car.builtin.util.Slogf;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.ServiceConnection;
32 import android.content.res.Resources;
33 import android.os.Build;
34 import android.os.Handler;
35 import android.os.IBinder;
36 import android.os.PowerManager;
37 import android.os.RemoteException;
38 import android.os.UserHandle;
39 import android.util.Log;
40 
41 import com.android.internal.annotations.GuardedBy;
42 import com.android.internal.policy.IKeyguardDrawnCallback;
43 import com.android.internal.policy.IKeyguardService;
44 import com.android.internal.util.Preconditions;
45 
46 import java.io.PrintWriter;
47 import java.util.Arrays;
48 
49 /**
50  * Wrapper for KeyguardService
51  *
52  * Simplified version of com.android.server.policy.keyguard.KeyguardServiceDelegate. If something
53  * is not working, check for oversimplification from that class.
54  *
55  * @hide
56  */
57 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
58 public final class KeyguardServiceDelegate {
59     private static final String TAG = KeyguardServiceDelegate.class.getSimpleName();
60     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
61 
62     private final KeyguardStateMonitor.StateCallback mStateCallback;
63     private final Object mLock = new Object();
64     private IKeyguardService mKeyguardService;
65     private KeyguardStateMonitor mKeyguardStateMonitor;
66     @GuardedBy("mLock")
67     private KeyguardLockedStateCallback mLockedStateCallback;
68     private Handler mHandler;
69     private int mUserId;
70     private int[] mDisplays;
71 
72     private final IKeyguardDrawnCallback.Stub mKeyguardShowDelegate =
73             new IKeyguardDrawnCallback.Stub() {
74                 @Override
75                 public void onDrawn() {
76                     if (DBG) {
77                         Slogf.v(TAG, "KeyguardShowDelegate.onDrawn userId=%d", mUserId);
78                     }
79                 }
80             };
81 
82     private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
83         @Override
84         public void onServiceConnected(ComponentName name, IBinder service) {
85             if (DBG) {
86                 Slogf.d(TAG, "Keyguard connected for user %d", mUserId);
87             }
88             try {
89                 // replicated PhoneWindowManager order
90                 mKeyguardService = IKeyguardService.Stub.asInterface(service);
91                 mKeyguardService.onSystemReady();
92                 mKeyguardService.setCurrentUser(mUserId);
93                 mKeyguardStateMonitor = new KeyguardStateMonitor(mKeyguardService, mUserId,
94                         mStateCallback);
95 
96                 mKeyguardService.setSwitchingUser(false);
97                 mKeyguardService.onBootCompleted();
98                 mKeyguardService.onStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN, false);
99                 mKeyguardService.onFinishedWakingUp();
100                 mKeyguardService.onScreenTurningOn(mKeyguardShowDelegate);
101                 mKeyguardService.onScreenTurnedOn();
102             } catch (Exception e) {
103                 Slogf.e(TAG, e, "Can not start the keyguard");
104             }
105         }
106 
107         @Override
108         public void onServiceDisconnected(ComponentName name) {
109             if (DBG) {
110                 Slogf.d(TAG, "Keyguard disconnected for user %d", mUserId);
111             }
112             mKeyguardService = null;
113             mKeyguardStateMonitor = null;
114             // TODO(b/258238612): Enable once ActivityTaskManagerService APIs are ready
115             // mHandler.post(() -> {
116             //     try {
117             //         ActivityTaskManager.getService().setLockScreenShownForDisplays(
118             //                 /* showingKeyguard= */ true, /* showingAod= */ false, mDisplays);
119             //     } catch (RemoteException e) {
120             //     }
121             // });
122         }
123     };
124 
KeyguardServiceDelegate()125     public KeyguardServiceDelegate() {
126         mStateCallback = showing -> {
127             if (mHandler != null) {
128                 mHandler.post(() -> {
129                     synchronized (mLock) {
130                         if (mLockedStateCallback != null) {
131                             mLockedStateCallback.onKeyguardLockedStateChanged(showing);
132                         }
133                     }
134                 });
135             }
136         };
137     }
138 
139     /**
140      * Binds to the KeyguardService for a particular user and display(s).
141      */
142     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
143     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
bindService(Context context, UserHandle userHandle, int[] displays)144     public void bindService(Context context, UserHandle userHandle, int[] displays) {
145         if (DBG) {
146             Slogf.v(TAG, "bindService for user=%d, displays=%s", userHandle.getIdentifier(),
147                     Arrays.toString(displays));
148         }
149         mHandler = new Handler(context.getMainLooper());
150         mUserId = userHandle.getIdentifier();
151         mDisplays = displays;
152 
153         Intent intent = new Intent();
154         Resources resources = context.getApplicationContext().getResources();
155 
156         ComponentName keyguardComponent = ComponentName.unflattenFromString(
157                 resources.getString(com.android.internal.R.string.config_keyguardComponent));
158         intent.setComponent(keyguardComponent);
159 
160         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
161                 Context.BIND_AUTO_CREATE, mHandler, userHandle)) {
162             Slogf.e(TAG, "Keyguard: can't bind to " + keyguardComponent);
163         } else {
164             if (DBG) {
165                 Slogf.v(TAG, "Keyguard started for user=%d", mUserId);
166             }
167         }
168     }
169 
170     /**
171      * Unbinds the currently bound KeyguardService.
172      */
173     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
174     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
stop(Context context)175     public void stop(Context context) {
176         try {
177             context.unbindService(mKeyguardConnection);
178         } catch (Exception e) {
179             Slogf.e(TAG, "Can't unbind the KeyguardService", e);
180         }
181     }
182 
183     /**
184      * Returns whether Keyguard is showing for this delegate. If Keyguard is not bound, return true
185      * to assume the most secure state.
186      */
187     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
188     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
isShowing()189     public boolean isShowing() {
190         if (mKeyguardStateMonitor == null) {
191             if (DBG) {
192                 Slogf.d(TAG, "mKeyguardStateMonitor null for user=%d - returning default", mUserId);
193             }
194             return true;
195         }
196         boolean showing = mKeyguardStateMonitor.isShowing();
197         if (DBG) {
198             Slogf.d(TAG, "isShowing=%b for user=%d", showing, mUserId);
199         }
200         return showing;
201     }
202 
203     /**
204      * Register a KeyguardLockedStateCallback for this delegate.
205      */
206     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
207     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
registerKeyguardLockedStateCallback( @onNull KeyguardLockedStateCallback callback)208     public void registerKeyguardLockedStateCallback(
209             @NonNull KeyguardLockedStateCallback callback) {
210         synchronized (mLock) {
211             Preconditions.checkState(mLockedStateCallback == null,
212                     "Keyguard locked state callback already registered");
213             mLockedStateCallback = callback;
214         }
215     }
216 
217     /**
218      * Unregister a KeyguardLockedStateCallback from this delegate.
219      */
220     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
221     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
unregisterKeyguardLockedStateCallback()222     public void unregisterKeyguardLockedStateCallback() {
223         synchronized (mLock) {
224             Preconditions.checkNotNull(mLockedStateCallback,
225                     "Keyguard locked state callback never registered");
226             mLockedStateCallback = null;
227         }
228     }
229 
230     /**
231      * Notify Keyguard of a display on event.
232      */
233     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
234     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
notifyDisplayOn()235     public void notifyDisplayOn() {
236         if (mKeyguardService == null) {
237             Slogf.w(TAG, "onDisplayOn - null KeyguardService");
238             return;
239         }
240         try {
241             if (DBG) {
242                 Slogf.v(TAG, "onDisplayOn");
243             }
244             mKeyguardService.onStartedWakingUp(
245                     WAKE_REASON_POWER_BUTTON, /* cameraGestureTriggered= */ false);
246             mKeyguardService.onScreenTurningOn(mKeyguardShowDelegate);
247             mKeyguardService.onScreenTurnedOn();
248             mKeyguardService.onFinishedWakingUp();
249         } catch (RemoteException e) {
250             Slogf.e(TAG, "RemoteException", e);
251         }
252     }
253 
254     /**
255      * Notify Keyguard of a display off event.
256      */
257     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
258     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
notifyDisplayOff()259     public void notifyDisplayOff() {
260         if (mKeyguardService == null) {
261             Slogf.w(TAG, "onDisplayOff - null KeyguardService");
262             return;
263         }
264         try {
265             if (DBG) {
266                 Slogf.v(TAG, "onDisplayOff");
267             }
268             // TODO(b/258238612): check that nothing is missed comparing to foreground user behavior
269             mKeyguardService.onStartedGoingToSleep(GO_TO_SLEEP_REASON_POWER_BUTTON);
270             mKeyguardService.onScreenTurningOff();
271             mKeyguardService.onScreenTurnedOff();
272             mKeyguardService.onFinishedGoingToSleep(GO_TO_SLEEP_REASON_POWER_BUTTON, false);
273         } catch (RemoteException e) {
274             Slogf.e(TAG, "RemoteException", e);
275         }
276     }
277 
278     /**
279      * Dump the KeyguardServiceDelegate state
280      */
281     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
282     @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
dump(PrintWriter writer)283     public void dump(PrintWriter writer) {
284         writer.println("*KeyguardServiceDelegate*");
285         writer.println("Keyguard service connected = " + (mKeyguardService != null));
286         if (mKeyguardStateMonitor != null) {
287             mKeyguardStateMonitor.dump(writer);
288         }
289     }
290 
291     /**
292      * Callback interface that executes when the keyguard locked state changes.
293      */
294     public interface KeyguardLockedStateCallback {
295         /**
296          * Callback function that executes when the keyguard locked state changes.
297          */
298         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
299         @AddedIn(PlatformVersion.UPSIDE_DOWN_CAKE_0)
onKeyguardLockedStateChanged(boolean isKeyguardLocked)300         void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
301     }
302 }
303