1 /*
2  * Copyright (C) 2007 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.app;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SystemService;
24 import android.app.trust.ITrustManager;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.os.Binder;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.Looper;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.os.ServiceManager.ServiceNotFoundException;
36 import android.os.UserHandle;
37 import android.util.Log;
38 import android.view.IOnKeyguardExitResult;
39 import android.view.IWindowManager;
40 import android.view.WindowManager.LayoutParams;
41 import android.view.WindowManagerGlobal;
42 
43 import com.android.internal.policy.IKeyguardDismissCallback;
44 
45 import java.util.List;
46 
47 /**
48  * Class that can be used to lock and unlock the keyboard. The
49  * actual class to control the keyboard locking is
50  * {@link android.app.KeyguardManager.KeyguardLock}.
51  */
52 @SystemService(Context.KEYGUARD_SERVICE)
53 public class KeyguardManager {
54 
55     private static final String TAG = "KeyguardManager";
56 
57     private final Context mContext;
58     private final IWindowManager mWM;
59     private final IActivityManager mAm;
60     private final ITrustManager mTrustManager;
61 
62     /**
63      * Intent used to prompt user for device credentials.
64      * @hide
65      */
66     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL =
67             "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
68 
69     /**
70      * Intent used to prompt user for device credentials.
71      * @hide
72      */
73     public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
74             "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
75 
76     /**
77      * A CharSequence dialog title to show to the user when used with a
78      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
79      * @hide
80      */
81     public static final String EXTRA_TITLE = "android.app.extra.TITLE";
82 
83     /**
84      * A CharSequence description to show to the user when used with
85      * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
86      * @hide
87      */
88     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
89 
90     /**
91      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
92      * for the current user of the device. The caller is expected to launch this activity using
93      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
94      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
95      *
96      * @return the intent for launching the activity or null if no password is required.
97      **/
createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description)98     public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
99         if (!isDeviceSecure()) return null;
100         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
101         intent.putExtra(EXTRA_TITLE, title);
102         intent.putExtra(EXTRA_DESCRIPTION, description);
103 
104         // explicitly set the package for security
105         intent.setPackage(getSettingsPackageForIntent(intent));
106         return intent;
107     }
108 
109     /**
110      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
111      * for the given user. The caller is expected to launch this activity using
112      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
113      * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
114      *
115      * @return the intent for launching the activity or null if no password is required.
116      *
117      * @hide
118      */
createConfirmDeviceCredentialIntent( CharSequence title, CharSequence description, int userId)119     public Intent createConfirmDeviceCredentialIntent(
120             CharSequence title, CharSequence description, int userId) {
121         if (!isDeviceSecure(userId)) return null;
122         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
123         intent.putExtra(EXTRA_TITLE, title);
124         intent.putExtra(EXTRA_DESCRIPTION, description);
125         intent.putExtra(Intent.EXTRA_USER_ID, userId);
126 
127         // explicitly set the package for security
128         intent.setPackage(getSettingsPackageForIntent(intent));
129 
130         return intent;
131     }
132 
getSettingsPackageForIntent(Intent intent)133     private String getSettingsPackageForIntent(Intent intent) {
134         List<ResolveInfo> resolveInfos = mContext.getPackageManager()
135                 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
136         for (int i = 0; i < resolveInfos.size(); i++) {
137             return resolveInfos.get(i).activityInfo.packageName;
138         }
139 
140         return "com.android.settings";
141     }
142 
143     /**
144      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
145      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
146      * instead; this allows you to seamlessly hide the keyguard as your application
147      * moves in and out of the foreground and does not require that any special
148      * permissions be requested.
149      *
150      * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows
151      * you to disable / reenable the keyguard.
152      */
153     @Deprecated
154     public class KeyguardLock {
155         private final IBinder mToken = new Binder();
156         private final String mTag;
157 
KeyguardLock(String tag)158         KeyguardLock(String tag) {
159             mTag = tag;
160         }
161 
162         /**
163          * Disable the keyguard from showing.  If the keyguard is currently
164          * showing, hide it.  The keyguard will be prevented from showing again
165          * until {@link #reenableKeyguard()} is called.
166          *
167          * A good place to call this is from {@link android.app.Activity#onResume()}
168          *
169          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
170          * is enabled that requires a password.
171          *
172          * @see #reenableKeyguard()
173          */
174         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
disableKeyguard()175         public void disableKeyguard() {
176             try {
177                 mWM.disableKeyguard(mToken, mTag);
178             } catch (RemoteException ex) {
179             }
180         }
181 
182         /**
183          * Reenable the keyguard.  The keyguard will reappear if the previous
184          * call to {@link #disableKeyguard()} caused it to be hidden.
185          *
186          * A good place to call this is from {@link android.app.Activity#onPause()}
187          *
188          * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
189          * is enabled that requires a password.
190          *
191          * @see #disableKeyguard()
192          */
193         @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
reenableKeyguard()194         public void reenableKeyguard() {
195             try {
196                 mWM.reenableKeyguard(mToken);
197             } catch (RemoteException ex) {
198             }
199         }
200     }
201 
202     /**
203      * @deprecated Use {@link KeyguardDismissCallback}
204      * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
205      * caller of result.
206      */
207     @Deprecated
208     public interface OnKeyguardExitResult {
209 
210         /**
211          * @param success True if the user was able to authenticate, false if
212          *   not.
213          */
onKeyguardExitResult(boolean success)214         void onKeyguardExitResult(boolean success);
215     }
216 
217     /**
218      * Callback passed to {@link KeyguardManager#dismissKeyguard} to notify caller of result.
219      */
220     public static abstract class KeyguardDismissCallback {
221 
222         /**
223          * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
224          * available, not showing or when the activity requesting the Keyguard dismissal isn't
225          * showing or isn't showing behind Keyguard.
226          */
onDismissError()227         public void onDismissError() { }
228 
229         /**
230          * Called when dismissing Keyguard has succeeded and the device is now unlocked.
231          */
onDismissSucceeded()232         public void onDismissSucceeded() { }
233 
234         /**
235          * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
236          * operation or the bouncer was hidden for some other reason.
237          */
onDismissCancelled()238         public void onDismissCancelled() { }
239     }
240 
KeyguardManager(Context context)241     KeyguardManager(Context context) throws ServiceNotFoundException {
242         mContext = context;
243         mWM = WindowManagerGlobal.getWindowManagerService();
244         mAm = ActivityManager.getService();
245         mTrustManager = ITrustManager.Stub.asInterface(
246                 ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
247     }
248 
249     /**
250      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
251      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
252      * instead; this allows you to seamlessly hide the keyguard as your application
253      * moves in and out of the foreground and does not require that any special
254      * permissions be requested.
255      *
256      * Enables you to lock or unlock the keyboard. Get an instance of this class by
257      * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
258      * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}.
259      * @param tag A tag that informally identifies who you are (for debugging who
260      *   is disabling he keyguard).
261      *
262      * @return A {@link KeyguardLock} handle to use to disable and reenable the
263      *   keyguard.
264      */
265     @Deprecated
newKeyguardLock(String tag)266     public KeyguardLock newKeyguardLock(String tag) {
267         return new KeyguardLock(tag);
268     }
269 
270     /**
271      * Return whether the keyguard is currently locked.
272      *
273      * @return true if keyguard is locked.
274      */
isKeyguardLocked()275     public boolean isKeyguardLocked() {
276         try {
277             return mWM.isKeyguardLocked();
278         } catch (RemoteException ex) {
279             return false;
280         }
281     }
282 
283     /**
284      * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
285      * is currently locked.
286      *
287      * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
288      *
289      * @return true if a PIN, pattern or password is set or a SIM card is locked.
290      */
isKeyguardSecure()291     public boolean isKeyguardSecure() {
292         try {
293             return mWM.isKeyguardSecure();
294         } catch (RemoteException ex) {
295             return false;
296         }
297     }
298 
299     /**
300      * If keyguard screen is showing or in restricted key input mode (i.e. in
301      * keyguard password emergency screen). When in such mode, certain keys,
302      * such as the Home key and the right soft keys, don't work.
303      *
304      * @return true if in keyguard restricted input mode.
305      *
306      * @see android.view.WindowManagerPolicy#inKeyguardRestrictedKeyInputMode
307      */
inKeyguardRestrictedInputMode()308     public boolean inKeyguardRestrictedInputMode() {
309         try {
310             return mWM.inKeyguardRestrictedInputMode();
311         } catch (RemoteException ex) {
312             return false;
313         }
314     }
315 
316     /**
317      * Returns whether the device is currently locked and requires a PIN, pattern or
318      * password to unlock.
319      *
320      * @return true if unlocking the device currently requires a PIN, pattern or
321      * password.
322      */
isDeviceLocked()323     public boolean isDeviceLocked() {
324         return isDeviceLocked(UserHandle.myUserId());
325     }
326 
327     /**
328      * Per-user version of {@link #isDeviceLocked()}.
329      *
330      * @hide
331      */
isDeviceLocked(int userId)332     public boolean isDeviceLocked(int userId) {
333         try {
334             return mTrustManager.isDeviceLocked(userId);
335         } catch (RemoteException e) {
336             return false;
337         }
338     }
339 
340     /**
341      * Returns whether the device is secured with a PIN, pattern or
342      * password.
343      *
344      * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
345      *
346      * @return true if a PIN, pattern or password was set.
347      */
isDeviceSecure()348     public boolean isDeviceSecure() {
349         return isDeviceSecure(UserHandle.myUserId());
350     }
351 
352     /**
353      * Per-user version of {@link #isDeviceSecure()}.
354      *
355      * @hide
356      */
isDeviceSecure(int userId)357     public boolean isDeviceSecure(int userId) {
358         try {
359             return mTrustManager.isDeviceSecure(userId);
360         } catch (RemoteException e) {
361             return false;
362         }
363     }
364 
365     /** @removed */
366     @Deprecated
dismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback, @Nullable Handler handler)367     public void dismissKeyguard(@NonNull Activity activity,
368             @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
369         requestDismissKeyguard(activity, callback);
370     }
371 
372     /**
373      * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
374      * be dismissed.
375      * <p>
376      * If the Keyguard is not secure or the device is currently in a trusted state, calling this
377      * method will immediately dismiss the Keyguard without any user interaction.
378      * <p>
379      * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
380      * UI so the user can enter their credentials.
381      *
382      * @param activity The activity requesting the dismissal. The activity must be either visible
383      *                 by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
384      *                 which it would be visible if Keyguard would not be hiding it. If that's not
385      *                 the case, the request will fail immediately and
386      *                 {@link KeyguardDismissCallback#onDismissError} will be invoked.
387      * @param callback The callback to be called if the request to dismiss Keyguard was successful
388      *                 or {@code null} if the caller isn't interested in knowing the result. The
389      *                 callback will not be invoked if the activity was destroyed before the
390      *                 callback was received.
391      */
requestDismissKeyguard(@onNull Activity activity, @Nullable KeyguardDismissCallback callback)392     public void requestDismissKeyguard(@NonNull Activity activity,
393             @Nullable KeyguardDismissCallback callback) {
394         try {
395             mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
396                 @Override
397                 public void onDismissError() throws RemoteException {
398                     if (callback != null && !activity.isDestroyed()) {
399                         activity.mHandler.post(callback::onDismissError);
400                     }
401                 }
402 
403                 @Override
404                 public void onDismissSucceeded() throws RemoteException {
405                     if (callback != null && !activity.isDestroyed()) {
406                         activity.mHandler.post(callback::onDismissSucceeded);
407                     }
408                 }
409 
410                 @Override
411                 public void onDismissCancelled() throws RemoteException {
412                     if (callback != null && !activity.isDestroyed()) {
413                         activity.mHandler.post(callback::onDismissCancelled);
414                     }
415                 }
416             });
417         } catch (RemoteException e) {
418             Log.i(TAG, "Failed to dismiss keyguard: " + e);
419         }
420     }
421 
422     /**
423      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
424      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
425      * instead; this allows you to seamlessly hide the keyguard as your application
426      * moves in and out of the foreground and does not require that any special
427      * permissions be requested.
428      *
429      * Exit the keyguard securely.  The use case for this api is that, after
430      * disabling the keyguard, your app, which was granted permission to
431      * disable the keyguard and show a limited amount of information deemed
432      * safe without the user getting past the keyguard, needs to navigate to
433      * something that is not safe to view without getting past the keyguard.
434      *
435      * This will, if the keyguard is secure, bring up the unlock screen of
436      * the keyguard.
437      *
438      * @param callback Let's you know whether the operation was succesful and
439      *   it is safe to launch anything that would normally be considered safe
440      *   once the user has gotten past the keyguard.
441      */
442     @Deprecated
443     @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
exitKeyguardSecurely(final OnKeyguardExitResult callback)444     public void exitKeyguardSecurely(final OnKeyguardExitResult callback) {
445         try {
446             mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
447                 public void onKeyguardExitResult(boolean success) throws RemoteException {
448                     if (callback != null) {
449                         callback.onKeyguardExitResult(success);
450                     }
451                 }
452             });
453         } catch (RemoteException e) {
454 
455         }
456     }
457 }
458