summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/HardwareService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/HardwareService.java')
-rwxr-xr-xservices/java/com/android/server/HardwareService.java328
1 files changed, 328 insertions, 0 deletions
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
new file mode 100755
index 0000000..2131ffd
--- /dev/null
+++ b/services/java/com/android/server/HardwareService.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Hardware;
+import android.os.IHardwareService;
+import android.os.Power;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Binder;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class HardwareService extends IHardwareService.Stub {
+ private static final String TAG = "HardwareService";
+
+ HardwareService(Context context) {
+ // Reset the hardware to a default state, in case this is a runtime
+ // restart instead of a fresh boot.
+ vibratorOff();
+
+ mContext = context;
+ PowerManager pm = (PowerManager)context.getSystemService(
+ Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock.setReferenceCounted(true);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ context.registerReceiver(mIntentReceiver, filter);
+ }
+
+ public void vibrate(long milliseconds) {
+ vibratePattern(new long[] { 0, milliseconds }, -1,
+ new Binder());
+ }
+
+ private boolean isAll0(long[] pattern) {
+ int N = pattern.length;
+ for (int i = 0; i < N; i++) {
+ if (pattern[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void vibratePattern(long[] pattern, int repeat, IBinder token) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires VIBRATE permission");
+ }
+ // so wakelock calls will succeed
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (false) {
+ String s = "";
+ int N = pattern.length;
+ for (int i=0; i<N; i++) {
+ s += " " + pattern[i];
+ }
+ Log.i(TAG, "vibrating with pattern: " + s);
+ }
+
+ // we're running in the server so we can't fail
+ if (pattern == null || pattern.length == 0
+ || isAll0(pattern)
+ || repeat >= pattern.length || token == null) {
+ return;
+ }
+
+ synchronized (this) {
+ Death death = new Death(token);
+ try {
+ token.linkToDeath(death, 0);
+ } catch (RemoteException e) {
+ return;
+ }
+
+ Thread oldThread = mThread;
+
+ if (oldThread != null) {
+ // stop the old one
+ synchronized (mThread) {
+ mThread.mDone = true;
+ mThread.notify();
+ }
+ }
+
+ if (mDeath != null) {
+ mToken.unlinkToDeath(mDeath, 0);
+ }
+
+ mDeath = death;
+ mToken = token;
+
+ // start the new thread
+ mThread = new VibrateThread(pattern, repeat);
+ mThread.start();
+ }
+ }
+ finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public void cancelVibrate() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.VIBRATE,
+ "cancelVibrate");
+
+ // so wakelock calls will succeed
+ long identity = Binder.clearCallingIdentity();
+ try {
+ doCancelVibrate();
+ }
+ finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public boolean getFlashlightEnabled() {
+ return Hardware.getFlashlightEnabled();
+ }
+
+ public void setFlashlightEnabled(boolean on) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
+ != PackageManager.PERMISSION_GRANTED &&
+ mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
+ }
+ Hardware.setFlashlightEnabled(on);
+ }
+
+ public void enableCameraFlash(int milliseconds) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED &&
+ mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
+ }
+ Hardware.enableCameraFlash(milliseconds);
+ }
+
+ public void setScreenBacklight(int brightness) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires HARDWARE_TEST permission");
+ }
+ // Don't let applications turn the screen all the way off
+ brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
+ Hardware.setScreenBacklight(brightness);
+ }
+
+ public void setKeyboardBacklight(boolean on) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires HARDWARE_TEST permission");
+ }
+ Hardware.setKeyboardBacklight(on);
+ }
+
+ public void setButtonBacklight(boolean on) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires HARDWARE_TEST permission");
+ }
+ Hardware.setButtonBacklight(on);
+ }
+
+ public void setLedState(int colorARGB, int onMS, int offMS) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires HARDWARE_TEST permission");
+ }
+ Hardware.setLedState(colorARGB, onMS, offMS);
+ }
+
+ private void doCancelVibrate() {
+ synchronized (this) {
+ if (mThread != null) {
+ synchronized (mThread) {
+ mThread.mDone = true;
+ mThread.notify();
+ }
+ mThread = null;
+ vibratorOff();
+ }
+ }
+ }
+
+ private class VibrateThread extends Thread {
+ long[] mPattern;
+ int mRepeat;
+ boolean mDone;
+
+ VibrateThread(long[] pattern, int repeat) {
+ mPattern = pattern;
+ mRepeat = repeat;
+ mWakeLock.acquire();
+ }
+
+ private void delay(long duration) {
+ if (duration > 0) {
+ long bedtime = SystemClock.uptimeMillis();
+ do {
+ try {
+ this.wait(duration);
+ }
+ catch (InterruptedException e) {
+ }
+ if (mDone) {
+ break;
+ }
+ duration = duration
+ - SystemClock.uptimeMillis() - bedtime;
+ } while (duration > 0);
+ }
+ }
+
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+ synchronized (this) {
+ int index = 0;
+ long[] pattern = mPattern;
+ int len = pattern.length;
+ long duration = 0;
+
+ while (!mDone) {
+ // add off-time duration to any accumulated on-time duration
+ if (index < len) {
+ duration += pattern[index++];
+ }
+
+ // sleep until it is time to start the vibrator
+ delay(duration);
+ if (mDone) {
+ break;
+ }
+
+ if (index < len) {
+ // read on-time duration and start the vibrator
+ // duration is saved for delay() at top of loop
+ duration = pattern[index++];
+ if (duration > 0) {
+ HardwareService.this.vibratorOn(duration);
+ }
+ } else {
+ if (mRepeat < 0) {
+ break;
+ } else {
+ index = mRepeat;
+ duration = 0;
+ }
+ }
+ }
+ if (mDone) {
+ // make sure vibrator is off if we were cancelled.
+ // otherwise, it will turn off automatically
+ // when the last timeout expires.
+ HardwareService.this.vibratorOff();
+ }
+ mWakeLock.release();
+ }
+ synchronized (HardwareService.this) {
+ if (mThread == this) {
+ mThread = null;
+ }
+ }
+ }
+ };
+
+ private class Death implements IBinder.DeathRecipient {
+ IBinder mMe;
+
+ Death(IBinder me) {
+ mMe = me;
+ }
+
+ public void binderDied() {
+ synchronized (HardwareService.this) {
+ if (mMe == mToken) {
+ doCancelVibrate();
+ }
+ }
+ }
+ }
+
+ BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+ doCancelVibrate();
+ }
+ }
+ };
+
+ private Context mContext;
+ private PowerManager.WakeLock mWakeLock;
+
+ volatile VibrateThread mThread;
+ volatile Death mDeath;
+ volatile IBinder mToken;
+
+ native static void vibratorOn(long milliseconds);
+ native static void vibratorOff();
+}