• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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;
18 
19 import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
20 import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
21 import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_OK;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.Mockito.when;
26 
27 import android.car.CarOccupantZoneManager;
28 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
29 import android.car.VehicleAreaSeat;
30 import android.os.UserHandle;
31 import android.util.SparseIntArray;
32 import android.view.Display;
33 
34 import org.mockito.Mock;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 /**
40  * This provides simple mock for {@link com.android.car.CarOccupantZoneService}.
41  *
42  * <p>For simplicity, only main display is supported and display id and zone id will be the same.
43  */
44 public final class OccupantZoneHelper {
45 
46     public final CarOccupantZoneManager.OccupantZoneInfo zoneDriverLHD = new OccupantZoneInfo(0,
47             CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
48             VehicleAreaSeat.SEAT_ROW_1_LEFT);
49     public final OccupantZoneInfo zoneFrontPassengerLHD = new OccupantZoneInfo(1,
50             CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
51             VehicleAreaSeat.SEAT_ROW_1_RIGHT);
52     public final OccupantZoneInfo zoneRearLeft = new OccupantZoneInfo(2,
53             CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
54             VehicleAreaSeat.SEAT_ROW_2_LEFT);
55     public final OccupantZoneInfo zoneRearRight = new OccupantZoneInfo(3,
56             CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
57             VehicleAreaSeat.SEAT_ROW_2_RIGHT);
58     public final OccupantZoneInfo zoneRearCenter = new OccupantZoneInfo(4,
59             CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
60             VehicleAreaSeat.SEAT_ROW_2_CENTER);
61 
62     private final List<CarOccupantZoneManager.OccupantZoneInfo> mZones = new ArrayList<>();
63     private final SparseIntArray mZoneToUser = new SparseIntArray(); // key: zone, value: user id
64     // Default driver user ID is 10.
65     private int mDriverUserId = 10;
66 
67     /**
68      * Sets up occupant zones.
69      *
70      * @param service The mocked service
71      * @param hasDriver Does it have a driver
72      * @param hasFrontPassenger Does the front passenger exist
73      * @param numRearPassengers number of rear passengers
74      */
setUpOccupantZones(@ock CarOccupantZoneService service, boolean hasDriver, boolean hasFrontPassenger, int numRearPassengers)75     public void setUpOccupantZones(@Mock CarOccupantZoneService service, boolean hasDriver,
76             boolean hasFrontPassenger, int numRearPassengers) {
77         if (hasDriver) {
78             mZones.add(zoneDriverLHD);
79         }
80         if (hasFrontPassenger) {
81             mZones.add(zoneFrontPassengerLHD);
82         }
83         if (numRearPassengers >= 1) {
84             mZones.add(zoneRearLeft);
85         }
86         if (numRearPassengers == 2) {
87             mZones.add(zoneRearRight);
88         }
89         if (numRearPassengers == 3) {
90             mZones.add(zoneRearCenter);
91         }
92         if (numRearPassengers > 3) {
93             throw new IllegalArgumentException("Supports only up to 3 rear passengers");
94         }
95 
96         // All following mocking are dynamic based on mZones and other params.
97         when(service.getAllOccupantZones()).thenAnswer(inv -> mZones);
98         when(service.hasDriverZone()).thenReturn(hasDriver);
99         when(service.getNumberOfPassengerZones()).thenReturn(
100                 numRearPassengers + (hasFrontPassenger ? 1 : 0));
101         when(service.getOccupantZone(anyInt(), anyInt())).thenAnswer(
102                 inv -> {
103                     int type = (int) inv.getArgument(0);
104                     int seat = (int) inv.getArgument(1);
105                     if (type == CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER) {
106                         if (hasDriver) {
107                             return zoneDriverLHD;
108                         } else {
109                             return null;
110                         }
111                     }
112                     for (OccupantZoneInfo zone : mZones) {
113                         if (zone.occupantType == type && zone.seat == seat) {
114                             return zone;
115                         }
116                     }
117                     return null;
118                 }
119         );
120         when(service.getDisplayForOccupant(anyInt(), anyInt())).thenAnswer(
121                 inv -> {
122                     int zoneId = (int) inv.getArgument(0);
123                     int displayType = (int) inv.getArgument(1);
124                     if (displayType != CarOccupantZoneManager.DISPLAY_TYPE_MAIN) {
125                         return Display.INVALID_DISPLAY;
126                     }
127                     for (OccupantZoneInfo zone : mZones) {
128                         if (zone.zoneId == zoneId) {
129                             return zoneId; // display id and zone id the same
130                         }
131                     }
132                     return Display.INVALID_DISPLAY;
133                 }
134         );
135         when(service.assignVisibleUserToOccupantZone(anyInt(), any())).thenAnswer(
136                 inv -> {
137                     int zoneId = (int) inv.getArgument(0);
138                     UserHandle user = (UserHandle) inv.getArgument(1);
139                     int userId = user.getIdentifier();
140                     if (!hasZone(zoneId)) {
141                         return USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
142                     }
143                     if (mZones.contains(zoneDriverLHD) && zoneDriverLHD.zoneId == zoneId) {
144                         return USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
145                     }
146                     int existingIndex = mZoneToUser.indexOfValue(userId);
147                     if (existingIndex >= 0) {
148                         int preassignedZone = mZoneToUser.keyAt(existingIndex);
149                         if (preassignedZone == zoneId) {
150                             return USER_ASSIGNMENT_RESULT_OK;
151                         } else {
152                             return USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
153                         }
154                     }
155                     mZoneToUser.append(zoneId, userId);
156                     return USER_ASSIGNMENT_RESULT_OK;
157                 }
158         );
159         when(service.unassignOccupantZone(anyInt())).thenAnswer(
160                 inv -> {
161                     int zoneId = (int) inv.getArgument(0);
162                     if (!hasZone(zoneId)) {
163                         return USER_ASSIGNMENT_RESULT_FAIL_ALREADY_ASSIGNED;
164                     }
165                     if (mZones.contains(zoneDriverLHD) && zoneDriverLHD.zoneId == zoneId) {
166                         return USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE;
167                     }
168                     int existingIndex = mZoneToUser.indexOfKey(zoneId);
169                     if (existingIndex >= 0) {
170                         mZoneToUser.delete(zoneId);
171                     }
172                     return USER_ASSIGNMENT_RESULT_OK;
173                 }
174         );
175         when(service.getOccupantZoneIdForUserId(anyInt())).thenAnswer(
176                 inv -> {
177                     int userId = (int) inv.getArgument(0);
178                     for (int i = 0; i < mZoneToUser.size(); i++) {
179                         int user = mZoneToUser.valueAt(i);
180                         int zoneId = mZoneToUser.keyAt(i);
181                         if (user == userId) {
182                             return zoneId;
183                         }
184                     }
185                     return OccupantZoneInfo.INVALID_ZONE_ID;
186                 }
187         );
188         when(service.getUserForOccupant(anyInt())).thenAnswer(
189                 inv -> {
190                     int zoneId = (int) inv.getArgument(0);
191                     if (mZones.contains(zoneDriverLHD) && zoneDriverLHD.zoneId == zoneId) {
192                         return mDriverUserId;
193                     }
194                     int existingIndex = mZoneToUser.indexOfKey(zoneId);
195                     if (existingIndex >= 0) {
196                         return mZoneToUser.valueAt(existingIndex);
197                     }
198                     return CarOccupantZoneManager.INVALID_USER_ID;
199                 }
200         );
201     }
202 
203     /**
204      * Gets the display Id
205      * @param zone The OccupantZoneInfo
206      * @return DisplayId
207      */
getDisplayId(OccupantZoneInfo zone)208     public int getDisplayId(OccupantZoneInfo zone) {
209         return zone.zoneId; // For simplicity, use the same id with zone.
210     }
211 
setDriverUserId(int userId)212     public void setDriverUserId(int userId) {
213         mDriverUserId = userId;
214     }
215 
hasZone(int zoneId)216     private boolean hasZone(int zoneId) {
217         for (OccupantZoneInfo zone : mZones) {
218             if (zoneId == zone.zoneId) {
219                 return true;
220             }
221         }
222         return false;
223     }
224 }
225