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