DozeSensors.java revision 79bacbbbdb4a2aa4cf6d143c2d2c30d7dd31ace5
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 17package com.android.systemui.doze; 18 19import com.android.internal.hardware.AmbientDisplayConfiguration; 20import com.android.internal.logging.MetricsLogger; 21import com.android.internal.logging.MetricsProto; 22import com.android.systemui.statusbar.phone.DozeParameters; 23 24import android.annotation.AnyThread; 25import android.app.ActivityManager; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.database.ContentObserver; 29import android.hardware.Sensor; 30import android.hardware.SensorManager; 31import android.hardware.TriggerEvent; 32import android.hardware.TriggerEventListener; 33import android.media.AudioAttributes; 34import android.net.Uri; 35import android.os.Handler; 36import android.os.PowerManager; 37import android.os.SystemClock; 38import android.os.UserHandle; 39import android.os.Vibrator; 40import android.provider.Settings; 41import android.text.TextUtils; 42import android.util.Log; 43 44import java.util.List; 45 46public class DozeSensors { 47 48 private static final boolean DEBUG = DozeService.DEBUG; 49 50 private static final String TAG = "DozeSensors"; 51 52 private final Context mContext; 53 private final SensorManager mSensorManager; 54 private final TriggerSensor[] mSensors; 55 private final ContentResolver mResolver; 56 private final TriggerSensor mPickupSensor; 57 private final DozeParameters mDozeParameters; 58 private final AmbientDisplayConfiguration mConfig; 59 private final PowerManager.WakeLock mWakeLock; 60 private final Callback mCallback; 61 62 private final Handler mHandler = new Handler(); 63 64 65 public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters, 66 AmbientDisplayConfiguration config, PowerManager.WakeLock wakeLock, Callback callback) { 67 mContext = context; 68 mSensorManager = sensorManager; 69 mDozeParameters = dozeParameters; 70 mConfig = config; 71 mWakeLock = wakeLock; 72 mResolver = mContext.getContentResolver(); 73 74 mSensors = new TriggerSensor[] { 75 new TriggerSensor( 76 mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), 77 null /* setting */, 78 dozeParameters.getPulseOnSigMotion(), 79 DozeLog.PULSE_REASON_SENSOR_SIGMOTION), 80 mPickupSensor = new TriggerSensor( 81 mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), 82 Settings.Secure.DOZE_PULSE_ON_PICK_UP, 83 config.pulseOnPickupAvailable(), 84 DozeLog.PULSE_REASON_SENSOR_PICKUP), 85 new TriggerSensor( 86 findSensorWithType(config.doubleTapSensorType()), 87 Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, 88 true /* configured */, 89 DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) 90 }; 91 mCallback = callback; 92 } 93 94 private Sensor findSensorWithType(String type) { 95 if (TextUtils.isEmpty(type)) { 96 return null; 97 } 98 List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); 99 for (Sensor s : sensorList) { 100 if (type.equals(s.getStringType())) { 101 return s; 102 } 103 } 104 return null; 105 } 106 107 public void setListen(boolean listen) { 108 for (TriggerSensor s : mSensors) { 109 s.setListening(listen); 110 if (listen) { 111 s.registerSettingsObserver(mSettingsObserver); 112 } 113 } 114 if (!listen) { 115 mResolver.unregisterContentObserver(mSettingsObserver); 116 } 117 } 118 119 public void reregisterAllSensors() { 120 for (TriggerSensor s : mSensors) { 121 s.setListening(false); 122 } 123 for (TriggerSensor s : mSensors) { 124 s.setListening(true); 125 } 126 } 127 128 public void onUserSwitched() { 129 for (TriggerSensor s : mSensors) { 130 s.updateListener(); 131 } 132 } 133 134 private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { 135 @Override 136 public void onChange(boolean selfChange, Uri uri, int userId) { 137 if (userId != ActivityManager.getCurrentUser()) { 138 return; 139 } 140 for (TriggerSensor s : mSensors) { 141 s.updateListener(); 142 } 143 } 144 }; 145 146 public void setDisableSensorsInterferingWithProximity(boolean disable) { 147 mPickupSensor.setDisabled(disable); 148 } 149 150 private class TriggerSensor extends TriggerEventListener { 151 final Sensor mSensor; 152 final boolean mConfigured; 153 final int mPulseReason; 154 final String mSetting; 155 156 private boolean mRequested; 157 private boolean mRegistered; 158 private boolean mDisabled; 159 160 public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) { 161 mSensor = sensor; 162 mSetting = setting; 163 mConfigured = configured; 164 mPulseReason = pulseReason; 165 } 166 167 public void setListening(boolean listen) { 168 if (mRequested == listen) return; 169 mRequested = listen; 170 updateListener(); 171 } 172 173 public void setDisabled(boolean disabled) { 174 if (mDisabled == disabled) return; 175 mDisabled = disabled; 176 updateListener(); 177 } 178 179 public void updateListener() { 180 if (!mConfigured || mSensor == null) return; 181 if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) { 182 mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); 183 if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered); 184 } else if (mRegistered) { 185 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); 186 if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt); 187 mRegistered = false; 188 } 189 } 190 191 private boolean enabledBySetting() { 192 if (TextUtils.isEmpty(mSetting)) { 193 return true; 194 } 195 return Settings.Secure.getIntForUser(mResolver, mSetting, 1, 196 UserHandle.USER_CURRENT) != 0; 197 } 198 199 @Override 200 public String toString() { 201 return new StringBuilder("{mRegistered=").append(mRegistered) 202 .append(", mRequested=").append(mRequested) 203 .append(", mDisabled=").append(mDisabled) 204 .append(", mConfigured=").append(mConfigured) 205 .append(", mSensor=").append(mSensor).append("}").toString(); 206 } 207 208 @Override 209 @AnyThread 210 public void onTrigger(TriggerEvent event) { 211 mHandler.post(mWakeLock.wrap(() -> { 212 if (DEBUG) 213 Log.d(TAG, "onTrigger: " + triggerEventToString(event)); 214 boolean sensorPerformsProxCheck = false; 215 if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { 216 int subType = (int) event.values[0]; 217 MetricsLogger.action( 218 mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE, 219 subType); 220 sensorPerformsProxCheck = 221 mDozeParameters.getPickupSubtypePerformsProxCheck(subType); 222 } 223 224 mRegistered = false; 225 mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck); 226 updateListener(); // reregister, this sensor only fires once 227 })); 228 } 229 230 public void registerSettingsObserver(ContentObserver settingsObserver) { 231 if (mConfigured && !TextUtils.isEmpty(mSetting)) { 232 mResolver.registerContentObserver( 233 Settings.Secure.getUriFor(mSetting), false /* descendants */, 234 mSettingsObserver, UserHandle.USER_ALL); 235 } 236 } 237 238 private String triggerEventToString(TriggerEvent event) { 239 if (event == null) return null; 240 final StringBuilder sb = new StringBuilder("TriggerEvent[") 241 .append(event.timestamp).append(',') 242 .append(event.sensor.getName()); 243 if (event.values != null) { 244 for (int i = 0; i < event.values.length; i++) { 245 sb.append(',').append(event.values[i]); 246 } 247 } 248 return sb.append(']').toString(); 249 } 250 } 251 252 public interface Callback { 253 void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck); 254 } 255} 256