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