blob: 88074c2c59eab371b5d3022dc6c90bb187df1d7c [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
Patrick Scott18dd5f02009-07-02 11:31:12 -040040import java.util.LinkedList;
41import java.util.ListIterator;
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043public class HardwareService extends IHardwareService.Stub {
44 private static final String TAG = "HardwareService";
45
The Android Open Source Project10592532009-03-18 17:39:46 -070046 static final int LIGHT_ID_BACKLIGHT = 0;
47 static final int LIGHT_ID_KEYBOARD = 1;
48 static final int LIGHT_ID_BUTTONS = 2;
49 static final int LIGHT_ID_BATTERY = 3;
50 static final int LIGHT_ID_NOTIFICATIONS = 4;
51 static final int LIGHT_ID_ATTENTION = 5;
52
53 static final int LIGHT_FLASH_NONE = 0;
54 static final int LIGHT_FLASH_TIMED = 1;
Eric Olsenf42f15c2009-10-29 16:42:03 -070055 static final int LIGHT_FLASH_HARDWARE = 2;
The Android Open Source Project10592532009-03-18 17:39:46 -070056
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050057 /**
58 * Light brightness is managed by a user setting.
59 */
60 static final int BRIGHTNESS_MODE_USER = 0;
61
62 /**
63 * Light brightness is managed by a light sensor.
64 */
65 static final int BRIGHTNESS_MODE_SENSOR = 1;
66
Patrick Scott18dd5f02009-07-02 11:31:12 -040067 private final LinkedList<Vibration> mVibrations;
68 private Vibration mCurrentVibration;
69
Joe Onorato95e4f702009-03-24 19:29:09 -070070 private boolean mAttentionLightOn;
71 private boolean mPulsing;
72
Patrick Scott18dd5f02009-07-02 11:31:12 -040073 private class Vibration implements IBinder.DeathRecipient {
74 private final IBinder mToken;
75 private final long mTimeout;
76 private final long mStartTime;
77 private final long[] mPattern;
78 private final int mRepeat;
79
80 Vibration(IBinder token, long millis) {
81 this(token, millis, null, 0);
82 }
83
84 Vibration(IBinder token, long[] pattern, int repeat) {
85 this(token, 0, pattern, repeat);
86 }
87
88 private Vibration(IBinder token, long millis, long[] pattern,
89 int repeat) {
90 mToken = token;
91 mTimeout = millis;
92 mStartTime = SystemClock.uptimeMillis();
93 mPattern = pattern;
94 mRepeat = repeat;
95 }
96
97 public void binderDied() {
98 synchronized (mVibrations) {
99 mVibrations.remove(this);
100 if (this == mCurrentVibration) {
101 doCancelVibrateLocked();
102 startNextVibrationLocked();
103 }
104 }
105 }
106
107 public boolean hasLongerTimeout(long millis) {
108 if (mTimeout == 0) {
109 // This is a pattern, return false to play the simple
110 // vibration.
111 return false;
112 }
113 if ((mStartTime + mTimeout)
114 < (SystemClock.uptimeMillis() + millis)) {
115 // If this vibration will end before the time passed in, let
116 // the new vibration play.
117 return false;
118 }
119 return true;
120 }
121 }
122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 HardwareService(Context context) {
124 // Reset the hardware to a default state, in case this is a runtime
125 // restart instead of a fresh boot.
126 vibratorOff();
127
The Android Open Source Project10592532009-03-18 17:39:46 -0700128 mNativePointer = init_native();
129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 mContext = context;
131 PowerManager pm = (PowerManager)context.getSystemService(
132 Context.POWER_SERVICE);
133 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
134 mWakeLock.setReferenceCounted(true);
135
Patrick Scott18dd5f02009-07-02 11:31:12 -0400136 mVibrations = new LinkedList<Vibration>();
137
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700138 mBatteryStats = BatteryStatsService.getService();
Eric Olsenf42f15c2009-10-29 16:42:03 -0700139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 IntentFilter filter = new IntentFilter();
141 filter.addAction(Intent.ACTION_SCREEN_OFF);
142 context.registerReceiver(mIntentReceiver, filter);
143 }
144
The Android Open Source Project10592532009-03-18 17:39:46 -0700145 protected void finalize() throws Throwable {
146 finalize_native(mNativePointer);
147 super.finalize();
148 }
149
Patrick Scott18dd5f02009-07-02 11:31:12 -0400150 public void vibrate(long milliseconds, IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700151 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
152 != PackageManager.PERMISSION_GRANTED) {
153 throw new SecurityException("Requires VIBRATE permission");
154 }
Patrick Scott24f10762009-08-19 09:03:56 -0400155 // We're running in the system server so we cannot crash. Check for a
156 // timeout of 0 or negative. This will ensure that a vibration has
157 // either a timeout of > 0 or a non-null pattern.
158 if (milliseconds <= 0 || (mCurrentVibration != null
159 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400160 // Ignore this vibration since the current vibration will play for
161 // longer than milliseconds.
162 return;
163 }
164 Vibration vib = new Vibration(token, milliseconds);
165 synchronized (mVibrations) {
166 removeVibrationLocked(token);
167 doCancelVibrateLocked();
168 mCurrentVibration = vib;
169 startVibrationLocked(vib);
170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 }
172
173 private boolean isAll0(long[] pattern) {
174 int N = pattern.length;
175 for (int i = 0; i < N; i++) {
176 if (pattern[i] != 0) {
177 return false;
178 }
179 }
180 return true;
181 }
182
183 public void vibratePattern(long[] pattern, int repeat, IBinder token) {
184 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
185 != PackageManager.PERMISSION_GRANTED) {
186 throw new SecurityException("Requires VIBRATE permission");
187 }
188 // so wakelock calls will succeed
189 long identity = Binder.clearCallingIdentity();
190 try {
191 if (false) {
192 String s = "";
193 int N = pattern.length;
194 for (int i=0; i<N; i++) {
195 s += " " + pattern[i];
196 }
197 Log.i(TAG, "vibrating with pattern: " + s);
198 }
199
200 // we're running in the server so we can't fail
201 if (pattern == null || pattern.length == 0
202 || isAll0(pattern)
203 || repeat >= pattern.length || token == null) {
204 return;
205 }
206
Patrick Scott18dd5f02009-07-02 11:31:12 -0400207 Vibration vib = new Vibration(token, pattern, repeat);
208 try {
209 token.linkToDeath(vib, 0);
210 } catch (RemoteException e) {
211 return;
212 }
213
214 synchronized (mVibrations) {
215 removeVibrationLocked(token);
216 doCancelVibrateLocked();
217 if (repeat >= 0) {
218 mVibrations.addFirst(vib);
219 startNextVibrationLocked();
220 } else {
221 // A negative repeat means that this pattern is not meant
222 // to repeat. Treat it like a simple vibration.
223 mCurrentVibration = vib;
224 startVibrationLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 }
227 }
228 finally {
229 Binder.restoreCallingIdentity(identity);
230 }
231 }
232
Patrick Scott18dd5f02009-07-02 11:31:12 -0400233 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 mContext.enforceCallingOrSelfPermission(
235 android.Manifest.permission.VIBRATE,
236 "cancelVibrate");
237
238 // so wakelock calls will succeed
239 long identity = Binder.clearCallingIdentity();
240 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400241 synchronized (mVibrations) {
242 final Vibration vib = removeVibrationLocked(token);
243 if (vib == mCurrentVibration) {
244 doCancelVibrateLocked();
245 startNextVibrationLocked();
246 }
247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 }
249 finally {
250 Binder.restoreCallingIdentity(identity);
251 }
252 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 public boolean getFlashlightEnabled() {
255 return Hardware.getFlashlightEnabled();
256 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 public void setFlashlightEnabled(boolean on) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700259 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 != PackageManager.PERMISSION_GRANTED &&
Eric Olsenf42f15c2009-10-29 16:42:03 -0700261 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 != PackageManager.PERMISSION_GRANTED) {
263 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
264 }
265 Hardware.setFlashlightEnabled(on);
266 }
267
268 public void enableCameraFlash(int milliseconds) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700269 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 != PackageManager.PERMISSION_GRANTED &&
Eric Olsenf42f15c2009-10-29 16:42:03 -0700271 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 != PackageManager.PERMISSION_GRANTED) {
273 throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
274 }
275 Hardware.enableCameraFlash(milliseconds);
276 }
277
The Android Open Source Project10592532009-03-18 17:39:46 -0700278 void setLightOff_UNCHECKED(int light) {
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500279 setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 }
281
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500282 void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700283 int b = brightness & 0x000000ff;
284 b = 0xff000000 | (b << 16) | (b << 8) | b;
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500285 setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
287
The Android Open Source Project10592532009-03-18 17:39:46 -0700288 void setLightColor_UNCHECKED(int light, int color) {
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500289 setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0);
The Android Open Source Project10592532009-03-18 17:39:46 -0700290 }
291
292 void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500293 setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0);
The Android Open Source Project10592532009-03-18 17:39:46 -0700294 }
295
Eric Olsenf42f15c2009-10-29 16:42:03 -0700296 public void setAttentionLight(boolean on, int color) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700297 // Not worthy of a permission. We shouldn't have a flashlight permission.
Joe Onorato95e4f702009-03-24 19:29:09 -0700298 synchronized (this) {
299 mAttentionLightOn = on;
300 mPulsing = false;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700301 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500302 LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0);
Joe Onorato95e4f702009-03-24 19:29:09 -0700303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 }
305
Joe Onorato95e4f702009-03-24 19:29:09 -0700306 public void pulseBreathingLight() {
307 synchronized (this) {
308 // HACK: Added at the last minute of cupcake -- design this better;
309 // Don't reuse the attention light -- make another one.
310 if (false) {
311 Log.d(TAG, "pulseBreathingLight mAttentionLightOn=" + mAttentionLightOn
312 + " mPulsing=" + mPulsing);
313 }
314 if (!mAttentionLightOn && !mPulsing) {
315 mPulsing = true;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700316 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500317 LIGHT_FLASH_HARDWARE, 7, 0, 0);
Joe Onorato95e4f702009-03-24 19:29:09 -0700318 mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
319 }
320 }
321 }
322
323 private Handler mH = new Handler() {
324 @Override
325 public void handleMessage(Message msg) {
326 synchronized (this) {
327 if (false) {
328 Log.d(TAG, "pulse cleanup handler firing mPulsing=" + mPulsing);
329 }
330 if (mPulsing) {
331 mPulsing = false;
332 setLight_native(mNativePointer, LIGHT_ID_ATTENTION,
333 mAttentionLightOn ? 0xffffffff : 0,
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500334 LIGHT_FLASH_NONE, 0, 0, 0);
Joe Onorato95e4f702009-03-24 19:29:09 -0700335 }
336 }
337 }
338 };
339
Patrick Scott18dd5f02009-07-02 11:31:12 -0400340 private final Runnable mVibrationRunnable = new Runnable() {
341 public void run() {
342 synchronized (mVibrations) {
343 doCancelVibrateLocked();
344 startNextVibrationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400346 }
347 };
348
349 // Lock held on mVibrations
350 private void doCancelVibrateLocked() {
351 if (mThread != null) {
352 synchronized (mThread) {
353 mThread.mDone = true;
354 mThread.notify();
355 }
356 mThread = null;
357 }
358 vibratorOff();
359 mH.removeCallbacks(mVibrationRunnable);
360 }
361
362 // Lock held on mVibrations
363 private void startNextVibrationLocked() {
364 if (mVibrations.size() <= 0) {
365 return;
366 }
367 mCurrentVibration = mVibrations.getFirst();
368 startVibrationLocked(mCurrentVibration);
369 }
370
371 // Lock held on mVibrations
372 private void startVibrationLocked(final Vibration vib) {
373 if (vib.mTimeout != 0) {
374 vibratorOn(vib.mTimeout);
375 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
376 } else {
377 // mThread better be null here. doCancelVibrate should always be
378 // called before startNextVibrationLocked or startVibrationLocked.
379 mThread = new VibrateThread(vib);
380 mThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 }
382 }
383
Patrick Scott18dd5f02009-07-02 11:31:12 -0400384 // Lock held on mVibrations
385 private Vibration removeVibrationLocked(IBinder token) {
386 ListIterator<Vibration> iter = mVibrations.listIterator(0);
387 while (iter.hasNext()) {
388 Vibration vib = iter.next();
389 if (vib.mToken == token) {
390 iter.remove();
391 return vib;
392 }
393 }
394 // We might be looking for a simple vibration which is only stored in
395 // mCurrentVibration.
396 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
397 return mCurrentVibration;
398 }
399 return null;
400 }
401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 private class VibrateThread extends Thread {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400403 final Vibration mVibration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 boolean mDone;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700405
Patrick Scott18dd5f02009-07-02 11:31:12 -0400406 VibrateThread(Vibration vib) {
407 mVibration = vib;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 mWakeLock.acquire();
409 }
410
411 private void delay(long duration) {
412 if (duration > 0) {
413 long bedtime = SystemClock.uptimeMillis();
414 do {
415 try {
416 this.wait(duration);
417 }
418 catch (InterruptedException e) {
419 }
420 if (mDone) {
421 break;
422 }
423 duration = duration
424 - SystemClock.uptimeMillis() - bedtime;
425 } while (duration > 0);
426 }
427 }
428
429 public void run() {
430 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
431 synchronized (this) {
432 int index = 0;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400433 long[] pattern = mVibration.mPattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 int len = pattern.length;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400435 int repeat = mVibration.mRepeat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 long duration = 0;
437
438 while (!mDone) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700439 // add off-time duration to any accumulated on-time duration
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 if (index < len) {
441 duration += pattern[index++];
442 }
443
444 // sleep until it is time to start the vibrator
445 delay(duration);
446 if (mDone) {
447 break;
448 }
449
450 if (index < len) {
451 // read on-time duration and start the vibrator
452 // duration is saved for delay() at top of loop
453 duration = pattern[index++];
454 if (duration > 0) {
455 HardwareService.this.vibratorOn(duration);
456 }
457 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400458 if (repeat < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 break;
460 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400461 index = repeat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 duration = 0;
463 }
464 }
465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 mWakeLock.release();
467 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400468 synchronized (mVibrations) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (mThread == this) {
470 mThread = null;
471 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400472 if (!mDone) {
473 // If this vibration finished naturally, start the next
474 // vibration.
475 mVibrations.remove(mVibration);
476 startNextVibrationLocked();
477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 }
479 }
480 };
481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
483 public void onReceive(Context context, Intent intent) {
484 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400485 synchronized (mVibrations) {
486 doCancelVibrateLocked();
487 mVibrations.clear();
488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 }
491 };
Eric Olsenf42f15c2009-10-29 16:42:03 -0700492
The Android Open Source Project10592532009-03-18 17:39:46 -0700493 private static native int init_native();
494 private static native void finalize_native(int ptr);
495
496 private static native void setLight_native(int ptr, int light, int color, int mode,
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -0500497 int onMS, int offMS, int brightnessMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700499 private final Context mContext;
500 private final PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501
Dianne Hackbornbed30e12009-03-31 14:46:20 -0700502 private final IBatteryStats mBatteryStats;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 volatile VibrateThread mThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505
The Android Open Source Project10592532009-03-18 17:39:46 -0700506 private int mNativePointer;
507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 native static void vibratorOn(long milliseconds);
509 native static void vibratorOff();
510}