1 /* 2 * Copyright (C) 2016 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 com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 20 21 import android.annotation.IntDef; 22 import android.app.UiModeManager; 23 import android.car.builtin.util.Slogf; 24 import android.car.hardware.CarPropertyValue; 25 import android.car.hardware.property.CarPropertyEvent; 26 import android.car.hardware.property.ICarPropertyEventListener; 27 import android.content.Context; 28 import android.hardware.automotive.vehicle.VehicleProperty; 29 import android.os.RemoteException; 30 31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 32 import com.android.car.internal.util.IndentingPrintWriter; 33 import com.android.internal.annotations.GuardedBy; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.util.List; 38 39 /** 40 * Class used to handle events used to set vehicle in night mode. 41 */ 42 public class CarNightService implements CarServiceBase { 43 44 public static final boolean DBG = false; 45 46 @IntDef({FORCED_SENSOR_MODE, FORCED_DAY_MODE, FORCED_NIGHT_MODE}) 47 @Retention(RetentionPolicy.SOURCE) 48 public @interface DayNightSensorMode {} 49 50 public static final int FORCED_SENSOR_MODE = 0; 51 public static final int FORCED_DAY_MODE = 1; 52 public static final int FORCED_NIGHT_MODE = 2; 53 54 private final Object mLock = new Object(); 55 @GuardedBy("mLock") 56 private int mNightSetting = UiModeManager.MODE_NIGHT_YES; 57 @GuardedBy("mLock") 58 private int mForcedMode = FORCED_SENSOR_MODE; 59 @GuardedBy("mLock") 60 private long mLastSensorEventTime = -1; 61 private final Context mContext; 62 @GuardedBy("mLock") 63 private final UiModeManager mUiModeManager; 64 private final CarPropertyService mCarPropertyService; 65 66 private final ICarPropertyEventListener mICarPropertyEventListener = 67 new ICarPropertyEventListener.Stub() { 68 @Override 69 public void onEvent(List<CarPropertyEvent> events) throws RemoteException { 70 synchronized (mLock) { 71 for (CarPropertyEvent event : events) { 72 onNightModeCarPropertyEventLocked(event); 73 } 74 } 75 } 76 }; 77 78 /** 79 * Acts on {@link CarPropertyEvent} events marked with {@link 80 * CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE} and marked with {@link 81 * VehicleProperty.NIGHT_MODE} by setting the vehicle in night mode. 82 * <p> 83 * This method does nothing if the event parameter is {@code null}. 84 * 85 * @param event the car property event to be handled 86 */ 87 @GuardedBy("mLock") onNightModeCarPropertyEventLocked(CarPropertyEvent event)88 private void onNightModeCarPropertyEventLocked(CarPropertyEvent event) { 89 if (event == null) { 90 return; 91 } 92 if (event.getEventType() == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE) { 93 // Only handle onChange events 94 CarPropertyValue value = event.getCarPropertyValue(); 95 if (value.getPropertyId() == VehicleProperty.NIGHT_MODE 96 && value.getTimestamp() > mLastSensorEventTime) { 97 mLastSensorEventTime = value.getTimestamp(); 98 boolean nightMode = (Boolean) value.getValue(); 99 Slogf.i(CarLog.TAG_SENSOR, "Set dayNight Mode as " 100 + nightMode + " at timestamp: " + mLastSensorEventTime); 101 setNightModeLocked(nightMode); 102 } 103 } 104 } 105 106 @GuardedBy("mLock") setNightModeLocked(boolean nightMode)107 private void setNightModeLocked(boolean nightMode) { 108 if (nightMode) { 109 mNightSetting = UiModeManager.MODE_NIGHT_YES; 110 if (DBG) Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent NIGHT"); 111 } else { 112 mNightSetting = UiModeManager.MODE_NIGHT_NO; 113 if (DBG) Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent DAY"); 114 } 115 if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) { 116 mUiModeManager.setNightMode(mNightSetting); 117 if (DBG) Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent APPLIED"); 118 } else { 119 if (DBG) Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent IGNORED"); 120 } 121 } 122 123 /** 124 * Sets {@link UiModeManager} to night mode according to the {@link DayNightSensorMode} passed 125 * as parameter. 126 * 127 * @param mode the sensor mode used to set vehicle in night mode 128 * @return the current night mode, or {@code -1} on error 129 */ forceDayNightMode(@ayNightSensorMode int mode)130 public int forceDayNightMode(@DayNightSensorMode int mode) { 131 synchronized (mLock) { 132 if (mUiModeManager == null) { 133 return -1; 134 } 135 int resultMode; 136 switch (mode) { 137 case FORCED_SENSOR_MODE: 138 resultMode = mNightSetting; 139 mForcedMode = FORCED_SENSOR_MODE; 140 break; 141 case FORCED_DAY_MODE: 142 resultMode = UiModeManager.MODE_NIGHT_NO; 143 mForcedMode = FORCED_DAY_MODE; 144 break; 145 case FORCED_NIGHT_MODE: 146 resultMode = UiModeManager.MODE_NIGHT_YES; 147 mForcedMode = FORCED_NIGHT_MODE; 148 break; 149 default: 150 Slogf.e(CarLog.TAG_SENSOR, "Unknown forced day/night mode " + mode); 151 return -1; 152 } 153 mUiModeManager.setNightMode(resultMode); 154 return mUiModeManager.getNightMode(); 155 } 156 } 157 CarNightService(Context context, CarPropertyService propertyService)158 CarNightService(Context context, CarPropertyService propertyService) { 159 mContext = context; 160 mCarPropertyService = propertyService; 161 mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE); 162 if (mUiModeManager == null) { 163 Slogf.w(CarLog.TAG_SENSOR, "Failed to get UI_MODE_SERVICE"); 164 } 165 } 166 167 @Override init()168 public void init() { 169 if (DBG) { 170 Slogf.d(CarLog.TAG_SENSOR, "CAR dayNight init."); 171 } 172 synchronized (mLock) { 173 mCarPropertyService.registerListener(VehicleProperty.NIGHT_MODE, 0, 174 mICarPropertyEventListener); 175 CarPropertyValue propertyValue = mCarPropertyService.getPropertySafe( 176 VehicleProperty.NIGHT_MODE, 0); 177 if (propertyValue != null && propertyValue.getTimestamp() != 0) { 178 mLastSensorEventTime = propertyValue.getTimestamp(); 179 setNightModeLocked((Boolean) propertyValue.getValue()); 180 } else { 181 Slogf.w(CarLog.TAG_SENSOR, "Failed to get value of NIGHT_MODE"); 182 setNightModeLocked(true); 183 } 184 } 185 } 186 187 @Override release()188 public void release() { 189 } 190 191 @Override 192 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)193 public void dump(IndentingPrintWriter writer) { 194 synchronized (mLock) { 195 writer.println("*DAY NIGHT POLICY*"); 196 writer.println( 197 "Mode:" + ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day")); 198 writer.println("Forced Mode? " + (mForcedMode == FORCED_SENSOR_MODE 199 ? "false, timestamp of dayNight sensor is: " + mLastSensorEventTime 200 : (mForcedMode == FORCED_DAY_MODE ? "day" : "night"))); 201 } 202 } 203 } 204