1 /* 2 * Copyright (C) 2023 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.car.userpicker; 18 19 import static android.car.CarOccupantZoneManager.DISPLAY_TYPE_MAIN; 20 import static android.car.CarOccupantZoneManager.INVALID_USER_ID; 21 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER; 22 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER; 23 import static android.car.CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER; 24 import static android.car.CarOccupantZoneManager.USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE; 25 import static android.car.VehicleAreaSeat.SEAT_ROW_1_CENTER; 26 import static android.car.VehicleAreaSeat.SEAT_ROW_1_LEFT; 27 import static android.car.VehicleAreaSeat.SEAT_ROW_1_RIGHT; 28 import static android.car.VehicleAreaSeat.SEAT_ROW_2_CENTER; 29 import static android.car.VehicleAreaSeat.SEAT_ROW_2_LEFT; 30 import static android.car.VehicleAreaSeat.SEAT_ROW_2_RIGHT; 31 import static android.car.VehicleAreaSeat.SEAT_ROW_3_CENTER; 32 import static android.car.VehicleAreaSeat.SEAT_ROW_3_LEFT; 33 import static android.car.VehicleAreaSeat.SEAT_ROW_3_RIGHT; 34 import static android.view.Display.INVALID_DISPLAY; 35 36 import android.annotation.Nullable; 37 import android.annotation.UserIdInt; 38 import android.car.Car; 39 import android.car.CarOccupantZoneManager; 40 import android.car.CarOccupantZoneManager.OccupantZoneInfo; 41 import android.car.hardware.power.CarPowerManager; 42 import android.car.user.CarUserManager; 43 import android.car.user.CarUserManager.UserLifecycleListener; 44 import android.car.user.UserLifecycleEventFilter; 45 import android.content.Context; 46 import android.util.Pair; 47 import android.util.Slog; 48 import android.view.Display; 49 50 import androidx.annotation.VisibleForTesting; 51 52 import com.android.systemui.R; 53 import com.android.systemui.car.CarServiceProvider; 54 55 import java.util.HashMap; 56 import java.util.List; 57 import java.util.Map; 58 import java.util.concurrent.Executor; 59 60 import javax.inject.Inject; 61 62 @UserPickerScope 63 final class CarServiceMediator { 64 private static final String TAG = CarServiceMediator.class.getSimpleName(); 65 66 // These are needed when getting the string of the seat for users. 67 private String mSeatDriver; 68 private String mSeatFront; 69 private String mSeatRear; 70 private String mSeatLeftSide; 71 private String mSeatCenterSide; 72 private String mSeatRightSide; 73 74 private CarOccupantZoneManager mCarOccupantZoneManager; 75 private CarUserManager mCarUserManager; 76 private CarPowerManager mCarPowerManager; 77 78 private final Context mContext; 79 private final CarServiceProvider mCarServiceProvider; 80 private final Map<UserLifecycleListener, Pair<Executor, UserLifecycleEventFilter>> 81 mUserLifecycleListeners = new HashMap<>(); 82 83 private final CarServiceProvider.CarServiceOnConnectedListener mServiceOnConnectedListener = 84 new CarServiceProvider.CarServiceOnConnectedListener() { 85 @Override 86 public void onConnected(Car car) { 87 onConnect(car); 88 } 89 }; 90 91 @Inject CarServiceMediator(Context context, CarServiceProvider carServiceProvider)92 CarServiceMediator(Context context, CarServiceProvider carServiceProvider) { 93 mContext = context.getApplicationContext(); 94 mCarServiceProvider = carServiceProvider; 95 mCarServiceProvider.addListener(mServiceOnConnectedListener); 96 97 updateTexts(); 98 } 99 100 @VisibleForTesting onConnect(Car car)101 void onConnect(Car car) { 102 mCarOccupantZoneManager = car.getCarManager(CarOccupantZoneManager.class); 103 mCarUserManager = car.getCarManager(CarUserManager.class); 104 mCarPowerManager = car.getCarManager(CarPowerManager.class); 105 //re-register listeners in case of CarService crash and recreation 106 if (mCarUserManager != null) { 107 for (UserLifecycleListener listener : mUserLifecycleListeners.keySet()) { 108 mCarUserManager.addListener(mUserLifecycleListeners.get(listener).first, 109 mUserLifecycleListeners.get(listener).second, listener); 110 } 111 } 112 } 113 updateTexts()114 void updateTexts() { 115 mSeatDriver = mContext.getString(R.string.seat_driver); 116 mSeatFront = mContext.getString(R.string.seat_front); 117 mSeatRear = mContext.getString(R.string.seat_rear); 118 mSeatLeftSide = mContext.getString(R.string.seat_left_side); 119 mSeatCenterSide = mContext.getString(R.string.seat_center_side); 120 mSeatRightSide = mContext.getString(R.string.seat_right_side); 121 } 122 registerUserChangeEventsListener(Executor receiver, UserLifecycleEventFilter filter, UserLifecycleListener listener)123 void registerUserChangeEventsListener(Executor receiver, UserLifecycleEventFilter filter, 124 UserLifecycleListener listener) { 125 mUserLifecycleListeners.put(listener, new Pair<>(receiver, filter)); 126 if (mCarUserManager != null) { 127 mCarUserManager.addListener(receiver, filter, listener); 128 } 129 } 130 onDestroy()131 void onDestroy() { 132 for (UserLifecycleListener listener : mUserLifecycleListeners.keySet()) { 133 mCarUserManager.removeListener(listener); 134 } 135 mUserLifecycleListeners.clear(); 136 mCarServiceProvider.removeListener(mServiceOnConnectedListener); 137 } 138 139 @Nullable getCarUserManager()140 CarUserManager getCarUserManager() { 141 return mCarUserManager; 142 } 143 144 @Nullable getOccupantZoneForDisplayId(int displayId)145 OccupantZoneInfo getOccupantZoneForDisplayId(int displayId) { 146 if (mCarOccupantZoneManager == null || displayId == INVALID_DISPLAY) { 147 Slog.w(TAG, "Cannot get occupant zone manager or has been requested for invalid" 148 + " display."); 149 return null; 150 } 151 152 List<OccupantZoneInfo> occupantZoneInfos = mCarOccupantZoneManager.getAllOccupantZones(); 153 for (int index = 0; index < occupantZoneInfos.size(); index++) { 154 CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(index); 155 List<Display> displays = mCarOccupantZoneManager.getAllDisplaysForOccupant( 156 occupantZoneInfo); 157 for (int displayIndex = 0; displayIndex < displays.size(); displayIndex++) { 158 if (displays.get(displayIndex).getDisplayId() == displayId) { 159 return occupantZoneInfo; 160 } 161 } 162 } 163 return null; 164 } 165 getDisplayIdForUser(@serIdInt int userId)166 int getDisplayIdForUser(@UserIdInt int userId) { 167 if (mCarOccupantZoneManager == null) { 168 Slog.w(TAG, "Cannot get occupant zone manager."); 169 return INVALID_DISPLAY; 170 } 171 172 List<OccupantZoneInfo> occupantZoneInfos = mCarOccupantZoneManager.getAllOccupantZones(); 173 for (int i = 0; i < occupantZoneInfos.size(); i++) { 174 OccupantZoneInfo zoneInfo = occupantZoneInfos.get(i); 175 int zoneUserId = mCarOccupantZoneManager.getUserForOccupant(zoneInfo); 176 if (zoneUserId == userId) { 177 Display d = mCarOccupantZoneManager.getDisplayForOccupant(zoneInfo, 178 DISPLAY_TYPE_MAIN); 179 return d != null ? d.getDisplayId() : INVALID_DISPLAY; 180 } 181 } 182 return INVALID_DISPLAY; 183 } 184 getUserForDisplay(int displayId)185 int getUserForDisplay(int displayId) { 186 if (mCarOccupantZoneManager == null) { 187 Slog.w(TAG, "Cannot get occupant zone manager."); 188 return INVALID_USER_ID; 189 } 190 191 return mCarOccupantZoneManager.getUserForDisplayId(displayId); 192 } 193 unassignOccupantZoneForDisplay(int displayId)194 int unassignOccupantZoneForDisplay(int displayId) { 195 OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId); 196 if (zoneInfo == null) { 197 // Return any error code for this situation. 198 Slog.w(TAG, "Cannot find occupant zone info associated with display " + displayId); 199 return USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE; 200 } 201 return mCarOccupantZoneManager.unassignOccupantZone(zoneInfo); 202 } 203 getSeatString(int displayId)204 String getSeatString(int displayId) { 205 String seatString = ""; 206 OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId); 207 if (zoneInfo == null) { 208 Slog.w(TAG, "Cannot find occupant zone info associated with display " + displayId); 209 return seatString; 210 } 211 212 switch (zoneInfo.occupantType) { 213 case OCCUPANT_TYPE_FRONT_PASSENGER: 214 return mSeatFront + " " + getSeatSideString(zoneInfo.seat); 215 case OCCUPANT_TYPE_REAR_PASSENGER: 216 return mSeatRear + " " + getSeatSideString(zoneInfo.seat); 217 case OCCUPANT_TYPE_DRIVER: 218 return mSeatDriver; 219 } 220 return seatString; 221 } 222 getSeatSideString(int seat)223 private String getSeatSideString(int seat) { 224 switch (seat) { 225 case SEAT_ROW_1_LEFT: 226 case SEAT_ROW_2_LEFT: 227 case SEAT_ROW_3_LEFT: 228 return mSeatLeftSide; 229 case SEAT_ROW_1_CENTER: 230 case SEAT_ROW_2_CENTER: 231 case SEAT_ROW_3_CENTER: 232 return mSeatCenterSide; 233 case SEAT_ROW_1_RIGHT: 234 case SEAT_ROW_2_RIGHT: 235 case SEAT_ROW_3_RIGHT: 236 return mSeatRightSide; 237 default: 238 return ""; 239 } 240 } 241 screenOffDisplay(int displayId)242 void screenOffDisplay(int displayId) { 243 if (mCarPowerManager == null) { 244 Slog.e(TAG, "Cannot get power manager."); 245 return; 246 } 247 mCarPowerManager.setDisplayPowerState(displayId, /* enable= */ false); 248 } 249 } 250