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