• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server;
18 
19 import com.android.internal.app.IBatteryStats;
20 import com.android.server.am.BatteryStatsService;
21 
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.PackageManager;
27 import android.os.Handler;
28 import android.os.Hardware;
29 import android.os.IHardwareService;
30 import android.os.Message;
31 import android.os.Power;
32 import android.os.PowerManager;
33 import android.os.Process;
34 import android.os.RemoteException;
35 import android.os.IBinder;
36 import android.os.Binder;
37 import android.os.SystemClock;
38 import android.util.Log;
39 
40 import java.util.LinkedList;
41 import java.util.ListIterator;
42 
43 public class HardwareService extends IHardwareService.Stub {
44     private static final String TAG = "HardwareService";
45 
46     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;
55     static final int LIGHT_FLASH_HARDWARE = 2;
56 
57     /**
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 
67     private final LinkedList<Vibration> mVibrations;
68     private Vibration mCurrentVibration;
69 
70     private boolean mAttentionLightOn;
71     private boolean mPulsing;
72 
73     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 
Vibration(IBinder token, long millis)80         Vibration(IBinder token, long millis) {
81             this(token, millis, null, 0);
82         }
83 
Vibration(IBinder token, long[] pattern, int repeat)84         Vibration(IBinder token, long[] pattern, int repeat) {
85             this(token, 0, pattern, repeat);
86         }
87 
Vibration(IBinder token, long millis, long[] pattern, int repeat)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 
binderDied()97         public void binderDied() {
98             synchronized (mVibrations) {
99                 mVibrations.remove(this);
100                 if (this == mCurrentVibration) {
101                     doCancelVibrateLocked();
102                     startNextVibrationLocked();
103                 }
104             }
105         }
106 
hasLongerTimeout(long millis)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 
HardwareService(Context context)123     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 
128         mNativePointer = init_native();
129 
130         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 
136         mVibrations = new LinkedList<Vibration>();
137 
138         mBatteryStats = BatteryStatsService.getService();
139 
140         IntentFilter filter = new IntentFilter();
141         filter.addAction(Intent.ACTION_SCREEN_OFF);
142         context.registerReceiver(mIntentReceiver, filter);
143     }
144 
finalize()145     protected void finalize() throws Throwable {
146         finalize_native(mNativePointer);
147         super.finalize();
148     }
149 
vibrate(long milliseconds, IBinder token)150     public void vibrate(long milliseconds, IBinder token) {
151         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
152                 != PackageManager.PERMISSION_GRANTED) {
153             throw new SecurityException("Requires VIBRATE permission");
154         }
155         // 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))) {
160             // 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         }
171     }
172 
isAll0(long[] pattern)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 
vibratePattern(long[] pattern, int repeat, IBinder token)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 
207             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);
225                 }
226             }
227         }
228         finally {
229             Binder.restoreCallingIdentity(identity);
230         }
231     }
232 
cancelVibrate(IBinder token)233     public void cancelVibrate(IBinder token) {
234         mContext.enforceCallingOrSelfPermission(
235                 android.Manifest.permission.VIBRATE,
236                 "cancelVibrate");
237 
238         // so wakelock calls will succeed
239         long identity = Binder.clearCallingIdentity();
240         try {
241             synchronized (mVibrations) {
242                 final Vibration vib = removeVibrationLocked(token);
243                 if (vib == mCurrentVibration) {
244                     doCancelVibrateLocked();
245                     startNextVibrationLocked();
246                 }
247             }
248         }
249         finally {
250             Binder.restoreCallingIdentity(identity);
251         }
252     }
253 
getFlashlightEnabled()254     public boolean getFlashlightEnabled() {
255         return Hardware.getFlashlightEnabled();
256     }
257 
setFlashlightEnabled(boolean on)258     public void setFlashlightEnabled(boolean on) {
259         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
260                 != PackageManager.PERMISSION_GRANTED &&
261                 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
262                 != PackageManager.PERMISSION_GRANTED) {
263             throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
264         }
265         Hardware.setFlashlightEnabled(on);
266     }
267 
enableCameraFlash(int milliseconds)268     public void enableCameraFlash(int milliseconds) {
269         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
270                 != PackageManager.PERMISSION_GRANTED &&
271                 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
272                 != PackageManager.PERMISSION_GRANTED) {
273             throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
274         }
275         Hardware.enableCameraFlash(milliseconds);
276     }
277 
setLightOff_UNCHECKED(int light)278     void setLightOff_UNCHECKED(int light) {
279         setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0);
280     }
281 
setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode)282     void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {
283         int b = brightness & 0x000000ff;
284         b = 0xff000000 | (b << 16) | (b << 8) | b;
285         setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
286     }
287 
setLightColor_UNCHECKED(int light, int color)288     void setLightColor_UNCHECKED(int light, int color) {
289         setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0);
290     }
291 
setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS)292     void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
293         setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0);
294     }
295 
setAttentionLight(boolean on, int color)296     public void setAttentionLight(boolean on, int color) {
297         // Not worthy of a permission.  We shouldn't have a flashlight permission.
298         synchronized (this) {
299             mAttentionLightOn = on;
300             mPulsing = false;
301             setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
302                     LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0);
303         }
304     }
305 
pulseBreathingLight()306     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;
316                 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
317                         LIGHT_FLASH_HARDWARE, 7, 0, 0);
318                 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,
334                             LIGHT_FLASH_NONE, 0, 0, 0);
335                 }
336             }
337         }
338     };
339 
340     private final Runnable mVibrationRunnable = new Runnable() {
341         public void run() {
342             synchronized (mVibrations) {
343                 doCancelVibrateLocked();
344                 startNextVibrationLocked();
345             }
346         }
347     };
348 
349     // Lock held on mVibrations
doCancelVibrateLocked()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
startNextVibrationLocked()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
startVibrationLocked(final Vibration vib)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();
381         }
382     }
383 
384     // Lock held on mVibrations
removeVibrationLocked(IBinder token)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 
402     private class VibrateThread extends Thread {
403         final Vibration mVibration;
404         boolean mDone;
405 
VibrateThread(Vibration vib)406         VibrateThread(Vibration vib) {
407             mVibration = vib;
408             mWakeLock.acquire();
409         }
410 
delay(long duration)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 
run()429         public void run() {
430             Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
431             synchronized (this) {
432                 int index = 0;
433                 long[] pattern = mVibration.mPattern;
434                 int len = pattern.length;
435                 int repeat = mVibration.mRepeat;
436                 long duration = 0;
437 
438                 while (!mDone) {
439                     // add off-time duration to any accumulated on-time duration
440                     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 {
458                         if (repeat < 0) {
459                             break;
460                         } else {
461                             index = repeat;
462                             duration = 0;
463                         }
464                     }
465                 }
466                 mWakeLock.release();
467             }
468             synchronized (mVibrations) {
469                 if (mThread == this) {
470                     mThread = null;
471                 }
472                 if (!mDone) {
473                     // If this vibration finished naturally, start the next
474                     // vibration.
475                     mVibrations.remove(mVibration);
476                     startNextVibrationLocked();
477                 }
478             }
479         }
480     };
481 
482     BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
483         public void onReceive(Context context, Intent intent) {
484             if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
485                 synchronized (mVibrations) {
486                     doCancelVibrateLocked();
487                     mVibrations.clear();
488                 }
489             }
490         }
491     };
492 
init_native()493     private static native int init_native();
finalize_native(int ptr)494     private static native void finalize_native(int ptr);
495 
setLight_native(int ptr, int light, int color, int mode, int onMS, int offMS, int brightnessMode)496     private static native void setLight_native(int ptr, int light, int color, int mode,
497             int onMS, int offMS, int brightnessMode);
498 
499     private final Context mContext;
500     private final PowerManager.WakeLock mWakeLock;
501 
502     private final IBatteryStats mBatteryStats;
503 
504     volatile VibrateThread mThread;
505 
506     private int mNativePointer;
507 
vibratorOn(long milliseconds)508     native static void vibratorOn(long milliseconds);
vibratorOff()509     native static void vibratorOff();
510 }
511