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