DozeService.java revision bf370992508c55d1f2493923bdc1834a0710e4ba
1/*
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
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.hardware.Sensor;
24import android.hardware.SensorManager;
25import android.hardware.TriggerEvent;
26import android.hardware.TriggerEventListener;
27import android.os.PowerManager;
28import android.os.Vibrator;
29import android.service.dreams.DozeHardware;
30import android.service.dreams.DreamService;
31import android.util.Log;
32
33import com.android.systemui.SystemUIApplication;
34
35public class DozeService extends DreamService {
36    private static final boolean DEBUG = false;
37
38    private static final String TEASE_ACTION = "com.android.systemui.doze.tease";
39
40    private final String mTag = String.format("DozeService.%08x", hashCode());
41    private final Context mContext = this;
42
43    private Host mHost;
44    private DozeHardware mDozeHardware;
45    private SensorManager mSensors;
46    private Sensor mSigMotionSensor;
47    private PowerManager mPowerManager;
48    private PowerManager.WakeLock mWakeLock;
49    private boolean mDreaming;
50    private boolean mTeaseReceiverRegistered;
51
52    public DozeService() {
53        if (DEBUG) Log.d(mTag, "new DozeService()");
54        setDebug(DEBUG);
55    }
56
57    @Override
58    public void onCreate() {
59        if (DEBUG) Log.d(mTag, "onCreate");
60        super.onCreate();
61
62        if (getApplication() instanceof SystemUIApplication) {
63            final SystemUIApplication app = (SystemUIApplication) getApplication();
64            mHost = app.getComponent(Host.class);
65        }
66
67        setWindowless(true);
68
69        mSensors = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
70        mSigMotionSensor = mSensors.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
71        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
72        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
73    }
74
75    @Override
76    public void onAttachedToWindow() {
77        if (DEBUG) Log.d(mTag, "onAttachedToWindow");
78        super.onAttachedToWindow();
79    }
80
81    @Override
82    public void onDreamingStarted() {
83        super.onDreamingStarted();
84        mDozeHardware = getDozeHardware();
85        if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze()
86                + " dozeHardware=" + mDozeHardware);
87        mDreaming = true;
88        listenForTeaseSignals(true);
89        requestDoze();
90    }
91
92    public void stayAwake(long millis) {
93        if (mDreaming && millis > 0) {
94            mWakeLock.acquire(millis);
95        }
96    }
97
98    public void startDozing() {
99        if (DEBUG) Log.d(mTag, "startDozing mDreaming=" + mDreaming);
100        if (!mDreaming) {
101            Log.w(mTag, "Not dozing, no longer dreaming");
102            return;
103        }
104
105        super.startDozing();
106    }
107
108    @Override
109    public void onDreamingStopped() {
110        if (DEBUG) Log.d(mTag, "onDreamingStopped isDozing=" + isDozing());
111        super.onDreamingStopped();
112
113        mDreaming = false;
114        mDozeHardware = null;
115        if (mWakeLock.isHeld()) {
116            mWakeLock.release();
117        }
118        listenForTeaseSignals(false);
119        stopDozing();
120        dozingStopped();
121    }
122
123    @Override
124    public void onDetachedFromWindow() {
125        if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
126        super.onDetachedFromWindow();
127
128        dozingStopped();
129    }
130
131    @Override
132    public void onDestroy() {
133        if (DEBUG) Log.d(mTag, "onDestroy");
134        super.onDestroy();
135
136        dozingStopped();
137    }
138
139    private void requestDoze() {
140        if (mHost != null) {
141            mHost.requestDoze(this);
142        }
143    }
144
145    private void requestTease() {
146        if (mHost != null) {
147            mHost.requestTease(this);
148        }
149    }
150
151    private void dozingStopped() {
152        if (mHost != null) {
153            mHost.dozingStopped(this);
154        }
155    }
156
157    private void listenForTeaseSignals(boolean listen) {
158        if (DEBUG) Log.d(mTag, "listenForTeaseSignals: " + listen);
159        if (mHost == null) return;
160        listenForSignificantMotion(listen);
161        if (listen) {
162            mContext.registerReceiver(mTeaseReceiver, new IntentFilter(TEASE_ACTION));
163            mTeaseReceiverRegistered = true;
164            mHost.addCallback(mHostCallback);
165        } else {
166            if (mTeaseReceiverRegistered) {
167                mContext.unregisterReceiver(mTeaseReceiver);
168            }
169            mTeaseReceiverRegistered = false;
170            mHost.removeCallback(mHostCallback);
171        }
172    }
173
174    private void listenForSignificantMotion(boolean listen) {
175        if (mSigMotionSensor == null) return;
176        if (listen) {
177            mSensors.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
178        } else {
179            mSensors.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
180        }
181    }
182
183    private static String triggerEventToString(TriggerEvent event) {
184        if (event == null) return null;
185        final StringBuilder sb = new StringBuilder("TriggerEvent[")
186                .append(event.timestamp).append(',')
187                .append(event.sensor.getName());
188        if (event.values != null) {
189            for (int i = 0; i < event.values.length; i++) {
190                sb.append(',').append(event.values[i]);
191            }
192        }
193        return sb.append(']').toString();
194    }
195
196    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
197        @Override
198        public void onTrigger(TriggerEvent event) {
199            if (DEBUG) Log.d(mTag, "sigMotion.onTrigger: " + triggerEventToString(event));
200            if (DEBUG) {
201                final Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
202                if (v != null) {
203                    v.vibrate(1000);
204                }
205            }
206            requestTease();
207            listenForSignificantMotion(true);  // reregister, this sensor only fires once
208        }
209    };
210
211    private final BroadcastReceiver mTeaseReceiver = new BroadcastReceiver() {
212        @Override
213        public void onReceive(Context context, Intent intent) {
214            if (DEBUG) Log.d(mTag, "Received tease intent");
215            requestTease();
216        }
217    };
218
219    private final Host.Callback mHostCallback = new Host.Callback() {
220        @Override
221        public void onNewNotifications() {
222            if (DEBUG) Log.d(mTag, "onNewNotifications");
223            requestTease();
224        }
225    };
226
227    public interface Host {
228        void addCallback(Callback callback);
229        void removeCallback(Callback callback);
230        void requestDoze(DozeService dozeService);
231        void requestTease(DozeService dozeService);
232        void dozingStopped(DozeService dozeService);
233
234        public interface Callback {
235            void onNewNotifications();
236        }
237    }
238}
239