blob: 333b8b483142413d6722996558505ba2b8838163 [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 Spurlockbf370992014-06-17 13:58:31 -040022import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
John Spurlocked69bd62014-07-23 11:09:02 -040026import android.content.res.Resources;
John Spurlockbf370992014-06-17 13:58:31 -040027import android.hardware.Sensor;
28import android.hardware.SensorManager;
29import android.hardware.TriggerEvent;
30import android.hardware.TriggerEventListener;
John Spurlocked69bd62014-07-23 11:09:02 -040031import android.os.Handler;
John Spurlockbf370992014-06-17 13:58:31 -040032import android.os.PowerManager;
John Spurlock66127272014-06-28 11:27:17 -040033import android.os.SystemProperties;
John Spurlockbf370992014-06-17 13:58:31 -040034import android.os.Vibrator;
35import android.service.dreams.DozeHardware;
36import android.service.dreams.DreamService;
37import android.util.Log;
John Spurlocked69bd62014-07-23 11:09:02 -040038import android.util.MathUtils;
39import android.view.Display;
John Spurlockbf370992014-06-17 13:58:31 -040040
John Spurlock66127272014-06-28 11:27:17 -040041import com.android.systemui.R;
John Spurlockbf370992014-06-17 13:58:31 -040042import com.android.systemui.SystemUIApplication;
43
John Spurlock66127272014-06-28 11:27:17 -040044import java.io.FileDescriptor;
45import java.io.PrintWriter;
46
John Spurlockbf370992014-06-17 13:58:31 -040047public class DozeService extends DreamService {
John Spurlocked69bd62014-07-23 11:09:02 -040048 private static final String TAG = "DozeService";
49 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlockbf370992014-06-17 13:58:31 -040050
51 private static final String TEASE_ACTION = "com.android.systemui.doze.tease";
52
John Spurlocked69bd62014-07-23 11:09:02 -040053 private final String mTag = String.format(TAG + ".%08x", hashCode());
John Spurlockbf370992014-06-17 13:58:31 -040054 private final Context mContext = this;
John Spurlocked69bd62014-07-23 11:09:02 -040055 private final Handler mHandler = new Handler();
John Spurlockbf370992014-06-17 13:58:31 -040056
57 private Host mHost;
58 private DozeHardware mDozeHardware;
59 private SensorManager mSensors;
60 private Sensor mSigMotionSensor;
61 private PowerManager mPowerManager;
62 private PowerManager.WakeLock mWakeLock;
John Spurlocked69bd62014-07-23 11:09:02 -040063 private int mMaxBrightness;
John Spurlockbf370992014-06-17 13:58:31 -040064 private boolean mDreaming;
65 private boolean mTeaseReceiverRegistered;
John Spurlock66127272014-06-28 11:27:17 -040066 private boolean mSigMotionConfigured;
67 private boolean mSigMotionEnabled;
John Spurlocked69bd62014-07-23 11:09:02 -040068 private boolean mDisplayStateSupported;
69 private int mDisplayStateWhenOn;
John Spurlockbf370992014-06-17 13:58:31 -040070
71 public DozeService() {
72 if (DEBUG) Log.d(mTag, "new DozeService()");
73 setDebug(DEBUG);
74 }
75
76 @Override
John Spurlock66127272014-06-28 11:27:17 -040077 protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
78 super.dumpOnHandler(fd, pw, args);
79 pw.print(" mDreaming: "); pw.println(mDreaming);
80 pw.print(" mDozeHardware: "); pw.println(mDozeHardware);
81 pw.print(" mTeaseReceiverRegistered: "); pw.println(mTeaseReceiverRegistered);
82 pw.print(" mSigMotionSensor: "); pw.println(mSigMotionSensor);
83 pw.print(" mSigMotionConfigured: "); pw.println(mSigMotionConfigured);
84 pw.print(" mSigMotionEnabled: "); pw.println(mSigMotionEnabled);
John Spurlocked69bd62014-07-23 11:09:02 -040085 pw.print(" mMaxBrightness: "); pw.println(mMaxBrightness);
86 pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
John Spurlock66127272014-06-28 11:27:17 -040087 }
88
89 @Override
John Spurlockbf370992014-06-17 13:58:31 -040090 public void onCreate() {
91 if (DEBUG) Log.d(mTag, "onCreate");
92 super.onCreate();
93
94 if (getApplication() instanceof SystemUIApplication) {
95 final SystemUIApplication app = (SystemUIApplication) getApplication();
96 mHost = app.getComponent(Host.class);
97 }
98
99 setWindowless(true);
100
101 mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
102 mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
103 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
104 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
John Spurlocked69bd62014-07-23 11:09:02 -0400105 final Resources res = mContext.getResources();
John Spurlock66127272014-06-28 11:27:17 -0400106 mSigMotionConfigured = SystemProperties.getBoolean("doze.tease.sigmotion",
John Spurlocked69bd62014-07-23 11:09:02 -0400107 res.getBoolean(R.bool.doze_tease_on_significant_motion));
108 mDisplayStateSupported = SystemProperties.getBoolean("doze.display.supported",
109 res.getBoolean(R.bool.doze_display_state_supported));
110 mMaxBrightness = MathUtils.constrain(res.getInteger(R.integer.doze_tease_brightness),
111 BRIGHTNESS_OFF, BRIGHTNESS_ON);
112
113 mDisplayStateWhenOn = mDisplayStateSupported ? Display.STATE_DOZE : Display.STATE_ON;
114 setDozeScreenState(mDisplayStateWhenOn);
John Spurlockbf370992014-06-17 13:58:31 -0400115 }
116
117 @Override
118 public void onAttachedToWindow() {
119 if (DEBUG) Log.d(mTag, "onAttachedToWindow");
120 super.onAttachedToWindow();
121 }
122
123 @Override
124 public void onDreamingStarted() {
125 super.onDreamingStarted();
126 mDozeHardware = getDozeHardware();
127 if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze()
128 + " dozeHardware=" + mDozeHardware);
129 mDreaming = true;
130 listenForTeaseSignals(true);
131 requestDoze();
132 }
133
134 public void stayAwake(long millis) {
135 if (mDreaming && millis > 0) {
136 mWakeLock.acquire(millis);
John Spurlocked69bd62014-07-23 11:09:02 -0400137 setDozeScreenState(mDisplayStateWhenOn);
138 setDozeScreenBrightness(mMaxBrightness);
139 rescheduleOff(millis);
John Spurlockbf370992014-06-17 13:58:31 -0400140 }
141 }
142
John Spurlocked69bd62014-07-23 11:09:02 -0400143 private void rescheduleOff(long millis) {
144 if (DEBUG) Log.d(TAG, "rescheduleOff millis=" + millis);
145 mHandler.removeCallbacks(mDisplayOff);
146 mHandler.postDelayed(mDisplayOff, millis);
147 }
148
John Spurlockbf370992014-06-17 13:58:31 -0400149 public void startDozing() {
150 if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming);
151 if (!mDreaming) {
152 Log.w(mTag, "Not dozing, no longer dreaming");
153 return;
154 }
155
156 super.startDozing();
157 }
158
159 @Override
160 public void onDreamingStopped() {
161 if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
162 super.onDreamingStopped();
163
164 mDreaming = false;
165 mDozeHardware = null;
166 if (mWakeLock.isHeld()) {
167 mWakeLock.release();
168 }
169 listenForTeaseSignals(false);
170 stopDozing();
171 dozingStopped();
172 }
173
174 @Override
175 public void onDetachedFromWindow() {
176 if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
177 super.onDetachedFromWindow();
178
179 dozingStopped();
180 }
181
182 @Override
183 public void onDestroy() {
184 if (DEBUG) Log.d(mTag, "onDestroy");
185 super.onDestroy();
186
187 dozingStopped();
188 }
189
190 private void requestDoze() {
191 if (mHost != null) {
192 mHost.requestDoze(this);
193 }
194 }
195
196 private void requestTease() {
197 if (mHost != null) {
198 mHost.requestTease(this);
199 }
200 }
201
202 private void dozingStopped() {
203 if (mHost != null) {
204 mHost.dozingStopped(this);
205 }
206 }
207
208 private void listenForTeaseSignals(boolean listen) {
209 if (DEBUG) Log.d(mTag, "listenForTeaseSignals: " + listen);
John Spurlockbf370992014-06-17 13:58:31 -0400210 listenForSignificantMotion(listen);
John Spurlock66127272014-06-28 11:27:17 -0400211 listenForBroadcast(listen);
212 listenForNotifications(listen);
213 }
214
215 private void listenForSignificantMotion(boolean listen) {
216 if (!mSigMotionConfigured || mSigMotionSensor == null) return;
217 if (listen) {
218 mSigMotionEnabled =
219 mSensors.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
220 } else if (mSigMotionEnabled) {
221 mSensors.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
222 }
223 }
224
225 private void listenForBroadcast(boolean listen) {
John Spurlockbf370992014-06-17 13:58:31 -0400226 if (listen) {
227 mContext.registerReceiver(mTeaseReceiver, new IntentFilter(TEASE_ACTION));
228 mTeaseReceiverRegistered = true;
John Spurlockbf370992014-06-17 13:58:31 -0400229 } else {
230 if (mTeaseReceiverRegistered) {
231 mContext.unregisterReceiver(mTeaseReceiver);
232 }
233 mTeaseReceiverRegistered = false;
John Spurlockbf370992014-06-17 13:58:31 -0400234 }
235 }
236
John Spurlock66127272014-06-28 11:27:17 -0400237 private void listenForNotifications(boolean listen) {
238 if (mHost == null) return;
John Spurlockbf370992014-06-17 13:58:31 -0400239 if (listen) {
John Spurlock66127272014-06-28 11:27:17 -0400240 mHost.addCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400241 } else {
John Spurlock66127272014-06-28 11:27:17 -0400242 mHost.removeCallback(mHostCallback);
John Spurlockbf370992014-06-17 13:58:31 -0400243 }
244 }
245
246 private static String triggerEventToString(TriggerEvent event) {
247 if (event == null) return null;
248 final StringBuilder sb = new StringBuilder("TriggerEvent[")
249 .append(event.timestamp).append(',')
250 .append(event.sensor.getName());
251 if (event.values != null) {
252 for (int i = 0; i < event.values.length; i++) {
253 sb.append(',').append(event.values[i]);
254 }
255 }
256 return sb.append(']').toString();
257 }
258
John Spurlocked69bd62014-07-23 11:09:02 -0400259 private final Runnable mDisplayOff = new Runnable() {
260 @Override
261 public void run() {
262 if (DEBUG) Log.d(TAG, "Display off");
263 setDozeScreenState(Display.STATE_OFF);
264 setDozeScreenBrightness(PowerManager.BRIGHTNESS_DEFAULT);
265 }
266 };
267
John Spurlockbf370992014-06-17 13:58:31 -0400268 private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
269 @Override
270 public void onTrigger(TriggerEvent event) {
271 if (DEBUG) Log.d(mTag, "sigMotion.onTrigger: " + triggerEventToString(event));
272 if (DEBUG) {
273 final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
274 if (v != null) {
275 v.vibrate(1000);
276 }
277 }
278 requestTease();
279 listenForSignificantMotion(true); // reregister, this sensor only fires once
280 }
281 };
282
283 private final BroadcastReceiver mTeaseReceiver = new BroadcastReceiver() {
284 @Override
285 public void onReceive(Context context, Intent intent) {
286 if (DEBUG) Log.d(mTag, "Received tease intent");
287 requestTease();
288 }
289 };
290
291 private final Host.Callback mHostCallback = new Host.Callback() {
292 @Override
293 public void onNewNotifications() {
294 if (DEBUG) Log.d(mTag, "onNewNotifications");
295 requestTease();
296 }
297 };
298
299 public interface Host {
300 void addCallback(Callback callback);
301 void removeCallback(Callback callback);
302 void requestDoze(DozeService dozeService);
303 void requestTease(DozeService dozeService);
304 void dozingStopped(DozeService dozeService);
305
306 public interface Callback {
307 void onNewNotifications();
308 }
309 }
310}