blob: 5bc9b5faf61cee56bfd37c233201984fa976a1c0 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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.server;
18
Dianne Hackbornbed30e12009-03-31 14:46:20 -070019import com.android.internal.app.IBatteryStats;
20import com.android.server.am.BatteryStatsService;
21
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
Joe Onorato95e4f702009-03-24 19:29:09 -070027import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.os.Hardware;
29import android.os.IHardwareService;
Joe Onorato95e4f702009-03-24 19:29:09 -070030import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.Power;
32import android.os.PowerManager;
33import android.os.Process;
34import android.os.RemoteException;
35import android.os.IBinder;
36import android.os.Binder;
37import android.os.SystemClock;
38import android.util.Log;
39
40public class HardwareService extends IHardwareService.Stub {
41 private static final String TAG = "HardwareService";
42
The Android Open Source Project10592532009-03-18 17:39:46 -070043 static final int LIGHT_ID_BACKLIGHT = 0;
44 static final int LIGHT_ID_KEYBOARD = 1;
45 static final int LIGHT_ID_BUTTONS = 2;
46 static final int LIGHT_ID_BATTERY = 3;
47 static final int LIGHT_ID_NOTIFICATIONS = 4;
48 static final int LIGHT_ID_ATTENTION = 5;
49
50 static final int LIGHT_FLASH_NONE = 0;
51 static final int LIGHT_FLASH_TIMED = 1;
52
Joe Onorato95e4f702009-03-24 19:29:09 -070053 private boolean mAttentionLightOn;
54 private boolean mPulsing;
55
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 HardwareService(Context context) {
57 // Reset the hardware to a default state, in case this is a runtime
58 // restart instead of a fresh boot.
59 vibratorOff();
60
The Android Open Source Project10592532009-03-18 17:39:46 -070061 mNativePointer = init_native();
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 mContext = context;
64 PowerManager pm = (PowerManager)context.getSystemService(
65 Context.POWER_SERVICE);
66 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
67 mWakeLock.setReferenceCounted(true);
68
Dianne Hackbornbed30e12009-03-31 14:46:20 -070069 mBatteryStats = BatteryStatsService.getService();
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 IntentFilter filter = new IntentFilter();
72 filter.addAction(Intent.ACTION_SCREEN_OFF);
73 context.registerReceiver(mIntentReceiver, filter);
74 }
75
The Android Open Source Project10592532009-03-18 17:39:46 -070076 protected void finalize() throws Throwable {
77 finalize_native(mNativePointer);
78 super.finalize();
79 }
80
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 public void vibrate(long milliseconds) {
The Android Open Source Project10592532009-03-18 17:39:46 -070082 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
83 != PackageManager.PERMISSION_GRANTED) {
84 throw new SecurityException("Requires VIBRATE permission");
85 }
86 doCancelVibrate();
87 vibratorOn(milliseconds);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 }
89
90 private boolean isAll0(long[] pattern) {
91 int N = pattern.length;
92 for (int i = 0; i < N; i++) {
93 if (pattern[i] != 0) {
94 return false;
95 }
96 }
97 return true;
98 }
99
100 public void vibratePattern(long[] pattern, int repeat, IBinder token) {
101 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
102 != PackageManager.PERMISSION_GRANTED) {
103 throw new SecurityException("Requires VIBRATE permission");
104 }
105 // so wakelock calls will succeed
106 long identity = Binder.clearCallingIdentity();
107 try {
108 if (false) {
109 String s = "";
110 int N = pattern.length;
111 for (int i=0; i<N; i++) {
112 s += " " + pattern[i];
113 }
114 Log.i(TAG, "vibrating with pattern: " + s);
115 }
116
117 // we're running in the server so we can't fail
118 if (pattern == null || pattern.length == 0
119 || isAll0(pattern)
120 || repeat >= pattern.length || token == null) {
121 return;
122 }
123
124 synchronized (this) {
125 Death death = new Death(token);
126 try {
127 token.linkToDeath(death, 0);
128 } catch (RemoteException e) {
129 return;
130 }
131
132 Thread oldThread = mThread;
133
134 if (oldThread != null) {
135 // stop the old one
136 synchronized (mThread) {
137 mThread.mDone = true;
138 mThread.notify();
139 }
140 }
141
142 if (mDeath != null) {
143 mToken.unlinkToDeath(mDeath, 0);
144 }
145
146 mDeath = death;
147 mToken = token;
148
149 // start the new thread
150 mThread = new VibrateThread(pattern, repeat);
151 mThread.start();
152 }
153 }
154 finally {
155 Binder.restoreCallingIdentity(identity);
156 }
157 }
158
159 public void cancelVibrate() {
160 mContext.enforceCallingOrSelfPermission(
161 android.Manifest.permission.VIBRATE,
162 "cancelVibrate");
163
164 // so wakelock calls will succeed
165 long identity = Binder.clearCallingIdentity();
166 try {
167 doCancelVibrate();
168 }
169 finally {
170 Binder.restoreCallingIdentity(identity);
171 }
172 }
173
174 public boolean getFlashlightEnabled() {
175 return Hardware.getFlashlightEnabled();
176 }
177
178 public void setFlashlightEnabled(boolean on) {
179 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
180 != PackageManager.PERMISSION_GRANTED &&
181 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
182 != PackageManager.PERMISSION_GRANTED) {
183 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
184 }
185 Hardware.setFlashlightEnabled(on);
186 }
187
188 public void enableCameraFlash(int milliseconds) {
189 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
190 != PackageManager.PERMISSION_GRANTED &&
191 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
192 != PackageManager.PERMISSION_GRANTED) {
193 throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
194 }
195 Hardware.enableCameraFlash(milliseconds);
196 }
197
The Android Open Source Project10592532009-03-18 17:39:46 -0700198 public void setBacklights(int brightness) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
200 != PackageManager.PERMISSION_GRANTED) {
201 throw new SecurityException("Requires HARDWARE_TEST permission");
202 }
203 // Don't let applications turn the screen all the way off
204 brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
The Android Open Source Project10592532009-03-18 17:39:46 -0700205 setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness);
206 setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness);
207 setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness);
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700208 long identity = Binder.clearCallingIdentity();
209 try {
210 mBatteryStats.noteScreenBrightness(brightness);
211 } catch (RemoteException e) {
212 Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
213 } finally {
214 Binder.restoreCallingIdentity(identity);
215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 }
217
The Android Open Source Project10592532009-03-18 17:39:46 -0700218 void setLightOff_UNCHECKED(int light) {
219 setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221
The Android Open Source Project10592532009-03-18 17:39:46 -0700222 void setLightBrightness_UNCHECKED(int light, int brightness) {
223 int b = brightness & 0x000000ff;
224 b = 0xff000000 | (b << 16) | (b << 8) | b;
225 setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 }
227
The Android Open Source Project10592532009-03-18 17:39:46 -0700228 void setLightColor_UNCHECKED(int light, int color) {
229 setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0);
230 }
231
232 void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
233 setLight_native(mNativePointer, light, color, mode, onMS, offMS);
234 }
235
236 public void setAttentionLight(boolean on) {
237 // Not worthy of a permission. We shouldn't have a flashlight permission.
Joe Onorato95e4f702009-03-24 19:29:09 -0700238 synchronized (this) {
239 mAttentionLightOn = on;
240 mPulsing = false;
241 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, on ? 0xffffffff : 0,
242 LIGHT_FLASH_NONE, 0, 0);
243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
245
Joe Onorato95e4f702009-03-24 19:29:09 -0700246 public void pulseBreathingLight() {
247 synchronized (this) {
248 // HACK: Added at the last minute of cupcake -- design this better;
249 // Don't reuse the attention light -- make another one.
250 if (false) {
251 Log.d(TAG, "pulseBreathingLight mAttentionLightOn=" + mAttentionLightOn
252 + " mPulsing=" + mPulsing);
253 }
254 if (!mAttentionLightOn && !mPulsing) {
255 mPulsing = true;
256 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0xff101010,
257 LIGHT_FLASH_NONE, 0, 0);
258 mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
259 }
260 }
261 }
262
263 private Handler mH = new Handler() {
264 @Override
265 public void handleMessage(Message msg) {
266 synchronized (this) {
267 if (false) {
268 Log.d(TAG, "pulse cleanup handler firing mPulsing=" + mPulsing);
269 }
270 if (mPulsing) {
271 mPulsing = false;
272 setLight_native(mNativePointer, LIGHT_ID_ATTENTION,
273 mAttentionLightOn ? 0xffffffff : 0,
274 LIGHT_FLASH_NONE, 0, 0);
275 }
276 }
277 }
278 };
279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 private void doCancelVibrate() {
281 synchronized (this) {
282 if (mThread != null) {
283 synchronized (mThread) {
284 mThread.mDone = true;
285 mThread.notify();
286 }
287 mThread = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700289 vibratorOff();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 }
291 }
292
293 private class VibrateThread extends Thread {
294 long[] mPattern;
295 int mRepeat;
296 boolean mDone;
297
298 VibrateThread(long[] pattern, int repeat) {
299 mPattern = pattern;
300 mRepeat = repeat;
301 mWakeLock.acquire();
302 }
303
304 private void delay(long duration) {
305 if (duration > 0) {
306 long bedtime = SystemClock.uptimeMillis();
307 do {
308 try {
309 this.wait(duration);
310 }
311 catch (InterruptedException e) {
312 }
313 if (mDone) {
314 break;
315 }
316 duration = duration
317 - SystemClock.uptimeMillis() - bedtime;
318 } while (duration > 0);
319 }
320 }
321
322 public void run() {
323 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
324 synchronized (this) {
325 int index = 0;
326 long[] pattern = mPattern;
327 int len = pattern.length;
328 long duration = 0;
329
330 while (!mDone) {
331 // add off-time duration to any accumulated on-time duration
332 if (index < len) {
333 duration += pattern[index++];
334 }
335
336 // sleep until it is time to start the vibrator
337 delay(duration);
338 if (mDone) {
339 break;
340 }
341
342 if (index < len) {
343 // read on-time duration and start the vibrator
344 // duration is saved for delay() at top of loop
345 duration = pattern[index++];
346 if (duration > 0) {
347 HardwareService.this.vibratorOn(duration);
348 }
349 } else {
350 if (mRepeat < 0) {
351 break;
352 } else {
353 index = mRepeat;
354 duration = 0;
355 }
356 }
357 }
358 if (mDone) {
359 // make sure vibrator is off if we were cancelled.
360 // otherwise, it will turn off automatically
361 // when the last timeout expires.
362 HardwareService.this.vibratorOff();
363 }
364 mWakeLock.release();
365 }
366 synchronized (HardwareService.this) {
367 if (mThread == this) {
368 mThread = null;
369 }
370 }
371 }
372 };
373
374 private class Death implements IBinder.DeathRecipient {
375 IBinder mMe;
376
377 Death(IBinder me) {
378 mMe = me;
379 }
380
381 public void binderDied() {
382 synchronized (HardwareService.this) {
383 if (mMe == mToken) {
384 doCancelVibrate();
385 }
386 }
387 }
388 }
389
390 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
391 public void onReceive(Context context, Intent intent) {
392 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
393 doCancelVibrate();
394 }
395 }
396 };
The Android Open Source Project10592532009-03-18 17:39:46 -0700397
398 private static native int init_native();
399 private static native void finalize_native(int ptr);
400
401 private static native void setLight_native(int ptr, int light, int color, int mode,
402 int onMS, int offMS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700404 private final Context mContext;
405 private final PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700407 private final IBatteryStats mBatteryStats;
408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 volatile VibrateThread mThread;
410 volatile Death mDeath;
411 volatile IBinder mToken;
412
The Android Open Source Project10592532009-03-18 17:39:46 -0700413 private int mNativePointer;
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 native static void vibratorOn(long milliseconds);
416 native static void vibratorOff();
417}