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 mCarServiceProvider.addListener(car -> { 128 mCarUserManager.addListener(receiver, filter, listener); 129 }); 130 } 131 } 132 onDestroy()133 void onDestroy() { 134 for (UserLifecycleListener listener : mUserLifecycleListeners.keySet()) { 135 mCarUserManager.removeListener(listener); 136 } 137 mUserLifecycleListeners.clear(); 138 mCarServiceProvider.removeListener(mServiceOnConnectedListener); 139 } 140 141 @Nullable getCarUserManager()142 CarUserManager getCarUserManager() { 143 return mCarUserManager; 144 } 145 146 @Nullable getOccupantZoneForDisplayId(int displayId)147 OccupantZoneInfo getOccupantZoneForDisplayId(int displayId) { 148 if (mCarOccupantZoneManager == null || displayId == INVALID_DISPLAY) { 149 Slog.w(TAG, "Cannot get occupant zone manager or has been requested for invalid" 150 + " display."); 151 return null; 152 } 153 154 List<OccupantZoneInfo> occupantZoneInfos = mCarOccupantZoneManager.getAllOccupantZones(); 155 for (int index = 0; index < occupantZoneInfos.size(); index++) { 156 CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = occupantZoneInfos.get(index); 157 List<Display> displays = mCarOccupantZoneManager.getAllDisplaysForOccupant( 158 occupantZoneInfo); 159 for (int displayIndex = 0; displayIndex < displays.size(); displayIndex++) { 160 if (displays.get(displayIndex).getDisplayId() == displayId) { 161 return occupantZoneInfo; 162 } 163 } 164 } 165 return null; 166 } 167 getDisplayIdForUser(@serIdInt int userId)168 int getDisplayIdForUser(@UserIdInt int userId) { 169 if (mCarOccupantZoneManager == null) { 170 Slog.w(TAG, "Cannot get occupant zone manager."); 171 return INVALID_DISPLAY; 172 } 173 174 List<OccupantZoneInfo> occupantZoneInfos = mCarOccupantZoneManager.getAllOccupantZones(); 175 for (int i = 0; i < occupantZoneInfos.size(); i++) { 176 OccupantZoneInfo zoneInfo = occupantZoneInfos.get(i); 177 int zoneUserId = mCarOccupantZoneManager.getUserForOccupant(zoneInfo); 178 if (zoneUserId == userId) { 179 Display d = mCarOccupantZoneManager.getDisplayForOccupant(zoneInfo, 180 DISPLAY_TYPE_MAIN); 181 return d != null ? d.getDisplayId() : INVALID_DISPLAY; 182 } 183 } 184 return INVALID_DISPLAY; 185 } 186 getUserForDisplay(int displayId)187 int getUserForDisplay(int displayId) { 188 if (mCarOccupantZoneManager == null) { 189 Slog.w(TAG, "Cannot get occupant zone manager."); 190 return INVALID_USER_ID; 191 } 192 193 return mCarOccupantZoneManager.getUserForDisplayId(displayId); 194 } 195 unassignOccupantZoneForDisplay(int displayId)196 int unassignOccupantZoneForDisplay(int displayId) { 197 OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId); 198 if (zoneInfo == null) { 199 // Return any error code for this situation. 200 Slog.w(TAG, "Cannot find occupant zone info associated with display " + displayId); 201 return USER_ASSIGNMENT_RESULT_FAIL_DRIVER_ZONE; 202 } 203 return mCarOccupantZoneManager.unassignOccupantZone(zoneInfo); 204 } 205 getSeatString(int displayId)206 String getSeatString(int displayId) { 207 String seatString = ""; 208 OccupantZoneInfo zoneInfo = getOccupantZoneForDisplayId(displayId); 209 if (zoneInfo == null) { 210 Slog.w(TAG, "Cannot find occupant zone info associated with display " + displayId); 211 return seatString; 212 } 213 214 switch (zoneInfo.occupantType) { 215 case OCCUPANT_TYPE_FRONT_PASSENGER: 216 return mSeatFront + " " + getSeatSideString(zoneInfo.seat); 217 case OCCUPANT_TYPE_REAR_PASSENGER: 218 return mSeatRear + " " + getSeatSideString(zoneInfo.seat); 219 case OCCUPANT_TYPE_DRIVER: 220 return mSeatDriver; 221 } 222 return seatString; 223 } 224 getSeatSideString(int seat)225 private String getSeatSideString(int seat) { 226 switch (seat) { 227 case SEAT_ROW_1_LEFT: 228 case SEAT_ROW_2_LEFT: 229 case SEAT_ROW_3_LEFT: 230 return mSeatLeftSide; 231 case SEAT_ROW_1_CENTER: 232 case SEAT_ROW_2_CENTER: 233 case SEAT_ROW_3_CENTER: 234 return mSeatCenterSide; 235 case SEAT_ROW_1_RIGHT: 236 case SEAT_ROW_2_RIGHT: 237 case SEAT_ROW_3_RIGHT: 238 return mSeatRightSide; 239 default: 240 return ""; 241 } 242 } 243 screenOffDisplay(int displayId)244 void screenOffDisplay(int displayId) { 245 if (mCarPowerManager == null) { 246 Slog.e(TAG, "Cannot get power manager."); 247 return; 248 } 249 mCarPowerManager.setDisplayPowerState(displayId, /* enable= */ false); 250 } 251 } 252