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
17package android.app;
18
19import android.Manifest;
20import android.annotation.RequiresPermission;
21import android.app.trust.ITrustManager;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.UserInfo;
25import android.os.Binder;
26import android.os.RemoteException;
27import android.os.IBinder;
28import android.os.IUserManager;
29import android.os.ServiceManager;
30import android.os.UserHandle;
31import android.os.UserManager;
32import android.view.IWindowManager;
33import android.view.IOnKeyguardExitResult;
34import android.view.WindowManagerGlobal;
35
36/**
37 * Class that can be used to lock and unlock the keyboard. Get an instance of this
38 * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
39 * with argument {@link android.content.Context#KEYGUARD_SERVICE}. The
40 * actual class to control the keyboard locking is
41 * {@link android.app.KeyguardManager.KeyguardLock}.
42 */
43public class KeyguardManager {
44    private IWindowManager mWM;
45    private ITrustManager mTrustManager;
46    private IUserManager mUserManager;
47
48    /**
49     * Intent used to prompt user for device credentials.
50     * @hide
51     */
52    public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL =
53            "android.app.action.CONFIRM_DEVICE_CREDENTIAL";
54
55    /**
56     * Intent used to prompt user for device credentials.
57     * @hide
58     */
59    public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
60            "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
61
62    /**
63     * A CharSequence dialog title to show to the user when used with a
64     * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
65     * @hide
66     */
67    public static final String EXTRA_TITLE = "android.app.extra.TITLE";
68
69    /**
70     * A CharSequence description to show to the user when used with
71     * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
72     * @hide
73     */
74    public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
75
76    /**
77     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
78     * for the current user of the device. The caller is expected to launch this activity using
79     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
80     * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
81     *
82     * @return the intent for launching the activity or null if no password is required.
83     **/
84    public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
85        if (!isDeviceSecure()) return null;
86        Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
87        intent.putExtra(EXTRA_TITLE, title);
88        intent.putExtra(EXTRA_DESCRIPTION, description);
89        // For security reasons, only allow this to come from system settings.
90        intent.setPackage("com.android.settings");
91        return intent;
92    }
93
94    /**
95     * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
96     * for the given user. The caller is expected to launch this activity using
97     * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
98     * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
99     *
100     * @return the intent for launching the activity or null if no password is required.
101     *
102     * @hide
103     */
104    public Intent createConfirmDeviceCredentialIntent(
105            CharSequence title, CharSequence description, int userId) {
106        if (!isDeviceSecure(userId)) return null;
107        Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
108        intent.putExtra(EXTRA_TITLE, title);
109        intent.putExtra(EXTRA_DESCRIPTION, description);
110        intent.putExtra(Intent.EXTRA_USER_ID, userId);
111        // For security reasons, only allow this to come from system settings.
112        intent.setPackage("com.android.settings");
113        return intent;
114    }
115
116    /**
117     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
118     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
119     * instead; this allows you to seamlessly hide the keyguard as your application
120     * moves in and out of the foreground and does not require that any special
121     * permissions be requested.
122     *
123     * Handle returned by {@link KeyguardManager#newKeyguardLock} that allows
124     * you to disable / reenable the keyguard.
125     */
126    public class KeyguardLock {
127        private final IBinder mToken = new Binder();
128        private final String mTag;
129
130        KeyguardLock(String tag) {
131            mTag = tag;
132        }
133
134        /**
135         * Disable the keyguard from showing.  If the keyguard is currently
136         * showing, hide it.  The keyguard will be prevented from showing again
137         * until {@link #reenableKeyguard()} is called.
138         *
139         * A good place to call this is from {@link android.app.Activity#onResume()}
140         *
141         * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
142         * is enabled that requires a password.
143         *
144         * <p>This method requires the caller to hold the permission
145         * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
146         *
147         * @see #reenableKeyguard()
148         */
149        @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
150        public void disableKeyguard() {
151            try {
152                mWM.disableKeyguard(mToken, mTag);
153            } catch (RemoteException ex) {
154            }
155        }
156
157        /**
158         * Reenable the keyguard.  The keyguard will reappear if the previous
159         * call to {@link #disableKeyguard()} caused it to be hidden.
160         *
161         * A good place to call this is from {@link android.app.Activity#onPause()}
162         *
163         * Note: This call has no effect while any {@link android.app.admin.DevicePolicyManager}
164         * is enabled that requires a password.
165         *
166         * <p>This method requires the caller to hold the permission
167         * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
168         *
169         * @see #disableKeyguard()
170         */
171        @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
172        public void reenableKeyguard() {
173            try {
174                mWM.reenableKeyguard(mToken);
175            } catch (RemoteException ex) {
176            }
177        }
178    }
179
180    /**
181     * Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
182     * caller of result.
183     */
184    public interface OnKeyguardExitResult {
185
186        /**
187         * @param success True if the user was able to authenticate, false if
188         *   not.
189         */
190        void onKeyguardExitResult(boolean success);
191    }
192
193
194    KeyguardManager() {
195        mWM = WindowManagerGlobal.getWindowManagerService();
196        mTrustManager = ITrustManager.Stub.asInterface(
197                ServiceManager.getService(Context.TRUST_SERVICE));
198        mUserManager = IUserManager.Stub.asInterface(
199                ServiceManager.getService(Context.USER_SERVICE));
200    }
201
202    /**
203     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
204     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
205     * instead; this allows you to seamlessly hide the keyguard as your application
206     * moves in and out of the foreground and does not require that any special
207     * permissions be requested.
208     *
209     * Enables you to lock or unlock the keyboard. Get an instance of this class by
210     * calling {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
211     * This class is wrapped by {@link android.app.KeyguardManager KeyguardManager}.
212     * @param tag A tag that informally identifies who you are (for debugging who
213     *   is disabling he keyguard).
214     *
215     * @return A {@link KeyguardLock} handle to use to disable and reenable the
216     *   keyguard.
217     */
218    @Deprecated
219    public KeyguardLock newKeyguardLock(String tag) {
220        return new KeyguardLock(tag);
221    }
222
223    /**
224     * Return whether the keyguard is currently locked.
225     *
226     * @return true if keyguard is locked.
227     */
228    public boolean isKeyguardLocked() {
229        try {
230            return mWM.isKeyguardLocked();
231        } catch (RemoteException ex) {
232            return false;
233        }
234    }
235
236    /**
237     * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
238     * is currently locked.
239     *
240     * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
241     *
242     * @return true if a PIN, pattern or password is set or a SIM card is locked.
243     */
244    public boolean isKeyguardSecure() {
245        try {
246            return mWM.isKeyguardSecure();
247        } catch (RemoteException ex) {
248            return false;
249        }
250    }
251
252    /**
253     * If keyguard screen is showing or in restricted key input mode (i.e. in
254     * keyguard password emergency screen). When in such mode, certain keys,
255     * such as the Home key and the right soft keys, don't work.
256     *
257     * @return true if in keyguard restricted input mode.
258     *
259     * @see android.view.WindowManagerPolicy#inKeyguardRestrictedKeyInputMode
260     */
261    public boolean inKeyguardRestrictedInputMode() {
262        try {
263            return mWM.inKeyguardRestrictedInputMode();
264        } catch (RemoteException ex) {
265            return false;
266        }
267    }
268
269    /**
270     * Returns whether the device is currently locked and requires a PIN, pattern or
271     * password to unlock.
272     *
273     * @return true if unlocking the device currently requires a PIN, pattern or
274     * password.
275     */
276    public boolean isDeviceLocked() {
277        return isDeviceLocked(UserHandle.getCallingUserId());
278    }
279
280    /**
281     * Per-user version of {@link #isDeviceLocked()}.
282     *
283     * @hide
284     */
285    public boolean isDeviceLocked(int userId) {
286        ITrustManager trustManager = getTrustManager();
287        try {
288            return trustManager.isDeviceLocked(userId);
289        } catch (RemoteException e) {
290            return false;
291        }
292    }
293
294    /**
295     * Returns whether the device is secured with a PIN, pattern or
296     * password.
297     *
298     * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
299     *
300     * @return true if a PIN, pattern or password was set.
301     */
302    public boolean isDeviceSecure() {
303        return isDeviceSecure(UserHandle.getCallingUserId());
304    }
305
306    /**
307     * Per-user version of {@link #isDeviceSecure()}.
308     *
309     * @hide
310     */
311    public boolean isDeviceSecure(int userId) {
312        ITrustManager trustManager = getTrustManager();
313        try {
314            return trustManager.isDeviceSecure(userId);
315        } catch (RemoteException e) {
316            return false;
317        }
318    }
319
320    private synchronized ITrustManager getTrustManager() {
321        if (mTrustManager == null) {
322            mTrustManager = ITrustManager.Stub.asInterface(
323                    ServiceManager.getService(Context.TRUST_SERVICE));
324        }
325        return mTrustManager;
326    }
327
328    /**
329     * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
330     * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
331     * instead; this allows you to seamlessly hide the keyguard as your application
332     * moves in and out of the foreground and does not require that any special
333     * permissions be requested.
334     *
335     * Exit the keyguard securely.  The use case for this api is that, after
336     * disabling the keyguard, your app, which was granted permission to
337     * disable the keyguard and show a limited amount of information deemed
338     * safe without the user getting past the keyguard, needs to navigate to
339     * something that is not safe to view without getting past the keyguard.
340     *
341     * This will, if the keyguard is secure, bring up the unlock screen of
342     * the keyguard.
343     *
344     * <p>This method requires the caller to hold the permission
345     * {@link android.Manifest.permission#DISABLE_KEYGUARD}.
346     *
347     * @param callback Let's you know whether the operation was succesful and
348     *   it is safe to launch anything that would normally be considered safe
349     *   once the user has gotten past the keyguard.
350     */
351    @Deprecated
352    @RequiresPermission(Manifest.permission.DISABLE_KEYGUARD)
353    public void exitKeyguardSecurely(final OnKeyguardExitResult callback) {
354        try {
355            mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
356                public void onKeyguardExitResult(boolean success) throws RemoteException {
357                    if (callback != null) {
358                        callback.onKeyguardExitResult(success);
359                    }
360                }
361            });
362        } catch (RemoteException e) {
363
364        }
365    }
366}
367