blob: 40456ff4d38c70da088d3d9b60102333ba78cd20 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.pm.PackageManager;
24import android.os.Hardware;
25import android.os.IHardwareService;
26import android.os.Power;
27import android.os.PowerManager;
28import android.os.RemoteException;
29import android.os.IBinder;
30import android.os.Binder;
31import android.os.SystemClock;
32import android.util.Log;
33
34public class HardwareService extends IHardwareService.Stub {
35 private static final String TAG = "HardwareService";
36
37 HardwareService(Context context) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080038 // Reset the hardware to a default state, in case this is a runtime
39 // restart instead of a fresh boot.
40 vibratorOff();
41
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070042 mContext = context;
43 PowerManager pm = (PowerManager)context.getSystemService(
44 Context.POWER_SERVICE);
45 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
46 mWakeLock.setReferenceCounted(true);
47
48 IntentFilter filter = new IntentFilter();
49 filter.addAction(Intent.ACTION_SCREEN_OFF);
50 context.registerReceiver(mIntentReceiver, filter);
51 }
52
53 public void vibrate(long milliseconds) {
54 vibratePattern(new long[] { 0, milliseconds }, -1,
55 new Binder());
56 }
57
58 private boolean isAll0(long[] pattern) {
59 int N = pattern.length;
60 for (int i = 0; i < N; i++) {
61 if (pattern[i] != 0) {
62 return false;
63 }
64 }
65 return true;
66 }
67
68 public void vibratePattern(long[] pattern, int repeat, IBinder token) {
69 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
70 != PackageManager.PERMISSION_GRANTED) {
71 throw new SecurityException("Requires VIBRATE permission");
72 }
73 // so wakelock calls will succeed
74 long identity = Binder.clearCallingIdentity();
75 try {
76 if (false) {
77 String s = "";
78 int N = pattern.length;
79 for (int i=0; i<N; i++) {
80 s += " " + pattern[i];
81 }
82 Log.i(TAG, "vibrating with pattern: " + s);
83 }
84
85 // we're running in the server so we can't fail
86 if (pattern == null || pattern.length == 0
87 || isAll0(pattern)
88 || repeat >= pattern.length || token == null) {
89 return;
90 }
91
92 synchronized (this) {
93 Death death = new Death(token);
94 try {
95 token.linkToDeath(death, 0);
96 } catch (RemoteException e) {
97 return;
98 }
99
100 Thread oldThread = mThread;
101
102 if (oldThread != null) {
103 // stop the old one
104 synchronized (mThread) {
105 mThread.mDone = true;
106 mThread.notify();
107 }
108 }
109
110 if (mDeath != null) {
111 mToken.unlinkToDeath(mDeath, 0);
112 }
113
114 mDeath = death;
115 mToken = token;
116
117 // start the new thread
118 mThread = new VibrateThread(pattern, repeat);
119 mThread.start();
120 }
121 }
122 finally {
123 Binder.restoreCallingIdentity(identity);
124 }
125 }
126
127 public void cancelVibrate() {
128 mContext.enforceCallingOrSelfPermission(
129 android.Manifest.permission.VIBRATE,
130 "cancelVibrate");
131
132 // so wakelock calls will succeed
133 long identity = Binder.clearCallingIdentity();
134 try {
135 doCancelVibrate();
136 }
137 finally {
138 Binder.restoreCallingIdentity(identity);
139 }
140 }
141
142 public boolean getFlashlightEnabled() {
143 return Hardware.getFlashlightEnabled();
144 }
145
146 public void setFlashlightEnabled(boolean on) {
147 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
148 != PackageManager.PERMISSION_GRANTED &&
149 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
150 != PackageManager.PERMISSION_GRANTED) {
151 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
152 }
153 Hardware.setFlashlightEnabled(on);
154 }
155
156 public void enableCameraFlash(int milliseconds) {
157 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
158 != PackageManager.PERMISSION_GRANTED &&
159 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
160 != PackageManager.PERMISSION_GRANTED) {
161 throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
162 }
163 Hardware.enableCameraFlash(milliseconds);
164 }
165
166 public void setScreenBacklight(int brightness) {
167 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
168 != PackageManager.PERMISSION_GRANTED) {
169 throw new SecurityException("Requires HARDWARE_TEST permission");
170 }
171 // Don't let applications turn the screen all the way off
172 brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
173 Hardware.setScreenBacklight(brightness);
174 }
175
176 public void setKeyboardBacklight(boolean on) {
177 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
178 != PackageManager.PERMISSION_GRANTED) {
179 throw new SecurityException("Requires HARDWARE_TEST permission");
180 }
181 Hardware.setKeyboardBacklight(on);
182 }
183
184 public void setButtonBacklight(boolean on) {
185 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
186 != PackageManager.PERMISSION_GRANTED) {
187 throw new SecurityException("Requires HARDWARE_TEST permission");
188 }
189 Hardware.setButtonBacklight(on);
190 }
191
192 public void setLedState(int colorARGB, int onMS, int offMS) {
193 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
194 != PackageManager.PERMISSION_GRANTED) {
195 throw new SecurityException("Requires HARDWARE_TEST permission");
196 }
197 Hardware.setLedState(colorARGB, onMS, offMS);
198 }
199
200 private void doCancelVibrate() {
201 synchronized (this) {
202 if (mThread != null) {
203 synchronized (mThread) {
204 mThread.mDone = true;
205 mThread.notify();
206 }
207 mThread = null;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800208 vibratorOff();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700209 }
210 }
211 }
212
213 private class VibrateThread extends Thread {
214 long[] mPattern;
215 int mRepeat;
216 boolean mDone;
217
218 VibrateThread(long[] pattern, int repeat) {
219 mPattern = pattern;
220 mRepeat = repeat;
221 mWakeLock.acquire();
222 }
223
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800224 private void delay(long duration) {
225 if (duration > 0) {
226 long bedtime = SystemClock.uptimeMillis();
227 do {
228 try {
229 this.wait(duration);
230 }
231 catch (InterruptedException e) {
232 }
233 if (mDone) {
234 break;
235 }
236 duration = duration
237 - SystemClock.uptimeMillis() - bedtime;
238 } while (duration > 0);
239 }
240 }
241
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700242 public void run() {
243 synchronized (this) {
244 int index = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700245 long[] pattern = mPattern;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700246 int len = pattern.length;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800247 long duration = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700248
249 while (!mDone) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800250 // add off-time duration to any accumulated on-time duration
251 if (index < len) {
252 duration += pattern[index++];
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700253 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800254
255 // sleep until it is time to start the vibrator
256 delay(duration);
257 if (mDone) {
258 break;
259 }
260
261 if (index < len) {
262 // read on-time duration and start the vibrator
263 // duration is saved for delay() at top of loop
264 duration = pattern[index++];
265 if (duration > 0) {
266 HardwareService.this.vibratorOn(duration);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700267 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800268 } else {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700269 if (mRepeat < 0) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700270 break;
271 } else {
272 index = mRepeat;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800273 duration = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700274 }
275 }
276 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800277 if (mDone) {
278 // make sure vibrator is off if we were cancelled.
279 // otherwise, it will turn off automatically
280 // when the last timeout expires.
281 HardwareService.this.vibratorOff();
282 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700283 mWakeLock.release();
284 }
285 synchronized (HardwareService.this) {
286 if (mThread == this) {
287 mThread = null;
288 }
289 }
290 }
291 };
292
293 private class Death implements IBinder.DeathRecipient {
294 IBinder mMe;
295
296 Death(IBinder me) {
297 mMe = me;
298 }
299
300 public void binderDied() {
301 synchronized (HardwareService.this) {
302 if (mMe == mToken) {
303 doCancelVibrate();
304 }
305 }
306 }
307 }
308
309 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
310 public void onReceive(Context context, Intent intent) {
311 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
312 doCancelVibrate();
313 }
314 }
315 };
316
317 private Context mContext;
318 private PowerManager.WakeLock mWakeLock;
319
320 volatile VibrateThread mThread;
321 volatile Death mDeath;
322 volatile IBinder mToken;
323
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800324 native static void vibratorOn(long milliseconds);
325 native static void vibratorOff();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700326}