1 /*
2  * Copyright (C) 2016 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 com.android.internal.app;
18 
19 import static android.Manifest.permission.HIDE_OVERLAY_WINDOWS;
20 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
21 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
22 import static android.hardware.biometrics.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
23 import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
24 import static android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED;
25 
26 import android.Manifest;
27 import android.annotation.IntDef;
28 import android.annotation.RequiresPermission;
29 import android.app.AlertDialog;
30 import android.app.KeyguardManager;
31 import android.content.ComponentName;
32 import android.content.DialogInterface;
33 import android.content.Intent;
34 import android.content.pm.UserInfo;
35 import android.os.Bundle;
36 import android.os.UserHandle;
37 import android.os.UserManager;
38 import android.util.Log;
39 
40 import com.android.internal.R;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 
45 /**
46  * A dialog shown to the user that prompts them to set the screen lock for the current foreground
47  * user. Should be called from the context of foreground user.
48  */
49 public class SetScreenLockDialogActivity extends AlertActivity
50         implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
51     private static final String TAG = "SetScreenLockDialog";
52     public static final String EXTRA_LAUNCH_REASON = "launch_reason";
53     /**
54      * User id associated with the workflow that wants to launch the prompt to set up the
55      * screen lock
56      */
57     public static final String EXTRA_ORIGIN_USER_ID = "origin_user_id";
58     private static final String PACKAGE_NAME = "android";
59     @IntDef(prefix = "LAUNCH_REASON_", value = {
60             LAUNCH_REASON_PRIVATE_SPACE_SETTINGS_ACCESS,
61             LAUNCH_REASON_DISABLE_QUIET_MODE,
62             LAUNCH_REASON_UNKNOWN,
63     })
64     @Retention(RetentionPolicy.SOURCE)
65     public @interface LaunchReason {
66     }
67     public static final int LAUNCH_REASON_UNKNOWN = -1;
68     public static final int LAUNCH_REASON_DISABLE_QUIET_MODE = 1;
69     public static final int LAUNCH_REASON_PRIVATE_SPACE_SETTINGS_ACCESS = 2;
70     private @LaunchReason int mReason;
71     private int mOriginUserId;
72 
73     @Override
74     @RequiresPermission(HIDE_OVERLAY_WINDOWS)
onCreate(Bundle savedInstanceState)75     protected void onCreate(Bundle savedInstanceState) {
76         super.onCreate(savedInstanceState);
77         if (!(android.os.Flags.allowPrivateProfile()
78                 && android.multiuser.Flags.showSetScreenLockDialog()
79                 && android.multiuser.Flags.enablePrivateSpaceFeatures())) {
80             finish();
81             return;
82         }
83         Intent intent = getIntent();
84         mReason = intent.getIntExtra(EXTRA_LAUNCH_REASON, LAUNCH_REASON_UNKNOWN);
85         mOriginUserId = intent.getIntExtra(EXTRA_ORIGIN_USER_ID, UserHandle.USER_NULL);
86 
87         if (mReason == LAUNCH_REASON_UNKNOWN) {
88             Log.e(TAG, "Invalid launch reason: " + mReason);
89             finish();
90             return;
91         }
92 
93         final KeyguardManager km = getSystemService(KeyguardManager.class);
94         if (km == null) {
95             Log.e(TAG, "Error fetching keyguard manager");
96             return;
97         }
98         if (km.isDeviceSecure()) {
99             Log.w(TAG, "Closing the activity since screen lock is already set");
100             return;
101         }
102 
103         Log.d(TAG, "Launching screen lock setup dialog due to " + mReason);
104         final AlertDialog.Builder builder = new AlertDialog.Builder(this);
105         builder.setTitle(R.string.set_up_screen_lock_title)
106                 .setOnDismissListener(this)
107                 .setPositiveButton(R.string.set_up_screen_lock_action_label, this)
108                 .setNegativeButton(R.string.cancel, this);
109         setLaunchUserSpecificMessage(builder);
110         final AlertDialog dialog = builder.create();
111         dialog.create();
112         getWindow().setHideOverlayWindows(true);
113         dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
114         dialog.show();
115     }
116 
117     @Override
onDismiss(DialogInterface dialog)118     public void onDismiss(DialogInterface dialog) {
119         finish();
120     }
121 
122     @Override
onClick(DialogInterface dialog, int which)123     public void onClick(DialogInterface dialog, int which) {
124         if (which == DialogInterface.BUTTON_POSITIVE) {
125             Intent setNewLockIntent = new Intent(ACTION_BIOMETRIC_ENROLL);
126             setNewLockIntent.putExtra(EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, DEVICE_CREDENTIAL);
127             startActivity(setNewLockIntent);
128         } else {
129             finish();
130         }
131     }
132 
133     @RequiresPermission(anyOf = {
134             Manifest.permission.MANAGE_USERS,
135             Manifest.permission.CREATE_USERS,
136             Manifest.permission.QUERY_USERS})
setLaunchUserSpecificMessage(AlertDialog.Builder builder)137     private void setLaunchUserSpecificMessage(AlertDialog.Builder builder) {
138         if (mReason == LAUNCH_REASON_PRIVATE_SPACE_SETTINGS_ACCESS) {
139             // Always set private space message if launch reason is specific to private space
140             builder.setMessage(R.string.private_space_set_up_screen_lock_message);
141             return;
142         }
143         final UserManager userManager = getApplicationContext().getSystemService(UserManager.class);
144         if (userManager != null) {
145             UserInfo userInfo = userManager.getUserInfo(mOriginUserId);
146             if (userInfo != null && userInfo.isPrivateProfile()) {
147                 builder.setMessage(R.string.private_space_set_up_screen_lock_message);
148             }
149         }
150     }
151 
152     /** Returns a basic intent to display the screen lock dialog */
createBaseIntent(@aunchReason int launchReason)153     public static Intent createBaseIntent(@LaunchReason int launchReason) {
154         Intent intent = new Intent();
155         intent.setComponent(new ComponentName(PACKAGE_NAME,
156                 SetScreenLockDialogActivity.class.getName()));
157         intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
158         intent.putExtra(EXTRA_LAUNCH_REASON, launchReason);
159         return intent;
160     }
161 }
162