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.profiles;
18 
19 import android.app.ActivityManager;
20 import android.car.user.CarUserManager;
21 import android.car.user.UserCreationResult;
22 import android.car.user.UserStartRequest;
23 import android.car.user.UserStopRequest;
24 import android.car.util.concurrent.AsyncFuture;
25 import android.content.Context;
26 import android.content.pm.UserInfo;
27 import android.os.AsyncTask;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 
31 import com.android.car.internal.user.UserHelper;
32 import com.android.car.settings.common.Logger;
33 
34 import java.util.concurrent.ExecutionException;
35 
36 /**
37  * Task to add a new profile to the device
38  */
39 public class AddNewProfileTask extends AsyncTask<String, Void, UserInfo> {
40     private static final Logger LOG = new Logger(AddNewProfileTask.class);
41 
42     private final Context mContext;
43     private final CarUserManager mCarUserManager;
44     private final AddNewProfileListener mAddNewProfileListener;
45     private final UserManager mUserManager;
46 
AddNewProfileTask(Context context, CarUserManager carUserManager, AddNewProfileListener addNewProfileListener)47     public AddNewProfileTask(Context context, CarUserManager carUserManager,
48             AddNewProfileListener addNewProfileListener) {
49         mContext = context;
50         mCarUserManager = carUserManager;
51         mAddNewProfileListener = addNewProfileListener;
52         mUserManager = context.getSystemService(UserManager.class);
53     }
54 
55     @Override
doInBackground(String... profileNames)56     protected UserInfo doInBackground(String... profileNames) {
57         AsyncFuture<UserCreationResult> future = mCarUserManager.createUser(profileNames[0],
58                 /* flags= */ 0);
59         try {
60             UserCreationResult result = future.get();
61             if (result.isSuccess()) {
62                 UserInfo user = mUserManager.getUserInfo(result.getUser().getIdentifier());
63                 if (user != null) {
64                     UserHelper.setDefaultNonAdminRestrictions(mContext, user.getUserHandle(),
65                             /* enable= */ true);
66                     UserHelper.assignDefaultIcon(mContext, user.getUserHandle());
67                 } else {
68                     LOG.wtf("Inconsistent state: successful future with null profile - "
69                             + result.toString());
70                 }
71                 return user;
72             }
73         } catch (InterruptedException | ExecutionException e) {
74             if (e instanceof InterruptedException) {
75                 Thread.currentThread().interrupt();
76             }
77             LOG.e("Error creating new profile: ", e);
78         }
79         return null;
80     }
81 
82     @Override
onPreExecute()83     protected void onPreExecute() { }
84 
85     @Override
onPostExecute(UserInfo user)86     protected void onPostExecute(UserInfo user) {
87         if (user != null) {
88             mAddNewProfileListener.onProfileAddedSuccess();
89             UserHandle currentUser = mContext.getUser();
90 
91             if (currentUser.getIdentifier() == ActivityManager.getCurrentUser()) {
92                 mCarUserManager.switchUser(user.id);
93             } else {
94                 // For passengers we need to call stop and start
95                 try {
96                     mCarUserManager.stopUser(
97                             new UserStopRequest.Builder(currentUser).setForce().build(),
98                             mContext.getMainExecutor(),
99                             result -> {
100                                 LOG.i("Stop user result: " + result.toString());
101                                 if (result.isSuccess()) {
102                                     startUser(user);
103                                 }
104                             });
105                 } catch (Exception e) {
106                     LOG.e("Exception stopping user " + currentUser, e);
107                 }
108             }
109         } else {
110             mAddNewProfileListener.onProfileAddedFailure();
111         }
112     }
113 
startUser(UserInfo user)114     private void startUser(UserInfo user) {
115         int displayId = mContext.getDisplayId();
116 
117         try {
118             mCarUserManager.startUser(
119                     new UserStartRequest.Builder(user.getUserHandle())
120                             .setDisplayId(displayId)
121                             .build(),
122                     Runnable::run,
123                     result -> LOG.i("Start user result: " + result.toString()));
124         } catch (Exception e) {
125             LOG.e("Exception starting user " + user.id, e);
126         }
127     }
128 
129     /**
130      * Interface for getting notified when AddNewProfileTask has been completed.
131      */
132     public interface AddNewProfileListener {
133         /**
134          * Invoked in AddNewProfileTask.onPostExecute after the profile has been created
135          * successfully.
136          */
onProfileAddedSuccess()137         void onProfileAddedSuccess();
138 
139         /**
140          * Invoked in AddNewProfileTask.onPostExecute if new profile creation failed.
141          */
onProfileAddedFailure()142         void onProfileAddedFailure();
143     }
144 }
145