blob: ff5f08ef2c96d158219bb61631be70910c4d60ad [file] [log] [blame]
John Spurlockbf370992014-06-17 13:58:31 -04001/*
2 * Copyright (C) 2014 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
Adrian Roos7294c112016-09-20 14:03:21 -070019import android.app.ActivityManager;
John Spurlock870f1532014-09-25 20:34:31 -040020import android.app.UiModeManager;
John Spurlockbf370992014-06-17 13:58:31 -040021import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
John Spurlock870f1532014-09-25 20:34:31 -040025import android.content.res.Configuration;
Adrian Roos7294c112016-09-20 14:03:21 -070026import android.database.ContentObserver;
John Spurlockbf370992014-06-17 13:58:31 -040027import android.hardware.Sensor;
John Spurlock92b8d412014-10-03 17:12:40 -040028import android.hardware.SensorEvent;
29import android.hardware.SensorEventListener;
John Spurlockbf370992014-06-17 13:58:31 -040030import android.hardware.SensorManager;
31import android.hardware.TriggerEvent;
32import android.hardware.TriggerEventListener;
John Spurlock559d9592014-08-09 12:04:36 -040033import android.media.AudioAttributes;
Adrian Roos7294c112016-09-20 14:03:21 -070034import android.net.Uri;
John Spurlock92b8d412014-10-03 17:12:40 -040035import android.os.Handler;
John Spurlockbf370992014-06-17 13:58:31 -040036import android.os.PowerManager;
John Spurlock92b8d412014-10-03 17:12:40 -040037import android.os.SystemClock;
Adrian Roos7294c112016-09-20 14:03:21 -070038import android.os.UserHandle;
John Spurlockbf370992014-06-17 13:58:31 -040039import android.os.Vibrator;
Adrian Roos7294c112016-09-20 14:03:21 -070040import android.provider.Settings;
John Spurlockbf370992014-06-17 13:58:31 -040041import android.service.dreams.DreamService;
Adrian Roos7294c112016-09-20 14:03:21 -070042import android.text.TextUtils;
John Spurlockbf370992014-06-17 13:58:31 -040043import android.util.Log;
John Spurlocked69bd62014-07-23 11:09:02 -040044import android.view.Display;
John Spurlockbf370992014-06-17 13:58:31 -040045
Adrian Roosb7e4e102016-10-14 13:03:45 -070046import com.android.internal.hardware.AmbientDisplayConfiguration;
Bhavik Singh3451da42016-06-01 18:25:59 -070047import com.android.internal.logging.MetricsLogger;
Tamas Berghammercbd3f0c2016-06-22 15:21:38 +010048import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
John Spurlockbf370992014-06-17 13:58:31 -040049import com.android.systemui.SystemUIApplication;
John Spurlockd06aa572014-09-10 10:40:49 -040050import com.android.systemui.statusbar.phone.DozeParameters;
John Spurlockbf370992014-06-17 13:58:31 -040051
John Spurlock66127272014-06-28 11:27:17 -040052import java.io.FileDescriptor;
53import java.io.PrintWriter;
John Spurlockcb566aa2014-08-03 22:58:28 -040054import java.util.Date;
Adrian Roos7294c112016-09-20 14:03:21 -070055import java.util.List;
John Spurlock66127272014-06-28 11:27:17 -040056
John Spurlockbf370992014-06-17 13:58:31 -040057public class DozeService extends DreamService {
John Spurlocked69bd62014-07-23 11:09:02 -040058 private static final String TAG = "DozeService";
59 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlockbf370992014-06-17 13:58:31 -040060
John Spurlockcb566aa2014-08-03 22:58:28 -040061 private static final String ACTION_BASE = "com.android.systemui.doze";
62 private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
Christoph Studer1f32c652014-11-26 15:32:20 +010063
Adrian Roos0288dcc2016-10-04 16:35:10 -040064 /**
65 * If true, reregisters all trigger sensors when the screen turns off.
66 */
67 private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
68
John Spurlocked69bd62014-07-23 11:09:02 -040069 private final String mTag = String.format(TAG + ".%08x", hashCode());
John Spurlockbf370992014-06-17 13:58:31 -040070 private final Context mContext = this;
John Spurlockd06aa572014-09-10 10:40:49 -040071 private final DozeParameters mDozeParameters = new DozeParameters(mContext);
John Spurlock92b8d412014-10-03 17:12:40 -040072 private final Handler mHandler = new Handler();
John Spurlockbf370992014-06-17 13:58:31 -040073
Jeff Brown4d69e222014-09-18 15:27:50 -070074 private DozeHost mHost;
Adrian Roos7294c112016-09-20 14:03:21 -070075 private SensorManager mSensorManager;
76 private TriggerSensor[] mSensors;
John Spurlock559d9592014-08-09 12:04:36 -040077 private TriggerSensor mPickupSensor;
John Spurlockbf370992014-06-17 13:58:31 -040078 private PowerManager mPowerManager;
79 private PowerManager.WakeLock mWakeLock;
John Spurlock870f1532014-09-25 20:34:31 -040080 private UiModeManager mUiModeManager;
John Spurlockbf370992014-06-17 13:58:31 -040081 private boolean mDreaming;
Jeff Brown4d69e222014-09-18 15:27:50 -070082 private boolean mPulsing;
John Spurlockcb566aa2014-08-03 22:58:28 -040083 private boolean mBroadcastReceiverRegistered;
John Spurlocked69bd62014-07-23 11:09:02 -040084 private boolean mDisplayStateSupported;
John Spurlockd96179e2014-08-21 16:43:45 -040085 private boolean mPowerSaveActive;
John Spurlock870f1532014-09-25 20:34:31 -040086 private boolean mCarMode;
John Spurlockd06aa572014-09-10 10:40:49 -040087 private long mNotificationPulseTime;
John Spurlockbf370992014-06-17 13:58:31 -040088
Adrian Roosb7e4e102016-10-14 13:03:45 -070089 private AmbientDisplayConfiguration mConfig;
90
John Spurlockbf370992014-06-17 13:58:31 -040091 public DozeService() {
92 if (DEBUG) Log.d(mTag, "new DozeService()");
93 setDebug(DEBUG);
94 }
95
96 @Override
John Spurlock66127272014-06-28 11:27:17 -040097 protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
98 super.dumpOnHandler(fd, pw, args);
99 pw.print(" mDreaming: "); pw.println(mDreaming);
Jeff Brown4d69e222014-09-18 15:27:50 -0700100 pw.print(" mPulsing: "); pw.println(mPulsing);
101 pw.print(" mWakeLock: held="); pw.println(mWakeLock.isHeld());
John Spurlockc6eed842014-08-25 12:19:41 -0400102 pw.print(" mHost: "); pw.println(mHost);
John Spurlockcb566aa2014-08-03 22:58:28 -0400103 pw.print(" mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
Adrian Roos7294c112016-09-20 14:03:21 -0700104 for (TriggerSensor s : mSensors) {
105 pw.print(" sensor: ");
106 pw.println(s);
107 }
John Spurlocked69bd62014-07-23 11:09:02 -0400108 pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
John Spurlockd96179e2014-08-21 16:43:45 -0400109 pw.print(" mPowerSaveActive: "); pw.println(mPowerSaveActive);
John Spurlock870f1532014-09-25 20:34:31 -0400110 pw.print(" mCarMode: "); pw.println(mCarMode);
Adrian Roosd13602f2016-08-22 15:31:38 +0200111 pw.print(" mNotificationPulseTime: "); pw.println(
112 DozeLog.FORMAT.format(new Date(mNotificationPulseTime
113 - SystemClock.elapsedRealtime() + System.currentTimeMillis())));
John Spurlockd06aa572014-09-10 10:40:49 -0400114 mDozeParameters.dump(pw);
John Spurlock66127272014-06-28 11:27:17 -0400115 }
116
117 @Override
John Spurlockbf370992014-06-17 13:58:31 -0400118 public void onCreate() {
119 if (DEBUG) Log.d(mTag, "onCreate");
120 super.onCreate();
121
122 if (getApplication() instanceof SystemUIApplication) {
123 final SystemUIApplication app = (SystemUIApplication) getApplication();
Jeff Brown4d69e222014-09-18 15:27:50 -0700124 mHost = app.getComponent(DozeHost.class);
John Spurlockbf370992014-06-17 13:58:31 -0400125 }
John Spurlockc6eed842014-08-25 12:19:41 -0400126 if (mHost == null) Log.w(TAG, "No doze service host found.");
John Spurlockbf370992014-06-17 13:58:31 -0400127
128 setWindowless(true);
129
Adrian Roos7294c112016-09-20 14:03:21 -0700130 mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
Adrian Roosb7e4e102016-10-14 13:03:45 -0700131 mConfig = new AmbientDisplayConfiguration(mContext);
Adrian Roos7294c112016-09-20 14:03:21 -0700132 mSensors = new TriggerSensor[] {
133 new TriggerSensor(
134 mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
135 null /* setting */,
136 mDozeParameters.getPulseOnSigMotion(),
137 mDozeParameters.getVibrateOnSigMotion(),
138 DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
139 mPickupSensor = new TriggerSensor(
140 mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
141 Settings.Secure.DOZE_PULSE_ON_PICK_UP,
Adrian Roosb7e4e102016-10-14 13:03:45 -0700142 mConfig.pulseOnPickupAvailable(), mDozeParameters.getVibrateOnPickup(),
Adrian Roos7294c112016-09-20 14:03:21 -0700143 DozeLog.PULSE_REASON_SENSOR_PICKUP),
144 new TriggerSensor(
Adrian Roosb7e4e102016-10-14 13:03:45 -0700145 findSensorWithType(mConfig.doubleTapSensorType()),
146 Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true,
147 mDozeParameters.getVibrateOnPickup(),
Adrian Roos7294c112016-09-20 14:03:21 -0700148 DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
149 };
John Spurlockbf370992014-06-17 13:58:31 -0400150 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn3f8bd3f2015-07-10 17:05:52 -0700151 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
Jeff Brown4d69e222014-09-18 15:27:50 -0700152 mWakeLock.setReferenceCounted(true);
John Spurlock190d0262014-09-14 15:39:13 -0400153 mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
John Spurlock870f1532014-09-25 20:34:31 -0400154 mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
Jeff Brown4d69e222014-09-18 15:27:50 -0700155 turnDisplayOff();
John Spurlockbf370992014-06-17 13:58:31 -0400156 }
157
158 @Override
159 public void onAttachedToWindow() {
160 if (DEBUG) Log.d(mTag, "onAttachedToWindow");
161 super.onAttachedToWindow();
162 }
163
164 @Override
165 public void onDreamingStarted() {
166 super.onDreamingStarted();
Jeff Brown4d69e222014-09-18 15:27:50 -0700167
168 if (mHost == null) {
169 finish();
170 return;
171 }
172
173 mPowerSaveActive = mHost.isPowerSaveActive();
John Spurlock870f1532014-09-25 20:34:31 -0400174 mCarMode = mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR;
John Spurlockd96179e2014-08-21 16:43:45 -0400175 if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " mPowerSaveActive="
John Spurlock870f1532014-09-25 20:34:31 -0400176 + mPowerSaveActive + " mCarMode=" + mCarMode);
John Spurlockd96179e2014-08-21 16:43:45 -0400177 if (mPowerSaveActive) {
178 finishToSavePower();
179 return;
180 }
John Spurlock870f1532014-09-25 20:34:31 -0400181 if (mCarMode) {
182 finishForCarMode();
183 return;
184 }
Jeff Brown4d69e222014-09-18 15:27:50 -0700185
John Spurlockbf370992014-06-17 13:58:31 -0400186 mDreaming = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100187 listenForPulseSignals(true);
John Spurlockbf370992014-06-17 13:58:31 -0400188
Jeff Brown4d69e222014-09-18 15:27:50 -0700189 // Ask the host to get things ready to start dozing.
190 // Once ready, we call startDozing() at which point the CPU may suspend
191 // and we will need to acquire a wakelock to do work.
Adrian Roos9ede1d22016-09-23 14:08:09 -0700192 mHost.startDozing(mWakeLock.wrap(() -> {
193 if (mDreaming) {
194 startDozing();
John Spurlockbf370992014-06-17 13:58:31 -0400195
Adrian Roos9ede1d22016-09-23 14:08:09 -0700196 // From this point until onDreamingStopped we will need to hold a
197 // wakelock whenever we are doing work. Note that we never call
198 // stopDozing because can we just keep dozing until the bitter end.
Jeff Brown4d69e222014-09-18 15:27:50 -0700199 }
Adrian Roos9ede1d22016-09-23 14:08:09 -0700200 }));
John Spurlocked69bd62014-07-23 11:09:02 -0400201 }
202
John Spurlockbf370992014-06-17 13:58:31 -0400203 @Override
204 public void onDreamingStopped() {
205 if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
206 super.onDreamingStopped();
207
Jeff Brown4d69e222014-09-18 15:27:50 -0700208 if (mHost == null) {
209 return;
210 }
211
John Spurlockbf370992014-06-17 13:58:31 -0400212 mDreaming = false;
John Spurlockcb566aa2014-08-03 22:58:28 -0400213 listenForPulseSignals(false);
John Spurlockbf370992014-06-17 13:58:31 -0400214
Jeff Brown4d69e222014-09-18 15:27:50 -0700215 // Tell the host that it's over.
216 mHost.stopDozing();
John Spurlockbf370992014-06-17 13:58:31 -0400217 }
218
John Spurlockeab28e62014-11-29 11:33:49 -0500219 private void requestPulse(final int reason) {
Adrian Roos5753f052016-07-13 10:30:37 -0700220 requestPulse(reason, false /* performedProxCheck */);
221 }
222
223 private void requestPulse(final int reason, boolean performedProxCheck) {
Jeff Brown4d69e222014-09-18 15:27:50 -0700224 if (mHost != null && mDreaming && !mPulsing) {
225 // Let the host know we want to pulse. Wait for it to be ready, then
226 // turn the screen on. When finished, turn the screen off again.
227 // Here we need a wakelock to stay awake until the pulse is finished.
228 mWakeLock.acquire();
229 mPulsing = true;
John Spurlock621afac82014-12-03 16:00:44 -0500230 if (!mDozeParameters.getProxCheckBeforePulse()) {
John Spurlock686e4d52014-11-20 21:48:09 -0500231 // skip proximity check
John Spurlockeab28e62014-11-29 11:33:49 -0500232 continuePulsing(reason);
John Spurlock686e4d52014-11-20 21:48:09 -0500233 return;
234 }
John Spurlock92b8d412014-10-03 17:12:40 -0400235 final long start = SystemClock.uptimeMillis();
Adrian Roos5753f052016-07-13 10:30:37 -0700236 if (performedProxCheck) {
237 // the caller already performed a successful proximity check; we'll only do one to
238 // capture statistics, continue pulsing immediately.
John Spurlock621afac82014-12-03 16:00:44 -0500239 continuePulsing(reason);
240 }
241 // perform a proximity check
John Spurlock92b8d412014-10-03 17:12:40 -0400242 new ProximityCheck() {
Jeff Brown4d69e222014-09-18 15:27:50 -0700243 @Override
John Spurlock92b8d412014-10-03 17:12:40 -0400244 public void onProximityResult(int result) {
John Spurlock92b8d412014-10-03 17:12:40 -0400245 final boolean isNear = result == RESULT_NEAR;
John Spurlockeab28e62014-11-29 11:33:49 -0500246 final long end = SystemClock.uptimeMillis();
Jorim Jaggi83969702015-06-05 14:59:24 -0700247 DozeLog.traceProximityResult(mContext, isNear, end - start, reason);
Adrian Roos5753f052016-07-13 10:30:37 -0700248 if (performedProxCheck) {
John Spurlock621afac82014-12-03 16:00:44 -0500249 // we already continued
250 return;
251 }
252 // avoid pulsing in pockets
John Spurlock92b8d412014-10-03 17:12:40 -0400253 if (isNear) {
Jeff Brown4d69e222014-09-18 15:27:50 -0700254 mPulsing = false;
John Spurlock92b8d412014-10-03 17:12:40 -0400255 mWakeLock.release();
256 return;
Jeff Brown4d69e222014-09-18 15:27:50 -0700257 }
John Spurlock92b8d412014-10-03 17:12:40 -0400258
259 // not in-pocket, continue pulsing
John Spurlockeab28e62014-11-29 11:33:49 -0500260 continuePulsing(reason);
Jeff Brown4d69e222014-09-18 15:27:50 -0700261 }
John Spurlock92b8d412014-10-03 17:12:40 -0400262 }.check();
John Spurlockbf370992014-06-17 13:58:31 -0400263 }
264 }
265
John Spurlockeab28e62014-11-29 11:33:49 -0500266 private void continuePulsing(int reason) {
Jorim Jaggi007f0e82015-08-14 13:56:01 -0700267 if (mHost.isPulsingBlocked()) {
Jorim Jaggi5fb4b982015-08-19 13:01:19 -0700268 mPulsing = false;
269 mWakeLock.release();
Jorim Jaggi007f0e82015-08-14 13:56:01 -0700270 return;
271 }
John Spurlock686e4d52014-11-20 21:48:09 -0500272 mHost.pulseWhileDozing(new DozeHost.PulseCallback() {
273 @Override
274 public void onPulseStarted() {
275 if (mPulsing && mDreaming) {
276 turnDisplayOn();
277 }
278 }
279
280 @Override
281 public void onPulseFinished() {
282 if (mPulsing && mDreaming) {
283 mPulsing = false;
Adrian Roos0288dcc2016-10-04 16:35:10 -0400284 if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
285 reregisterAllSensors();
286 }
John Spurlock686e4d52014-11-20 21:48:09 -0500287 turnDisplayOff();
288 }
289 mWakeLock.release(); // needs to be unconditional to balance acquire
290 }
John Spurlockeab28e62014-11-29 11:33:49 -0500291 }, reason);
John Spurlock686e4d52014-11-20 21:48:09 -0500292 }
293
Jeff Brown4d69e222014-09-18 15:27:50 -0700294 private void turnDisplayOff() {
John Spurlock92b8d412014-10-03 17:12:40 -0400295 if (DEBUG) Log.d(mTag, "Display off");
Jeff Brown4d69e222014-09-18 15:27:50 -0700296 setDozeScreenState(Display.STATE_OFF);
297 }
298
299 private void turnDisplayOn() {
John Spurlock92b8d412014-10-03 17:12:40 -0400300 if (DEBUG) Log.d(mTag, "Display on");
Jeff Brown4d69e222014-09-18 15:27:50 -0700301 setDozeScreenState(mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON);
John Spurlockbf370992014-06-17 13:58:31 -0400302 }
303
John Spurlockd96179e2014-08-21 16:43:45 -0400304 private void finishToSavePower() {
305 Log.w(mTag, "Exiting ambient mode due to low power battery saver");
306 finish();
307 }
308
John Spurlock870f1532014-09-25 20:34:31 -0400309 private void finishForCarMode() {
310 Log.w(mTag, "Exiting ambient mode, not allowed in car mode");
311 finish();
312 }
313
John Spurlockcb566aa2014-08-03 22:58:28 -0400314 private void listenForPulseSignals(boolean listen) {
315 if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
Adrian Roos7294c112016-09-20 14:03:21 -0700316 for (TriggerSensor s : mSensors) {
317 s.setListening(listen);
318 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400319 listenForBroadcasts(listen);
John Spurlock66127272014-06-28 11:27:17 -0400320 listenForNotifications(listen);
321 }
322
Adrian Roos0288dcc2016-10-04 16:35:10 -0400323 private void reregisterAllSensors() {
324 for (TriggerSensor s : mSensors) {
325 s.setListening(false);
326 }
327 for (TriggerSensor s : mSensors) {
328 s.setListening(true);
329 }
330 }
331
John Spurlockcb566aa2014-08-03 22:58:28 -0400332 private void listenForBroadcasts(boolean listen) {
John Spurlockbf370992014-06-17 13:58:31 -0400333 if (listen) {
John Spurlockcb566aa2014-08-03 22:58:28 -0400334 final IntentFilter filter = new IntentFilter(PULSE_ACTION);
John Spurlock870f1532014-09-25 20:34:31 -0400335 filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
Adrian Roos7294c112016-09-20 14:03:21 -0700336 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlockcb566aa2014-08-03 22:58:28 -0400337 mContext.registerReceiver(mBroadcastReceiver, filter);
Adrian Roos7294c112016-09-20 14:03:21 -0700338
339 for (TriggerSensor s : mSensors) {
340 if (s.mConfigured && !TextUtils.isEmpty(s.mSetting)) {
341 mContext.getContentResolver().registerContentObserver(
342 Settings.Secure.getUriFor(s.mSetting), false /* descendants */,
343 mSettingsObserver, UserHandle.USER_ALL);
344 }
345 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400346 mBroadcastReceiverRegistered = true;
John Spurlockbf370992014-06-17 13:58:31 -0400347 } else {
John Spurlockcb566aa2014-08-03 22:58:28 -0400348 if (mBroadcastReceiverRegistered) {
349 mContext.unregisterReceiver(mBroadcastReceiver);
Adrian Roos7294c112016-09-20 14:03:21 -0700350 mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
John Spurlockbf370992014-06-17 13:58:31 -0400351 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400352 mBroadcastReceiverRegistered = false;
John Spurlockbf370992014-06-17 13:58:31 -0400353 }
354 }
355
John Spurlock66127272014-06-28 11:27:17 -0400356 private void listenForNotifications(boolean listen) {
John Spurlockbf370992014-06-17 13:58:31 -0400357 if (listen) {
John Spurlock66127272014-06-28 11:27:17 -0400358 mHost.addCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400359 } else {
John Spurlock66127272014-06-28 11:27:17 -0400360 mHost.removeCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400361 }
362 }
363
Adrian Roosd13602f2016-08-22 15:31:38 +0200364 private void requestNotificationPulse() {
365 if (DEBUG) Log.d(mTag, "requestNotificationPulse");
Adrian Roosb7e4e102016-10-14 13:03:45 -0700366 if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
Adrian Roosd13602f2016-08-22 15:31:38 +0200367 mNotificationPulseTime = SystemClock.elapsedRealtime();
368 requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
John Spurlockcb566aa2014-08-03 22:58:28 -0400369 }
370
John Spurlockbf370992014-06-17 13:58:31 -0400371 private static String triggerEventToString(TriggerEvent event) {
372 if (event == null) return null;
373 final StringBuilder sb = new StringBuilder("TriggerEvent[")
374 .append(event.timestamp).append(',')
375 .append(event.sensor.getName());
376 if (event.values != null) {
377 for (int i = 0; i < event.values.length; i++) {
378 sb.append(',').append(event.values[i]);
379 }
380 }
381 return sb.append(']').toString();
382 }
383
John Spurlockcb566aa2014-08-03 22:58:28 -0400384 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
John Spurlockbf370992014-06-17 13:58:31 -0400385 @Override
386 public void onReceive(Context context, Intent intent) {
John Spurlockcb566aa2014-08-03 22:58:28 -0400387 if (PULSE_ACTION.equals(intent.getAction())) {
388 if (DEBUG) Log.d(mTag, "Received pulse intent");
John Spurlockeab28e62014-11-29 11:33:49 -0500389 requestPulse(DozeLog.PULSE_REASON_INTENT);
John Spurlockcb566aa2014-08-03 22:58:28 -0400390 }
John Spurlock870f1532014-09-25 20:34:31 -0400391 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
392 mCarMode = true;
393 if (mCarMode && mDreaming) {
394 finishForCarMode();
395 }
396 }
Adrian Roos7294c112016-09-20 14:03:21 -0700397 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
398 for (TriggerSensor s : mSensors) {
399 s.updateListener();
400 }
401 }
402 }
403 };
404
405 private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
406 @Override
407 public void onChange(boolean selfChange, Uri uri, int userId) {
408 if (userId != ActivityManager.getCurrentUser()) {
409 return;
410 }
411 for (TriggerSensor s : mSensors) {
412 s.updateListener();
413 }
John Spurlockbf370992014-06-17 13:58:31 -0400414 }
415 };
416
Jeff Brown4d69e222014-09-18 15:27:50 -0700417 private final DozeHost.Callback mHostCallback = new DozeHost.Callback() {
John Spurlockbf370992014-06-17 13:58:31 -0400418 @Override
419 public void onNewNotifications() {
Christoph Studer1f32c652014-11-26 15:32:20 +0100420 if (DEBUG) Log.d(mTag, "onNewNotifications (noop)");
John Spurlockcad57682014-07-26 17:09:56 -0400421 // noop for now
422 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400423
John Spurlockcad57682014-07-26 17:09:56 -0400424 @Override
425 public void onBuzzBeepBlinked() {
426 if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
Adrian Roosd13602f2016-08-22 15:31:38 +0200427 requestNotificationPulse();
John Spurlockcb566aa2014-08-03 22:58:28 -0400428 }
429
430 @Override
431 public void onNotificationLight(boolean on) {
Adrian Roosd13602f2016-08-22 15:31:38 +0200432 if (DEBUG) Log.d(mTag, "onNotificationLight (noop) on=" + on);
433 // noop for now
John Spurlockbf370992014-06-17 13:58:31 -0400434 }
John Spurlockd96179e2014-08-21 16:43:45 -0400435
436 @Override
437 public void onPowerSaveChanged(boolean active) {
438 mPowerSaveActive = active;
439 if (mPowerSaveActive && mDreaming) {
440 finishToSavePower();
441 }
442 }
John Spurlockbf370992014-06-17 13:58:31 -0400443 };
444
Adrian Roos7294c112016-09-20 14:03:21 -0700445 private Sensor findSensorWithType(String type) {
446 if (TextUtils.isEmpty(type)) {
447 return null;
448 }
449 List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
450 for (Sensor s : sensorList) {
451 if (type.equals(s.getStringType())) {
452 return s;
453 }
454 }
455 return null;
456 }
457
John Spurlock559d9592014-08-09 12:04:36 -0400458 private class TriggerSensor extends TriggerEventListener {
Adrian Roos7294c112016-09-20 14:03:21 -0700459 final Sensor mSensor;
460 final boolean mConfigured;
461 final boolean mDebugVibrate;
462 final int mPulseReason;
463 final String mSetting;
John Spurlock559d9592014-08-09 12:04:36 -0400464
John Spurlock92b8d412014-10-03 17:12:40 -0400465 private boolean mRequested;
466 private boolean mRegistered;
467 private boolean mDisabled;
John Spurlock559d9592014-08-09 12:04:36 -0400468
Adrian Roos7294c112016-09-20 14:03:21 -0700469 public TriggerSensor(Sensor sensor, String setting, boolean configured,
470 boolean debugVibrate, int pulseReason) {
471 mSensor = sensor;
472 mSetting = setting;
John Spurlock190d0262014-09-14 15:39:13 -0400473 mConfigured = configured;
474 mDebugVibrate = debugVibrate;
John Spurlockeab28e62014-11-29 11:33:49 -0500475 mPulseReason = pulseReason;
John Spurlock559d9592014-08-09 12:04:36 -0400476 }
477
478 public void setListening(boolean listen) {
John Spurlock92b8d412014-10-03 17:12:40 -0400479 if (mRequested == listen) return;
480 mRequested = listen;
481 updateListener();
482 }
483
484 public void setDisabled(boolean disabled) {
485 if (mDisabled == disabled) return;
486 mDisabled = disabled;
487 updateListener();
488 }
489
Adrian Roos7294c112016-09-20 14:03:21 -0700490 public void updateListener() {
John Spurlock559d9592014-08-09 12:04:36 -0400491 if (!mConfigured || mSensor == null) return;
Adrian Roos7294c112016-09-20 14:03:21 -0700492 if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
493 mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
John Spurlock78503732014-11-10 09:41:41 -0500494 if (DEBUG) Log.d(mTag, "requestTriggerSensor " + mRegistered);
John Spurlock92b8d412014-10-03 17:12:40 -0400495 } else if (mRegistered) {
Adrian Roos7294c112016-09-20 14:03:21 -0700496 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
John Spurlock78503732014-11-10 09:41:41 -0500497 if (DEBUG) Log.d(mTag, "cancelTriggerSensor " + rt);
John Spurlock92b8d412014-10-03 17:12:40 -0400498 mRegistered = false;
John Spurlock559d9592014-08-09 12:04:36 -0400499 }
500 }
501
Adrian Roos7294c112016-09-20 14:03:21 -0700502 private boolean enabledBySetting() {
503 if (TextUtils.isEmpty(mSetting)) {
504 return true;
505 }
506 return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSetting, 1,
507 UserHandle.USER_CURRENT) != 0;
508 }
509
John Spurlock559d9592014-08-09 12:04:36 -0400510 @Override
511 public String toString() {
John Spurlock92b8d412014-10-03 17:12:40 -0400512 return new StringBuilder("{mRegistered=").append(mRegistered)
513 .append(", mRequested=").append(mRequested)
514 .append(", mDisabled=").append(mDisabled)
515 .append(", mConfigured=").append(mConfigured)
516 .append(", mDebugVibrate=").append(mDebugVibrate)
John Spurlock190d0262014-09-14 15:39:13 -0400517 .append(", mSensor=").append(mSensor).append("}").toString();
John Spurlock559d9592014-08-09 12:04:36 -0400518 }
519
520 @Override
521 public void onTrigger(TriggerEvent event) {
Jeff Brown4d69e222014-09-18 15:27:50 -0700522 mWakeLock.acquire();
523 try {
524 if (DEBUG) Log.d(mTag, "onTrigger: " + triggerEventToString(event));
Adrian Roos5753f052016-07-13 10:30:37 -0700525 boolean sensorPerformsProxCheck = false;
Bhavik Singh3451da42016-06-01 18:25:59 -0700526 if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
527 int subType = (int) event.values[0];
528 MetricsLogger.action(mContext, MetricsEvent.ACTION_AMBIENT_GESTURE, subType);
Adrian Roos5753f052016-07-13 10:30:37 -0700529 sensorPerformsProxCheck = mDozeParameters.getPickupSubtypePerformsProxCheck(
530 subType);
Bhavik Singh3451da42016-06-01 18:25:59 -0700531 }
Jeff Brown4d69e222014-09-18 15:27:50 -0700532 if (mDebugVibrate) {
533 final Vibrator v = (Vibrator) mContext.getSystemService(
534 Context.VIBRATOR_SERVICE);
535 if (v != null) {
536 v.vibrate(1000, new AudioAttributes.Builder()
537 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
538 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build());
539 }
John Spurlock559d9592014-08-09 12:04:36 -0400540 }
John Spurlock50a8ea62014-09-16 09:12:03 -0400541
John Spurlock78503732014-11-10 09:41:41 -0500542 mRegistered = false;
Adrian Roos5753f052016-07-13 10:30:37 -0700543 requestPulse(mPulseReason, sensorPerformsProxCheck);
John Spurlock78503732014-11-10 09:41:41 -0500544 updateListener(); // reregister, this sensor only fires once
Jeff Brown4d69e222014-09-18 15:27:50 -0700545
Adrian Roosd13602f2016-08-22 15:31:38 +0200546 // record pickup gesture, also keep track of whether we might have been triggered
547 // by recent vibration.
548 final long timeSinceNotification = SystemClock.elapsedRealtime()
John Spurlock92b8d412014-10-03 17:12:40 -0400549 - mNotificationPulseTime;
Jeff Brown4d69e222014-09-18 15:27:50 -0700550 final boolean withinVibrationThreshold =
551 timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
Jeff Brown4d69e222014-09-18 15:27:50 -0700552 if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
Adrian Roos23c14fc2016-07-28 12:32:41 -0700553 DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
Jeff Brown4d69e222014-09-18 15:27:50 -0700554 }
555 } finally {
556 mWakeLock.release();
John Spurlock813552c2014-09-19 08:30:21 -0400557 }
John Spurlock559d9592014-08-09 12:04:36 -0400558 }
559 }
John Spurlock92b8d412014-10-03 17:12:40 -0400560
561 private abstract class ProximityCheck implements SensorEventListener, Runnable {
562 private static final int TIMEOUT_DELAY_MS = 500;
563
564 protected static final int RESULT_UNKNOWN = 0;
565 protected static final int RESULT_NEAR = 1;
566 protected static final int RESULT_FAR = 2;
567
568 private final String mTag = DozeService.this.mTag + ".ProximityCheck";
569
570 private boolean mRegistered;
571 private boolean mFinished;
572 private float mMaxRange;
573
574 abstract public void onProximityResult(int result);
575
576 public void check() {
577 if (mFinished || mRegistered) return;
Adrian Roos7294c112016-09-20 14:03:21 -0700578 final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
John Spurlock92b8d412014-10-03 17:12:40 -0400579 if (sensor == null) {
580 if (DEBUG) Log.d(mTag, "No sensor found");
581 finishWithResult(RESULT_UNKNOWN);
582 return;
583 }
584 // the pickup sensor interferes with the prox event, disable it until we have a result
585 mPickupSensor.setDisabled(true);
586
587 mMaxRange = sensor.getMaximumRange();
Adrian Roos7294c112016-09-20 14:03:21 -0700588 mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
589 mHandler);
John Spurlock92b8d412014-10-03 17:12:40 -0400590 mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
591 mRegistered = true;
592 }
593
594 @Override
595 public void onSensorChanged(SensorEvent event) {
596 if (event.values.length == 0) {
597 if (DEBUG) Log.d(mTag, "Event has no values!");
598 finishWithResult(RESULT_UNKNOWN);
599 } else {
600 if (DEBUG) Log.d(mTag, "Event: value=" + event.values[0] + " max=" + mMaxRange);
601 final boolean isNear = event.values[0] < mMaxRange;
602 finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR);
603 }
604 }
605
606 @Override
607 public void run() {
608 if (DEBUG) Log.d(mTag, "No event received before timeout");
609 finishWithResult(RESULT_UNKNOWN);
610 }
611
612 private void finishWithResult(int result) {
613 if (mFinished) return;
614 if (mRegistered) {
615 mHandler.removeCallbacks(this);
Adrian Roos7294c112016-09-20 14:03:21 -0700616 mSensorManager.unregisterListener(this);
John Spurlock92b8d412014-10-03 17:12:40 -0400617 // we're done - reenable the pickup sensor
618 mPickupSensor.setDisabled(false);
619 mRegistered = false;
620 }
621 onProximityResult(result);
622 mFinished = true;
623 }
624
625 @Override
626 public void onAccuracyChanged(Sensor sensor, int accuracy) {
627 // noop
628 }
629 }
John Spurlockbf370992014-06-17 13:58:31 -0400630}