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 android.car.user;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.UserIdInt;
23 import android.car.Car;
24 import android.car.CarManagerBase;
25 import android.car.ICarUserService;
26 import android.car.annotation.ExperimentalFeature;
27 import android.content.pm.UserInfo;
28 import android.os.RemoteException;
29 import android.os.UserHandle;
30 import android.util.Log;
31 
32 import com.android.internal.infra.AndroidFuture;
33 
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.List;
37 
38 /**
39  * Temporary class containing {@link CarUserManager} features that are not ready yet.
40  *
41  * <p>New instances are created through {@link #from(CarUserManager)}.
42  *
43  * @hide
44  */
45 @ExperimentalFeature
46 public final class ExperimentalCarUserManager extends CarManagerBase {
47 
48     private static final String TAG = ExperimentalCarUserManager.class.getSimpleName();
49 
50     /**
51      *  User id representing invalid user.
52      */
53     private static final int INVALID_USER_ID = UserHandle.USER_NULL;
54 
55     private final ICarUserService mService;
56 
57     /**
58      * Factory method to create a new instance.
59      */
from(@onNull CarUserManager carUserManager)60     public static ExperimentalCarUserManager from(@NonNull CarUserManager carUserManager) {
61         return carUserManager.newExperimentalCarUserManager();
62     }
63 
ExperimentalCarUserManager(@onNull Car car, @NonNull ICarUserService service)64     ExperimentalCarUserManager(@NonNull Car car, @NonNull ICarUserService service) {
65         super(car);
66 
67         mService = service;
68     }
69 
70     /**
71      * Creates a driver who is a regular user and is allowed to login to the driving occupant zone.
72      *
73      * @param name The name of the driver to be created.
74      * @param admin Whether the created driver will be an admin.
75      * @return an {@link AndroidFuture} that can be used to track operation's completion and
76      *         retrieve its result (if any).
77      *
78      * @hide
79      */
80     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
createDriver(@onNull String name, boolean admin)81     public AndroidFuture<UserCreationResult> createDriver(@NonNull String name, boolean admin) {
82         try {
83             return mService.createDriver(name, admin);
84         } catch (RemoteException e) {
85             AndroidFuture<UserCreationResult> future = new AndroidFuture<>();
86             future.complete(new UserCreationResult(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE,
87                     null, null));
88             handleRemoteExceptionFromCarService(e);
89             return future;
90         }
91     }
92 
93     /**
94      * Creates a passenger who is a profile of the given driver.
95      *
96      * @param name The name of the passenger to be created.
97      * @param driverId User id of the driver under whom a passenger is created.
98      * @return user id of the created passenger, or {@code INVALID_USER_ID} if the passenger
99      *         could not be created.
100      *
101      * @hide
102      */
103     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
104     @Nullable
createPassenger(@onNull String name, @UserIdInt int driverId)105     public int createPassenger(@NonNull String name, @UserIdInt int driverId) {
106         try {
107             UserInfo ui = mService.createPassenger(name, driverId);
108             return ui != null ? ui.id : INVALID_USER_ID;
109         } catch (RemoteException e) {
110             return handleRemoteExceptionFromCarService(e, null);
111         }
112     }
113 
114     /**
115      * Switches a driver to the given user.
116      *
117      * @param driverId User id of the driver to switch to.
118      * @return an {@link AndroidFuture} that can be used to track operation's completion and
119      *         retrieve its result (if any).
120      *
121      * @hide
122      */
123     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
switchDriver(@serIdInt int driverId)124     public AndroidFuture<UserSwitchResult> switchDriver(@UserIdInt int driverId) {
125         try {
126             AndroidFuture<UserSwitchResult> future = new AndroidFuture<>() {
127                 @Override
128                 protected void onCompleted(UserSwitchResult result, Throwable err) {
129                     if (result == null) {
130                         Log.w(TAG, "switchDriver(" + driverId + ") failed: " + err);
131                     }
132                     super.onCompleted(result, err);
133                 }
134             };
135             mService.switchDriver(driverId, future);
136             return future;
137         } catch (RemoteException e) {
138             AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
139             future.complete(
140                     new UserSwitchResult(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE, null));
141             handleRemoteExceptionFromCarService(e);
142             return future;
143         }
144     }
145 
146     /**
147      * Returns all drivers who can occupy the driving zone. Guest users are included in the list.
148      *
149      * @return the list of user ids who can be a driver on the device.
150      *
151      * @hide
152      */
153     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
154     @NonNull
getAllDrivers()155     public List<Integer> getAllDrivers() {
156         try {
157             return getUserIdsFromUserInfos(mService.getAllDrivers());
158         } catch (RemoteException e) {
159             return handleRemoteExceptionFromCarService(e, Collections.emptyList());
160         }
161     }
162 
163     /**
164      * Returns all passengers under the given driver.
165      *
166      * @param driverId User id of a driver.
167      * @return the list of user ids who are passengers under the given driver.
168      *
169      * @hide
170      */
171     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
172     @NonNull
getPassengers(@serIdInt int driverId)173     public List<Integer> getPassengers(@UserIdInt int driverId) {
174         try {
175             return getUserIdsFromUserInfos(mService.getPassengers(driverId));
176         } catch (RemoteException e) {
177             return handleRemoteExceptionFromCarService(e, Collections.emptyList());
178         }
179     }
180 
181     /**
182      * Assigns the passenger to the zone and starts the user if it is not started yet.
183      *
184      * @param passengerId User id of the passenger to be started.
185      * @param zoneId Zone id to which the passenger is assigned.
186      * @return {@code true} if the user is successfully started or the user is already running.
187      *         Otherwise, {@code false}.
188      *
189      * @hide
190      */
191     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
startPassenger(@serIdInt int passengerId, int zoneId)192     public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
193         try {
194             return mService.startPassenger(passengerId, zoneId);
195         } catch (RemoteException e) {
196             return handleRemoteExceptionFromCarService(e, false);
197         }
198     }
199 
200     /**
201      * Stops the given passenger.
202      *
203      * @param passengerId User id of the passenger to be stopped.
204      * @return {@code true} if successfully stopped, or {@code false} if failed.
205      *
206      * @hide
207      */
208     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
stopPassenger(@serIdInt int passengerId)209     public boolean stopPassenger(@UserIdInt int passengerId) {
210         try {
211             return mService.stopPassenger(passengerId);
212         } catch (RemoteException e) {
213             return handleRemoteExceptionFromCarService(e, false);
214         }
215     }
216 
217     /** @hide */
218     @Override
onCarDisconnected()219     public void onCarDisconnected() {
220         // nothing to do
221     }
222 
getUserIdsFromUserInfos(List<UserInfo> infos)223     private List<Integer> getUserIdsFromUserInfos(List<UserInfo> infos) {
224         List<Integer> ids = new ArrayList<>(infos.size());
225         for (UserInfo ui : infos) {
226             ids.add(ui.id);
227         }
228         return ids;
229     }
230 }
231