1 /* 2 * Copyright (C) 2020 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.util.sensors; 18 19 import android.content.res.Resources; 20 import android.hardware.Sensor; 21 import android.hardware.SensorManager; 22 import android.text.TextUtils; 23 import android.util.Log; 24 25 import androidx.annotation.NonNull; 26 27 import com.android.systemui.dagger.qualifiers.Main; 28 import com.android.systemui.res.R; 29 import com.android.systemui.statusbar.policy.DevicePostureController; 30 import com.android.systemui.util.concurrency.DelayableExecutor; 31 32 import dagger.Lazy; 33 import dagger.Module; 34 import dagger.Provides; 35 36 import java.util.Arrays; 37 import java.util.HashMap; 38 import java.util.Map; 39 40 /** 41 * Dagger module for Sensor related classes. 42 */ 43 @Module 44 public class SensorModule { 45 @Provides 46 @PrimaryProxSensor providePrimaryProximitySensor( SensorManager sensorManager, ThresholdSensorImpl.Builder thresholdSensorBuilder )47 static ThresholdSensor providePrimaryProximitySensor( 48 SensorManager sensorManager, 49 ThresholdSensorImpl.Builder thresholdSensorBuilder 50 ) { 51 try { 52 return thresholdSensorBuilder 53 .setSensorDelay(SensorManager.SENSOR_DELAY_NORMAL) 54 .setSensorResourceId(R.string.proximity_sensor_type, true) 55 .setThresholdResourceId(R.dimen.proximity_sensor_threshold) 56 .setThresholdLatchResourceId(R.dimen.proximity_sensor_threshold_latch) 57 .build(); 58 } catch (IllegalStateException e) { 59 Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY, 60 true); 61 return thresholdSensorBuilder 62 .setSensor(defaultSensor) 63 .setThresholdValue(defaultSensor != null ? defaultSensor.getMaximumRange() : 0) 64 .build(); 65 } 66 } 67 68 @Provides 69 @SecondaryProxSensor provideSecondaryProximitySensor( ThresholdSensorImpl.Builder thresholdSensorBuilder )70 static ThresholdSensor provideSecondaryProximitySensor( 71 ThresholdSensorImpl.Builder thresholdSensorBuilder 72 ) { 73 try { 74 return thresholdSensorBuilder 75 .setSensorResourceId(R.string.proximity_sensor_secondary_type, true) 76 .setThresholdResourceId(R.dimen.proximity_sensor_secondary_threshold) 77 .setThresholdLatchResourceId(R.dimen.proximity_sensor_secondary_threshold_latch) 78 .build(); 79 } catch (IllegalStateException e) { 80 return thresholdSensorBuilder.setSensor(null).setThresholdValue(0).build(); 81 } 82 } 83 84 /** 85 * If postures are supported on the device, returns a posture dependent proximity sensor 86 * which switches proximity sensors based on the current posture. 87 * 88 * If postures are not supported the regular {@link ProximitySensorImpl} will be returned. 89 */ 90 @Provides provideProximitySensor( @ain Resources resources, Lazy<PostureDependentProximitySensor> postureDependentProximitySensorProvider, Lazy<ProximitySensorImpl> proximitySensorProvider )91 static ProximitySensor provideProximitySensor( 92 @Main Resources resources, 93 Lazy<PostureDependentProximitySensor> postureDependentProximitySensorProvider, 94 Lazy<ProximitySensorImpl> proximitySensorProvider 95 ) { 96 if (hasPostureSupport( 97 resources.getStringArray(R.array.proximity_sensor_posture_mapping))) { 98 return postureDependentProximitySensorProvider.get(); 99 } else { 100 return proximitySensorProvider.get(); 101 } 102 } 103 104 @Provides provideProximityCheck( ProximitySensor proximitySensor, @Main DelayableExecutor delayableExecutor )105 static ProximityCheck provideProximityCheck( 106 ProximitySensor proximitySensor, 107 @Main DelayableExecutor delayableExecutor 108 ) { 109 return new ProximityCheck( 110 proximitySensor, 111 delayableExecutor 112 ); 113 } 114 115 @Provides 116 @PrimaryProxSensor 117 @NonNull providePostureToProximitySensorMapping( ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, @Main Resources resources )118 static ThresholdSensor[] providePostureToProximitySensorMapping( 119 ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, 120 @Main Resources resources 121 ) { 122 return createPostureToSensorMapping( 123 thresholdSensorImplBuilderFactory, 124 resources.getStringArray(R.array.proximity_sensor_posture_mapping), 125 R.dimen.proximity_sensor_threshold, 126 R.dimen.proximity_sensor_threshold_latch 127 ); 128 } 129 130 @Provides 131 @SecondaryProxSensor 132 @NonNull providePostureToSecondaryProximitySensorMapping( ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, @Main Resources resources )133 static ThresholdSensor[] providePostureToSecondaryProximitySensorMapping( 134 ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, 135 @Main Resources resources 136 ) { 137 return createPostureToSensorMapping( 138 thresholdSensorImplBuilderFactory, 139 resources.getStringArray(R.array.proximity_sensor_secondary_posture_mapping), 140 R.dimen.proximity_sensor_secondary_threshold, 141 R.dimen.proximity_sensor_secondary_threshold_latch 142 ); 143 } 144 145 /** 146 * Builds sensors to use per posture. 147 * 148 * @param sensorTypes an array where the index represents 149 * {@link DevicePostureController.DevicePostureInt} and the value 150 * at the given index is the sensorType. Empty values represent 151 * no sensor desired. 152 * @param proximitySensorThresholdResourceId resource id for the threshold for all sensor 153 * postures. This currently only supports one value. 154 * This needs to be updated in the future if postures 155 * use different sensors with differing thresholds. 156 * @param proximitySensorThresholdLatchResourceId resource id for the latch for all sensor 157 * postures. This currently only supports one 158 * value. This needs to be updated in the future 159 * if postures use different sensors with 160 * differing latches. 161 * @return an array where the index represents the device posture 162 * {@link DevicePostureController.DevicePostureInt} and the value at the index is the sensor to 163 * use when the device is in that posture. 164 */ 165 @NonNull createPostureToSensorMapping( ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, String[] sensorTypes, int proximitySensorThresholdResourceId, int proximitySensorThresholdLatchResourceId )166 private static ThresholdSensor[] createPostureToSensorMapping( 167 ThresholdSensorImpl.BuilderFactory thresholdSensorImplBuilderFactory, 168 String[] sensorTypes, 169 int proximitySensorThresholdResourceId, 170 int proximitySensorThresholdLatchResourceId 171 172 ) { 173 ThresholdSensor noProxSensor = thresholdSensorImplBuilderFactory 174 .createBuilder() 175 .setSensor(null).setThresholdValue(0).build(); 176 177 178 // length and index of sensorMap correspond to DevicePostureController.DevicePostureInt: 179 final ThresholdSensor[] sensorMap = 180 new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; 181 Arrays.fill(sensorMap, noProxSensor); 182 183 if (!hasPostureSupport(sensorTypes)) { 184 Log.e("SensorModule", "config doesn't support postures," 185 + " but attempting to retrieve proxSensorMapping"); 186 return sensorMap; 187 } 188 189 // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between 190 // postures 191 Map<String, ThresholdSensor> typeToSensorMap = new HashMap<>(); 192 for (int i = 0; i < sensorTypes.length; i++) { 193 try { 194 final String sensorType = sensorTypes[i]; 195 if (typeToSensorMap.containsKey(sensorType)) { 196 sensorMap[i] = typeToSensorMap.get(sensorType); 197 } else { 198 sensorMap[i] = thresholdSensorImplBuilderFactory 199 .createBuilder() 200 .setSensorType(sensorTypes[i], true) 201 .setThresholdResourceId(proximitySensorThresholdResourceId) 202 .setThresholdLatchResourceId(proximitySensorThresholdLatchResourceId) 203 .build(); 204 typeToSensorMap.put(sensorType, sensorMap[i]); 205 } 206 } catch (IllegalStateException e) { 207 // do nothing, sensor at this posture is already set to noProxSensor 208 } 209 } 210 211 return sensorMap; 212 } 213 214 /** 215 * Returns true if there's at least one non-empty sensor type in the given array. 216 */ hasPostureSupport(String[] postureToSensorTypeMapping)217 private static boolean hasPostureSupport(String[] postureToSensorTypeMapping) { 218 if (postureToSensorTypeMapping == null || postureToSensorTypeMapping.length == 0) { 219 return false; 220 } 221 222 for (String sensorType : postureToSensorTypeMapping) { 223 if (!TextUtils.isEmpty(sensorType)) { 224 return true; 225 } 226 } 227 228 return false; 229 } 230 } 231