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.server.display.config;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.res.Resources;
22 import android.text.TextUtils;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.server.display.feature.DisplayManagerFlags;
26 
27 import java.util.Collections;
28 import java.util.List;
29 
30 /**
31  * Uniquely identifies a Sensor, with the combination of Type and Name.
32  */
33 public class SensorData {
34 
35     public static final String TEMPERATURE_TYPE_DISPLAY = "DISPLAY";
36     public static final String TEMPERATURE_TYPE_SKIN = "SKIN";
37 
38     @Nullable
39     public final String type;
40     @Nullable
41     public final String name;
42     public final float minRefreshRate;
43     public final float maxRefreshRate;
44     public final List<SupportedModeData> supportedModes;
45 
46     @VisibleForTesting
SensorData()47     public SensorData() {
48         this(/* type= */ null, /* name= */ null);
49     }
50 
51     @VisibleForTesting
SensorData(String type, String name)52     public SensorData(String type, String name) {
53         this(type, name, /* minRefreshRate= */ 0f, /* maxRefreshRate= */ Float.POSITIVE_INFINITY);
54     }
55 
56     @VisibleForTesting
SensorData(String type, String name, float minRefreshRate, float maxRefreshRate)57     public SensorData(String type, String name, float minRefreshRate, float maxRefreshRate) {
58         this(type, name, minRefreshRate, maxRefreshRate, /* supportedModes= */ List.of());
59     }
60 
61     @VisibleForTesting
SensorData(String type, String name, float minRefreshRate, float maxRefreshRate, List<SupportedModeData> supportedModes)62     public SensorData(String type, String name, float minRefreshRate, float maxRefreshRate,
63             List<SupportedModeData> supportedModes) {
64         this.type = type;
65         this.name = name;
66         this.minRefreshRate = minRefreshRate;
67         this.maxRefreshRate = maxRefreshRate;
68         this.supportedModes = Collections.unmodifiableList(supportedModes);
69     }
70 
71     /**
72      * @return True if the sensor matches both the specified name and type, or one if only one
73      * is specified (not-empty). Always returns false if both parameters are null or empty.
74      */
matches(String sensorName, String sensorType)75     public boolean matches(String sensorName, String sensorType) {
76         final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
77         final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
78         return (isNameSpecified || isTypeSpecified)
79                 && (!isNameSpecified || sensorName.equals(name))
80                 && (!isTypeSpecified || sensorType.equals(type));
81     }
82 
83     @Override
toString()84     public String toString() {
85         return "SensorData{"
86                 + "type= " + type
87                 + ", name= " + name
88                 + ", refreshRateRange: [" + minRefreshRate + ", " + maxRefreshRate + "]"
89                 + ", supportedModes=" + supportedModes
90                 + '}';
91     }
92 
93     /**
94      * Loads ambient light sensor data from DisplayConfiguration and if missing from resources xml
95      */
loadAmbientLightSensorConfig(DisplayConfiguration config, Resources resources)96     public static SensorData loadAmbientLightSensorConfig(DisplayConfiguration config,
97             Resources resources) {
98         SensorDetails sensorDetails = config.getLightSensor();
99         if (sensorDetails != null) {
100             return loadSensorData(sensorDetails);
101         } else {
102             return loadAmbientLightSensorConfig(resources);
103         }
104     }
105 
106     /**
107      * Loads ambient light sensor data from resources xml
108      */
loadAmbientLightSensorConfig(Resources resources)109     public static SensorData loadAmbientLightSensorConfig(Resources resources) {
110         return new SensorData(
111                 resources.getString(com.android.internal.R.string.config_displayLightSensorType),
112                 /* name= */ "");
113     }
114 
115     /**
116      * Loads screen off brightness sensor data from DisplayConfiguration
117      */
loadScreenOffBrightnessSensorConfig(DisplayConfiguration config)118     public static SensorData loadScreenOffBrightnessSensorConfig(DisplayConfiguration config) {
119         SensorDetails sensorDetails = config.getScreenOffBrightnessSensor();
120         if (sensorDetails != null) {
121             return loadSensorData(sensorDetails);
122         } else {
123             return new SensorData();
124         }
125     }
126 
127     /**
128      * Loads proximity sensor data from DisplayConfiguration
129      */
130     @Nullable
loadProxSensorConfig( DisplayManagerFlags flags, DisplayConfiguration config)131     public static SensorData loadProxSensorConfig(
132             DisplayManagerFlags flags, DisplayConfiguration config) {
133         SensorData DEFAULT_SENSOR = new SensorData();
134         List<SensorDetails> sensorDetailsList = config.getProxSensor();
135         if (sensorDetailsList.isEmpty()) {
136             return DEFAULT_SENSOR;
137         }
138 
139         SensorData selectedSensor = DEFAULT_SENSOR;
140         // Prioritize flagged sensors.
141         for (SensorDetails sensorDetails : sensorDetailsList) {
142             String flagStr = sensorDetails.getFeatureFlag();
143             if (flags.isUseFusionProxSensorEnabled() &&
144                 flags.getUseFusionProxSensorFlagName().equals(flagStr)) {
145                 selectedSensor = loadSensorData(sensorDetails);
146                 break;
147             }
148         }
149 
150         // Check for normal un-flagged sensor if a flagged one wasn't found.
151         if (DEFAULT_SENSOR == selectedSensor) {
152             for (SensorDetails sensorDetails : sensorDetailsList) {
153                 if (sensorDetails.getFeatureFlag() != null) {
154                     continue;
155                 }
156                 selectedSensor = loadSensorData(sensorDetails);
157                 break;
158             }
159         }
160 
161         // Check if we shouldn't use a sensor at all.
162         if (DEFAULT_SENSOR != selectedSensor) {
163             if ("".equals(selectedSensor.name) && "".equals(selectedSensor.type)) {
164                 // <proxSensor> with empty values to the config means no sensor should be used.
165                 // See also {@link com.android.server.display.utils.SensorUtils}
166                 selectedSensor = null;
167             }
168         }
169 
170         return selectedSensor;
171     }
172 
173     /**
174      * Loads temperature sensor data for no config case. (Type: SKIN, Name: null)
175      */
loadTempSensorUnspecifiedConfig()176     public static SensorData loadTempSensorUnspecifiedConfig() {
177         return new SensorData(TEMPERATURE_TYPE_SKIN, null);
178     }
179 
180     /**
181      * Loads temperature sensor data from given display config.
182      * If empty or null config given default to (Type: SKIN, Name: null)
183      */
loadTempSensorConfig(DisplayManagerFlags flags, DisplayConfiguration config)184     public static SensorData loadTempSensorConfig(DisplayManagerFlags flags,
185             DisplayConfiguration config) {
186         SensorDetails sensorDetails = config.getTempSensor();
187         if (!flags.isSensorBasedBrightnessThrottlingEnabled() || sensorDetails == null) {
188             return new SensorData(TEMPERATURE_TYPE_SKIN, null);
189         }
190         String name = sensorDetails.getName();
191         String type = sensorDetails.getType();
192         if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
193             type = TEMPERATURE_TYPE_SKIN;
194             name = null;
195         }
196         return new SensorData(type, name);
197     }
198 
199     /**
200      * Loads sensor unspecified config, this means system should use default sensor.
201      * See also {@link com.android.server.display.utils.SensorUtils}
202      */
203     @NonNull
loadSensorUnspecifiedConfig()204     public static SensorData loadSensorUnspecifiedConfig() {
205         return new SensorData();
206     }
207 
loadSensorData(@onNull SensorDetails sensorDetails)208     private static SensorData loadSensorData(@NonNull SensorDetails sensorDetails) {
209         float minRefreshRate = 0f;
210         float maxRefreshRate = Float.POSITIVE_INFINITY;
211         RefreshRateRange rr = sensorDetails.getRefreshRate();
212         if (rr != null) {
213             minRefreshRate = rr.getMinimum().floatValue();
214             maxRefreshRate = rr.getMaximum().floatValue();
215         }
216         List<SupportedModeData> supportedModes = SupportedModeData.load(
217                 sensorDetails.getSupportedModes());
218 
219         return new SensorData(sensorDetails.getType(), sensorDetails.getName(), minRefreshRate,
220                 maxRefreshRate, supportedModes);
221     }
222 
223 }
224