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 
17 package com.android.systemui.user;
18 
19 import android.app.Activity;
20 import android.app.Dialog;
21 import android.app.IActivityManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.graphics.drawable.Drawable;
25 import android.os.Bundle;
26 import android.os.RemoteException;
27 import android.util.Log;
28 import android.window.OnBackInvokedCallback;
29 import android.window.OnBackInvokedDispatcher;
30 
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 
34 import com.android.internal.logging.UiEventLogger;
35 import com.android.settingslib.users.CreateUserDialogController;
36 import com.android.systemui.plugins.ActivityStarter;
37 import com.android.systemui.res.R;
38 
39 import javax.inject.Inject;
40 
41 /**
42  * This screen shows a Dialog for choosing nickname and photo for a new user, and then delegates the
43  * user creation to a UserCreator.
44  */
45 public class CreateUserActivity extends Activity {
46 
47     /**
48      * Creates an intent to start this activity.
49      */
createIntentForStart(Context context, boolean isKeyguardShowing)50     public static Intent createIntentForStart(Context context, boolean isKeyguardShowing) {
51         Intent intent = new Intent(context, CreateUserActivity.class);
52         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
53         intent.putExtra(EXTRA_IS_KEYGUARD_SHOWING, isKeyguardShowing);
54         return intent;
55     }
56 
57     private static final String TAG = "CreateUserActivity";
58     private static final String DIALOG_STATE_KEY = "create_user_dialog_state";
59     private static final String EXTRA_IS_KEYGUARD_SHOWING = "extra_is_keyguard_showing";
60 
61     private final UserCreator mUserCreator;
62     private CreateUserDialogController mCreateUserDialogController;
63     private final IActivityManager mActivityManager;
64     private final ActivityStarter mActivityStarter;
65     private final UiEventLogger mUiEventLogger;
66     private Dialog mSetupUserDialog;
67     private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
68     @Inject
CreateUserActivity(UserCreator userCreator, CreateUserDialogController createUserDialogController, IActivityManager activityManager, ActivityStarter activityStarter, UiEventLogger uiEventLogger)69     public CreateUserActivity(UserCreator userCreator,
70             CreateUserDialogController createUserDialogController, IActivityManager activityManager,
71             ActivityStarter activityStarter, UiEventLogger uiEventLogger) {
72         mUserCreator = userCreator;
73         mCreateUserDialogController = createUserDialogController;
74         mActivityManager = activityManager;
75         mActivityStarter = activityStarter;
76         mUiEventLogger = uiEventLogger;
77     }
78 
79     @Override
onCreate(@ullable Bundle savedInstanceState)80     protected void onCreate(@Nullable Bundle savedInstanceState) {
81         super.onCreate(savedInstanceState);
82         setShowWhenLocked(true);
83         setContentView(R.layout.activity_create_new_user);
84         if (savedInstanceState != null) {
85             mCreateUserDialogController.onRestoreInstanceState(savedInstanceState);
86         }
87         mSetupUserDialog = createDialog();
88         mSetupUserDialog.show();
89         getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
90                         OnBackInvokedDispatcher.PRIORITY_DEFAULT,
91                         mBackCallback);
92     }
93 
94     @Override
onSaveInstanceState(@onNull Bundle outState)95     protected void onSaveInstanceState(@NonNull Bundle outState) {
96         if (mSetupUserDialog != null && mSetupUserDialog.isShowing()) {
97             outState.putBundle(DIALOG_STATE_KEY, mSetupUserDialog.onSaveInstanceState());
98         }
99 
100         mCreateUserDialogController.onSaveInstanceState(outState);
101         super.onSaveInstanceState(outState);
102     }
103 
104     @Override
onRestoreInstanceState(@onNull Bundle savedInstanceState)105     protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
106         super.onRestoreInstanceState(savedInstanceState);
107         Bundle savedDialogState = savedInstanceState.getBundle(DIALOG_STATE_KEY);
108         if (savedDialogState != null && mSetupUserDialog != null) {
109             mSetupUserDialog.onRestoreInstanceState(savedDialogState);
110         }
111     }
112 
createDialog()113     private Dialog createDialog() {
114         String defaultUserName = getString(com.android.settingslib.R.string.user_new_user_name);
115         boolean isKeyguardShowing = getIntent().getBooleanExtra(EXTRA_IS_KEYGUARD_SHOWING, true);
116         return mCreateUserDialogController.createDialog(
117                 this,
118                 this::startActivity,
119                 (mUserCreator.isMultipleAdminEnabled() && mUserCreator.isUserAdmin()
120                         && !isKeyguardShowing),
121                 this::addUserNow,
122                 this::finish
123         );
124     }
125 
126     @Override
onActivityResult(int requestCode, int resultCode, Intent data)127     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
128         super.onActivityResult(requestCode, resultCode, data);
129         mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
130     }
131 
132     @Override
onBackPressed()133     public void onBackPressed() {
134         onBackInvoked();
135     }
136 
onBackInvoked()137     private void onBackInvoked() {
138         if (mSetupUserDialog != null) {
139             mSetupUserDialog.dismiss();
140         }
141         finish();
142     }
143 
144     @Override
onDestroy()145     protected void onDestroy() {
146         getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback);
147         super.onDestroy();
148     }
149 
addUserNow(String userName, Drawable userIcon, Boolean isAdmin)150     private void addUserNow(String userName, Drawable userIcon, Boolean isAdmin) {
151         mSetupUserDialog.dismiss();
152         userName = (userName == null || userName.trim().isEmpty())
153                 ? getString(com.android.settingslib.R.string.user_new_user_name)
154                 : userName;
155 
156         mUserCreator.createUser(userName, userIcon,
157                 userInfo -> {
158                     if (isAdmin) {
159                         mUserCreator.setUserAdmin(userInfo.id);
160                     }
161                     switchToUser(userInfo.id);
162                     finishIfNeeded();
163                 }, () -> {
164                     Log.e(TAG, "Unable to create user");
165                     finishIfNeeded();
166                 });
167     }
168 
finishIfNeeded()169     private void finishIfNeeded() {
170         if (!isFinishing() && !isDestroyed()) {
171             finish();
172         }
173     }
174 
switchToUser(int userId)175     private void switchToUser(int userId) {
176         try {
177             mActivityManager.switchUser(userId);
178         } catch (RemoteException e) {
179             Log.e(TAG, "Couldn't switch user.", e);
180         }
181     }
182 
183     /**
184      * Lambda to start activity from an intent. Ensures that device is unlocked first.
185      * @param intent
186      * @param requestCode
187      */
startActivity(Intent intent, int requestCode)188     private void startActivity(Intent intent, int requestCode) {
189         mActivityStarter.dismissKeyguardThenExecute(() -> {
190             mCreateUserDialogController.startingActivityForResult();
191             startActivityForResult(intent, requestCode);
192             return true;
193         }, /* cancel= */ null, /* afterKeyguardGone= */ true);
194     }
195 }
196