blob: 943a294a42cd1eda866c8dbda657612fd8fd3512 [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
John Spurlocked69bd62014-07-23 11:09:02 -040019import static android.os.PowerManager.BRIGHTNESS_OFF;
20import static android.os.PowerManager.BRIGHTNESS_ON;
21
John Spurlockcb566aa2014-08-03 22:58:28 -040022import android.app.AlarmManager;
23import android.app.PendingIntent;
John Spurlockbf370992014-06-17 13:58:31 -040024import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
John Spurlocked69bd62014-07-23 11:09:02 -040028import android.content.res.Resources;
John Spurlockbf370992014-06-17 13:58:31 -040029import android.hardware.Sensor;
30import android.hardware.SensorManager;
31import android.hardware.TriggerEvent;
32import android.hardware.TriggerEventListener;
John Spurlocked69bd62014-07-23 11:09:02 -040033import android.os.Handler;
John Spurlockbf370992014-06-17 13:58:31 -040034import android.os.PowerManager;
John Spurlock66127272014-06-28 11:27:17 -040035import android.os.SystemProperties;
John Spurlockbf370992014-06-17 13:58:31 -040036import android.os.Vibrator;
John Spurlockbf370992014-06-17 13:58:31 -040037import android.service.dreams.DreamService;
38import android.util.Log;
John Spurlocked69bd62014-07-23 11:09:02 -040039import android.util.MathUtils;
40import android.view.Display;
John Spurlockbf370992014-06-17 13:58:31 -040041
John Spurlock66127272014-06-28 11:27:17 -040042import com.android.systemui.R;
John Spurlockbf370992014-06-17 13:58:31 -040043import com.android.systemui.SystemUIApplication;
44
John Spurlock66127272014-06-28 11:27:17 -040045import java.io.FileDescriptor;
46import java.io.PrintWriter;
John Spurlockcb566aa2014-08-03 22:58:28 -040047import java.util.Date;
John Spurlock66127272014-06-28 11:27:17 -040048
John Spurlockbf370992014-06-17 13:58:31 -040049public class DozeService extends DreamService {
John Spurlocked69bd62014-07-23 11:09:02 -040050 private static final String TAG = "DozeService";
51 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlockbf370992014-06-17 13:58:31 -040052
John Spurlockcb566aa2014-08-03 22:58:28 -040053 private static final String ACTION_BASE = "com.android.systemui.doze";
54 private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
55 private static final String NOTIFICATION_PULSE_ACTION = ACTION_BASE + ".notification_pulse";
56 private static final String EXTRA_PULSES = "pulses";
John Spurlockbf370992014-06-17 13:58:31 -040057
John Spurlocked69bd62014-07-23 11:09:02 -040058 private final String mTag = String.format(TAG + ".%08x", hashCode());
John Spurlockbf370992014-06-17 13:58:31 -040059 private final Context mContext = this;
John Spurlocked69bd62014-07-23 11:09:02 -040060 private final Handler mHandler = new Handler();
John Spurlockbf370992014-06-17 13:58:31 -040061
62 private Host mHost;
John Spurlockbf370992014-06-17 13:58:31 -040063 private SensorManager mSensors;
64 private Sensor mSigMotionSensor;
65 private PowerManager mPowerManager;
66 private PowerManager.WakeLock mWakeLock;
John Spurlockcb566aa2014-08-03 22:58:28 -040067 private AlarmManager mAlarmManager;
John Spurlocked69bd62014-07-23 11:09:02 -040068 private int mMaxBrightness;
John Spurlockbf370992014-06-17 13:58:31 -040069 private boolean mDreaming;
John Spurlockcb566aa2014-08-03 22:58:28 -040070 private boolean mBroadcastReceiverRegistered;
John Spurlock66127272014-06-28 11:27:17 -040071 private boolean mSigMotionConfigured;
72 private boolean mSigMotionEnabled;
John Spurlocked69bd62014-07-23 11:09:02 -040073 private boolean mDisplayStateSupported;
74 private int mDisplayStateWhenOn;
John Spurlockcb566aa2014-08-03 22:58:28 -040075 private boolean mNotificationLightOn;
76 private PendingIntent mNotificationPulseIntent;
77 private int mMultipulseCount;
78 private int mNotificationPulseInterval;
John Spurlockbf370992014-06-17 13:58:31 -040079
80 public DozeService() {
81 if (DEBUG) Log.d(mTag, "new DozeService()");
82 setDebug(DEBUG);
83 }
84
85 @Override
John Spurlock66127272014-06-28 11:27:17 -040086 protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
87 super.dumpOnHandler(fd, pw, args);
88 pw.print(" mDreaming: "); pw.println(mDreaming);
John Spurlockcb566aa2014-08-03 22:58:28 -040089 pw.print(" mBroadcastReceiverRegistered: "); pw.println(mBroadcastReceiverRegistered);
John Spurlock66127272014-06-28 11:27:17 -040090 pw.print(" mSigMotionSensor: "); pw.println(mSigMotionSensor);
91 pw.print(" mSigMotionConfigured: "); pw.println(mSigMotionConfigured);
92 pw.print(" mSigMotionEnabled: "); pw.println(mSigMotionEnabled);
John Spurlocked69bd62014-07-23 11:09:02 -040093 pw.print(" mMaxBrightness: "); pw.println(mMaxBrightness);
94 pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
John Spurlockcb566aa2014-08-03 22:58:28 -040095 pw.print(" mNotificationLightOn: "); pw.println(mNotificationLightOn);
96 pw.print(" mMultipulseCount: "); pw.println(mMultipulseCount);
97 pw.print(" mNotificationPulseInterval: "); pw.println(mNotificationPulseInterval);
John Spurlock66127272014-06-28 11:27:17 -040098 }
99
100 @Override
John Spurlockbf370992014-06-17 13:58:31 -0400101 public void onCreate() {
102 if (DEBUG) Log.d(mTag, "onCreate");
103 super.onCreate();
104
105 if (getApplication() instanceof SystemUIApplication) {
106 final SystemUIApplication app = (SystemUIApplication) getApplication();
107 mHost = app.getComponent(Host.class);
108 }
109
110 setWindowless(true);
111
112 mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
113 mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
114 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
115 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
John Spurlockcb566aa2014-08-03 22:58:28 -0400116 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
John Spurlocked69bd62014-07-23 11:09:02 -0400117 final Resources res = mContext.getResources();
John Spurlockcb566aa2014-08-03 22:58:28 -0400118 mSigMotionConfigured = SystemProperties.getBoolean("doze.pulse.sigmotion",
119 res.getBoolean(R.bool.doze_pulse_on_significant_motion));
John Spurlocked69bd62014-07-23 11:09:02 -0400120 mDisplayStateSupported = SystemProperties.getBoolean("doze.display.supported",
121 res.getBoolean(R.bool.doze_display_state_supported));
John Spurlockcb566aa2014-08-03 22:58:28 -0400122 mMaxBrightness = MathUtils.constrain(res.getInteger(R.integer.doze_pulse_brightness),
John Spurlocked69bd62014-07-23 11:09:02 -0400123 BRIGHTNESS_OFF, BRIGHTNESS_ON);
John Spurlockcb566aa2014-08-03 22:58:28 -0400124 mNotificationPulseIntent = PendingIntent.getBroadcast(mContext, 0,
125 new Intent(NOTIFICATION_PULSE_ACTION).setPackage(getPackageName()),
126 PendingIntent.FLAG_CANCEL_CURRENT);
127 mMultipulseCount = SystemProperties.getInt("doze.multipulses",
128 res.getInteger(R.integer.doze_multipulse_count));
129 mNotificationPulseInterval = SystemProperties.getInt("doze.notification.pulse",
130 res.getInteger(R.integer.doze_notification_pulse_interval));
John Spurlocked69bd62014-07-23 11:09:02 -0400131 mDisplayStateWhenOn = mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON;
132 setDozeScreenState(mDisplayStateWhenOn);
John Spurlockbf370992014-06-17 13:58:31 -0400133 }
134
135 @Override
136 public void onAttachedToWindow() {
137 if (DEBUG) Log.d(mTag, "onAttachedToWindow");
138 super.onAttachedToWindow();
139 }
140
141 @Override
142 public void onDreamingStarted() {
143 super.onDreamingStarted();
Jeff Brown0f208eb2014-07-26 15:14:21 -0700144 if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze());
John Spurlockbf370992014-06-17 13:58:31 -0400145 mDreaming = true;
John Spurlockcb566aa2014-08-03 22:58:28 -0400146 listenForPulseSignals(true);
John Spurlockbf370992014-06-17 13:58:31 -0400147 requestDoze();
148 }
149
150 public void stayAwake(long millis) {
151 if (mDreaming && millis > 0) {
152 mWakeLock.acquire(millis);
John Spurlocked69bd62014-07-23 11:09:02 -0400153 setDozeScreenState(mDisplayStateWhenOn);
154 setDozeScreenBrightness(mMaxBrightness);
155 rescheduleOff(millis);
John Spurlockbf370992014-06-17 13:58:31 -0400156 }
157 }
158
John Spurlocked69bd62014-07-23 11:09:02 -0400159 private void rescheduleOff(long millis) {
160 if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis);
161 mHandler.removeCallbacks(mDisplayOff);
162 mHandler.postDelayed(mDisplayOff, millis);
163 }
164
John Spurlockbf370992014-06-17 13:58:31 -0400165 public void startDozing() {
166 if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming);
167 if (!mDreaming) {
168 Log.w(mTag, "Not dozing, no longer dreaming");
169 return;
170 }
171
172 super.startDozing();
173 }
174
175 @Override
176 public void onDreamingStopped() {
177 if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
178 super.onDreamingStopped();
179
180 mDreaming = false;
John Spurlockbf370992014-06-17 13:58:31 -0400181 if (mWakeLock.isHeld()) {
182 mWakeLock.release();
183 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400184 listenForPulseSignals(false);
John Spurlockbf370992014-06-17 13:58:31 -0400185 stopDozing();
186 dozingStopped();
187 }
188
189 @Override
190 public void onDetachedFromWindow() {
191 if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
192 super.onDetachedFromWindow();
193
194 dozingStopped();
195 }
196
197 @Override
198 public void onDestroy() {
199 if (DEBUG) Log.d(mTag, "onDestroy");
200 super.onDestroy();
201
202 dozingStopped();
203 }
204
205 private void requestDoze() {
206 if (mHost != null) {
207 mHost.requestDoze(this);
208 }
209 }
210
John Spurlockcb566aa2014-08-03 22:58:28 -0400211 private void requestMultipulse() {
212 requestPulse(mMultipulseCount);
213 }
214
215 private void requestPulse() {
216 requestPulse(1);
217 }
218
219 private void requestPulse(int pulses) {
John Spurlockbf370992014-06-17 13:58:31 -0400220 if (mHost != null) {
John Spurlockcb566aa2014-08-03 22:58:28 -0400221 mHost.requestPulse(pulses, this);
John Spurlockbf370992014-06-17 13:58:31 -0400222 }
223 }
224
225 private void dozingStopped() {
226 if (mHost != null) {
227 mHost.dozingStopped(this);
228 }
229 }
230
John Spurlockcb566aa2014-08-03 22:58:28 -0400231 private void listenForPulseSignals(boolean listen) {
232 if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
John Spurlockbf370992014-06-17 13:58:31 -0400233 listenForSignificantMotion(listen);
John Spurlockcb566aa2014-08-03 22:58:28 -0400234 listenForBroadcasts(listen);
John Spurlock66127272014-06-28 11:27:17 -0400235 listenForNotifications(listen);
236 }
237
238 private void listenForSignificantMotion(boolean listen) {
239 if (!mSigMotionConfigured || mSigMotionSensor == null) return;
240 if (listen) {
241 mSigMotionEnabled =
242 mSensors.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
243 } else if (mSigMotionEnabled) {
244 mSensors.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
245 }
246 }
247
John Spurlockcb566aa2014-08-03 22:58:28 -0400248 private void listenForBroadcasts(boolean listen) {
John Spurlockbf370992014-06-17 13:58:31 -0400249 if (listen) {
John Spurlockcb566aa2014-08-03 22:58:28 -0400250 final IntentFilter filter = new IntentFilter(PULSE_ACTION);
251 filter.addAction(NOTIFICATION_PULSE_ACTION);
252 mContext.registerReceiver(mBroadcastReceiver, filter);
253 mBroadcastReceiverRegistered = true;
John Spurlockbf370992014-06-17 13:58:31 -0400254 } else {
John Spurlockcb566aa2014-08-03 22:58:28 -0400255 if (mBroadcastReceiverRegistered) {
256 mContext.unregisterReceiver(mBroadcastReceiver);
John Spurlockbf370992014-06-17 13:58:31 -0400257 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400258 mBroadcastReceiverRegistered = false;
John Spurlockbf370992014-06-17 13:58:31 -0400259 }
260 }
261
John Spurlock66127272014-06-28 11:27:17 -0400262 private void listenForNotifications(boolean listen) {
263 if (mHost == null) return;
John Spurlockbf370992014-06-17 13:58:31 -0400264 if (listen) {
John Spurlock66127272014-06-28 11:27:17 -0400265 mHost.addCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400266 } else {
John Spurlock66127272014-06-28 11:27:17 -0400267 mHost.removeCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400268 }
269 }
270
John Spurlockcb566aa2014-08-03 22:58:28 -0400271 private void rescheduleNotificationPulse() {
272 mAlarmManager.cancel(mNotificationPulseIntent);
273 if (mNotificationLightOn) {
274 final long time = System.currentTimeMillis() + mNotificationPulseInterval;
275 if (DEBUG) Log.d(TAG, "Scheduling pulse for " + new Date(time));
276 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, time, mNotificationPulseIntent);
277 }
278 }
279
John Spurlockbf370992014-06-17 13:58:31 -0400280 private static String triggerEventToString(TriggerEvent event) {
281 if (event == null) return null;
282 final StringBuilder sb = new StringBuilder("TriggerEvent[")
283 .append(event.timestamp).append(',')
284 .append(event.sensor.getName());
285 if (event.values != null) {
286 for (int i = 0; i < event.values.length; i++) {
287 sb.append(',').append(event.values[i]);
288 }
289 }
290 return sb.append(']').toString();
291 }
292
John Spurlocked69bd62014-07-23 11:09:02 -0400293 private final Runnable mDisplayOff = new Runnable() {
294 @Override
295 public void run() {
296 if (DEBUG) Log.d(TAG, "Display off");
297 setDozeScreenState(Display.STATE_OFF);
298 setDozeScreenBrightness(PowerManager.BRIGHTNESS_DEFAULT);
299 }
300 };
301
John Spurlockbf370992014-06-17 13:58:31 -0400302 private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
303 @Override
304 public void onTrigger(TriggerEvent event) {
305 if (DEBUG) Log.d(mTag, "sigMotion.onTrigger: " + triggerEventToString(event));
306 if (DEBUG) {
307 final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
308 if (v != null) {
309 v.vibrate(1000);
310 }
311 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400312 requestPulse();
John Spurlockbf370992014-06-17 13:58:31 -0400313 listenForSignificantMotion(true); // reregister, this sensor only fires once
314 }
315 };
316
John Spurlockcb566aa2014-08-03 22:58:28 -0400317 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
John Spurlockbf370992014-06-17 13:58:31 -0400318 @Override
319 public void onReceive(Context context, Intent intent) {
John Spurlockcb566aa2014-08-03 22:58:28 -0400320 if (PULSE_ACTION.equals(intent.getAction())) {
321 if (DEBUG) Log.d(mTag, "Received pulse intent");
322 requestPulse(intent.getIntExtra(EXTRA_PULSES, mMultipulseCount));
323 }
324 if (NOTIFICATION_PULSE_ACTION.equals(intent.getAction())) {
325 if (DEBUG) Log.d(mTag, "Received notification pulse intent");
326 requestPulse();
327 rescheduleNotificationPulse();
328 }
John Spurlockbf370992014-06-17 13:58:31 -0400329 }
330 };
331
332 private final Host.Callback mHostCallback = new Host.Callback() {
333 @Override
334 public void onNewNotifications() {
335 if (DEBUG) Log.d(mTag, "onNewNotifications");
John Spurlockcad57682014-07-26 17:09:56 -0400336 // noop for now
337 }
John Spurlockcb566aa2014-08-03 22:58:28 -0400338
John Spurlockcad57682014-07-26 17:09:56 -0400339 @Override
340 public void onBuzzBeepBlinked() {
341 if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
John Spurlockcb566aa2014-08-03 22:58:28 -0400342 requestMultipulse();
343 }
344
345 @Override
346 public void onNotificationLight(boolean on) {
347 if (DEBUG) Log.d(mTag, "onNotificationLight on=" + on);
348 if (mNotificationLightOn == on) return;
349 mNotificationLightOn = on;
350 rescheduleNotificationPulse();
John Spurlockbf370992014-06-17 13:58:31 -0400351 }
352 };
353
354 public interface Host {
355 void addCallback(Callback callback);
356 void removeCallback(Callback callback);
357 void requestDoze(DozeService dozeService);
John Spurlockcb566aa2014-08-03 22:58:28 -0400358 void requestPulse(int pulses, DozeService dozeService);
John Spurlockbf370992014-06-17 13:58:31 -0400359 void dozingStopped(DozeService dozeService);
360
361 public interface Callback {
362 void onNewNotifications();
John Spurlockcad57682014-07-26 17:09:56 -0400363 void onBuzzBeepBlinked();
John Spurlockcb566aa2014-08-03 22:58:28 -0400364 void onNotificationLight(boolean on);
John Spurlockbf370992014-06-17 13:58:31 -0400365 }
366 }
367}