1 /*
2  * Copyright (C) 2018 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.car.settings.users;
18 
19 import android.car.drivingstate.CarUxRestrictions;
20 import android.car.userlib.CarUserManagerHelper;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.AsyncTask;
24 import android.os.Bundle;
25 import android.view.View;
26 import android.widget.ProgressBar;
27 
28 import androidx.annotation.XmlRes;
29 
30 import com.android.car.settings.R;
31 import com.android.car.settings.common.ConfirmationDialogFragment;
32 import com.android.car.settings.common.ErrorDialog;
33 import com.android.car.settings.common.SettingsFragment;
34 import com.android.car.ui.toolbar.MenuItem;
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 import java.util.Collections;
38 import java.util.List;
39 
40 /**
41  * Lists all Users available on this device.
42  */
43 public class UsersListFragment extends SettingsFragment implements
44         ConfirmExitRetailModeDialog.ConfirmExitRetailModeListener,
45         AddNewUserTask.AddNewUserListener {
46     private static final String FACTORY_RESET_PACKAGE_NAME = "android";
47     private static final String FACTORY_RESET_REASON = "ExitRetailModeConfirmed";
48 
49     private CarUserManagerHelper mCarUserManagerHelper;
50 
51     private ProgressBar mProgressBar;
52     private MenuItem mAddUserButton;
53 
54     private AsyncTask mAddNewUserTask;
55     /** Indicates that a task is running. */
56     private boolean mIsBusy;
57 
58     @VisibleForTesting
59     final ConfirmationDialogFragment.ConfirmListener mConfirmListener = arguments -> {
60         mAddNewUserTask = new AddNewUserTask(mCarUserManagerHelper, /* addNewUserListener= */
61                 this).execute(getContext().getString(R.string.user_new_user_name));
62         mIsBusy = true;
63         updateUi();
64     };
65 
66     @Override
getToolbarMenuItems()67     public List<MenuItem> getToolbarMenuItems() {
68         return Collections.singletonList(mAddUserButton);
69     }
70 
71     @Override
onCreate(Bundle savedInstanceState)72     public void onCreate(Bundle savedInstanceState) {
73         super.onCreate(savedInstanceState);
74 
75         mAddUserButton = new MenuItem.Builder(getContext())
76                 .setOnClickListener(i -> handleAddUserClicked())
77                 .setTitle(mCarUserManagerHelper.isCurrentProcessDemoUser()
78                         ? R.string.exit_retail_button_text : R.string.user_add_user_menu)
79                 .setVisible(mCarUserManagerHelper.isCurrentProcessDemoUser()
80                         || mCarUserManagerHelper.canCurrentProcessAddUsers())
81                 .setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP)
82                 .build();
83     }
84 
85     @Override
86     @XmlRes
getPreferenceScreenResId()87     protected int getPreferenceScreenResId() {
88         return R.xml.users_list_fragment;
89     }
90 
91     @Override
onAttach(Context context)92     public void onAttach(Context context) {
93         super.onAttach(context);
94         mCarUserManagerHelper = new CarUserManagerHelper(getContext());
95     }
96 
97     @Override
onActivityCreated(Bundle savedInstanceState)98     public void onActivityCreated(Bundle savedInstanceState) {
99         super.onActivityCreated(savedInstanceState);
100         mProgressBar = getToolbar().getProgressBar();
101     }
102 
103     /**
104      * Will perform a factory reset. Copied from
105      * {@link com.android.settings.MasterClearConfirm#doMasterClear()}
106      */
107     @Override
onExitRetailModeConfirmed()108     public void onExitRetailModeConfirmed() {
109         Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
110         intent.setPackage(FACTORY_RESET_PACKAGE_NAME);
111         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
112         intent.putExtra(Intent.EXTRA_REASON, FACTORY_RESET_REASON);
113         intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, true);
114         intent.putExtra(Intent.EXTRA_WIPE_ESIMS, true);
115         getActivity().sendBroadcast(intent);
116         // Intent handling is asynchronous -- assume it will happen soon.
117     }
118 
119     @Override
onStart()120     public void onStart() {
121         super.onStart();
122         updateUi();
123     }
124 
125     @Override
onStop()126     public void onStop() {
127         super.onStop();
128         mProgressBar.setVisibility(View.GONE);
129     }
130 
131     @Override
onDestroy()132     public void onDestroy() {
133         super.onDestroy();
134 
135         if (mAddNewUserTask != null) {
136             mAddNewUserTask.cancel(/* mayInterruptIfRunning= */ false);
137         }
138     }
139 
140     @Override
onUserAddedSuccess()141     public void onUserAddedSuccess() {
142         mIsBusy = false;
143         updateUi();
144     }
145 
146     @Override
onUserAddedFailure()147     public void onUserAddedFailure() {
148         mIsBusy = false;
149         updateUi();
150         // Display failure dialog.
151         ErrorDialog.show(this, R.string.add_user_error_title);
152     }
153 
updateUi()154     private void updateUi() {
155         mAddUserButton.setEnabled(!mIsBusy);
156         mProgressBar.setVisibility(mIsBusy ? View.VISIBLE : View.GONE);
157     }
158 
handleAddUserClicked()159     private void handleAddUserClicked() {
160         // If the user is a demo user, show a dialog asking if they want to exit retail/demo mode.
161         if (mCarUserManagerHelper.isCurrentProcessDemoUser()) {
162             ConfirmExitRetailModeDialog dialog = new ConfirmExitRetailModeDialog();
163             dialog.setConfirmExitRetailModeListener(this);
164             dialog.show(this);
165             return;
166         }
167 
168         // If no more users can be added because the maximum allowed number is reached, let the user
169         // know.
170         if (mCarUserManagerHelper.isUserLimitReached()) {
171             MaxUsersLimitReachedDialog dialog = new MaxUsersLimitReachedDialog(
172                     mCarUserManagerHelper.getMaxSupportedRealUsers());
173             dialog.show(this);
174             return;
175         }
176 
177         // Only add the add user button if the current user is allowed to add a user.
178         if (mCarUserManagerHelper.canCurrentProcessAddUsers()) {
179             ConfirmationDialogFragment dialogFragment =
180                     UsersDialogProvider.getConfirmCreateNewUserDialogFragment(getContext(),
181                             mConfirmListener, null);
182 
183             dialogFragment.show(getFragmentManager(), ConfirmationDialogFragment.TAG);
184         }
185     }
186 }
187