eclair snapshot
This commit is contained in:
@@ -37,6 +37,9 @@ import android.os.Binder;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class HardwareService extends IHardwareService.Stub {
|
||||
private static final String TAG = "HardwareService";
|
||||
|
||||
@@ -49,10 +52,74 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
|
||||
static final int LIGHT_FLASH_NONE = 0;
|
||||
static final int LIGHT_FLASH_TIMED = 1;
|
||||
static final int LIGHT_FLASH_HARDWARE = 2;
|
||||
|
||||
/**
|
||||
* Light brightness is managed by a user setting.
|
||||
*/
|
||||
static final int BRIGHTNESS_MODE_USER = 0;
|
||||
|
||||
/**
|
||||
* Light brightness is managed by a light sensor.
|
||||
*/
|
||||
static final int BRIGHTNESS_MODE_SENSOR = 1;
|
||||
|
||||
private final LinkedList<Vibration> mVibrations;
|
||||
private Vibration mCurrentVibration;
|
||||
|
||||
private boolean mAttentionLightOn;
|
||||
private boolean mPulsing;
|
||||
|
||||
private class Vibration implements IBinder.DeathRecipient {
|
||||
private final IBinder mToken;
|
||||
private final long mTimeout;
|
||||
private final long mStartTime;
|
||||
private final long[] mPattern;
|
||||
private final int mRepeat;
|
||||
|
||||
Vibration(IBinder token, long millis) {
|
||||
this(token, millis, null, 0);
|
||||
}
|
||||
|
||||
Vibration(IBinder token, long[] pattern, int repeat) {
|
||||
this(token, 0, pattern, repeat);
|
||||
}
|
||||
|
||||
private Vibration(IBinder token, long millis, long[] pattern,
|
||||
int repeat) {
|
||||
mToken = token;
|
||||
mTimeout = millis;
|
||||
mStartTime = SystemClock.uptimeMillis();
|
||||
mPattern = pattern;
|
||||
mRepeat = repeat;
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
synchronized (mVibrations) {
|
||||
mVibrations.remove(this);
|
||||
if (this == mCurrentVibration) {
|
||||
doCancelVibrateLocked();
|
||||
startNextVibrationLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasLongerTimeout(long millis) {
|
||||
if (mTimeout == 0) {
|
||||
// This is a pattern, return false to play the simple
|
||||
// vibration.
|
||||
return false;
|
||||
}
|
||||
if ((mStartTime + mTimeout)
|
||||
< (SystemClock.uptimeMillis() + millis)) {
|
||||
// If this vibration will end before the time passed in, let
|
||||
// the new vibration play.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
HardwareService(Context context) {
|
||||
// Reset the hardware to a default state, in case this is a runtime
|
||||
// restart instead of a fresh boot.
|
||||
@@ -66,8 +133,10 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
|
||||
mWakeLock.setReferenceCounted(true);
|
||||
|
||||
mVibrations = new LinkedList<Vibration>();
|
||||
|
||||
mBatteryStats = BatteryStatsService.getService();
|
||||
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
context.registerReceiver(mIntentReceiver, filter);
|
||||
@@ -78,13 +147,27 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void vibrate(long milliseconds) {
|
||||
public void vibrate(long milliseconds, IBinder token) {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Requires VIBRATE permission");
|
||||
}
|
||||
doCancelVibrate();
|
||||
vibratorOn(milliseconds);
|
||||
// We're running in the system server so we cannot crash. Check for a
|
||||
// timeout of 0 or negative. This will ensure that a vibration has
|
||||
// either a timeout of > 0 or a non-null pattern.
|
||||
if (milliseconds <= 0 || (mCurrentVibration != null
|
||||
&& mCurrentVibration.hasLongerTimeout(milliseconds))) {
|
||||
// Ignore this vibration since the current vibration will play for
|
||||
// longer than milliseconds.
|
||||
return;
|
||||
}
|
||||
Vibration vib = new Vibration(token, milliseconds);
|
||||
synchronized (mVibrations) {
|
||||
removeVibrationLocked(token);
|
||||
doCancelVibrateLocked();
|
||||
mCurrentVibration = vib;
|
||||
startVibrationLocked(vib);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAll0(long[] pattern) {
|
||||
@@ -121,34 +204,25 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
Death death = new Death(token);
|
||||
try {
|
||||
token.linkToDeath(death, 0);
|
||||
} catch (RemoteException e) {
|
||||
return;
|
||||
Vibration vib = new Vibration(token, pattern, repeat);
|
||||
try {
|
||||
token.linkToDeath(vib, 0);
|
||||
} catch (RemoteException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mVibrations) {
|
||||
removeVibrationLocked(token);
|
||||
doCancelVibrateLocked();
|
||||
if (repeat >= 0) {
|
||||
mVibrations.addFirst(vib);
|
||||
startNextVibrationLocked();
|
||||
} else {
|
||||
// A negative repeat means that this pattern is not meant
|
||||
// to repeat. Treat it like a simple vibration.
|
||||
mCurrentVibration = vib;
|
||||
startVibrationLocked(vib);
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -156,7 +230,7 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelVibrate() {
|
||||
public void cancelVibrate(IBinder token) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.VIBRATE,
|
||||
"cancelVibrate");
|
||||
@@ -164,21 +238,27 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
// so wakelock calls will succeed
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
doCancelVibrate();
|
||||
synchronized (mVibrations) {
|
||||
final Vibration vib = removeVibrationLocked(token);
|
||||
if (vib == mCurrentVibration) {
|
||||
doCancelVibrateLocked();
|
||||
startNextVibrationLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean getFlashlightEnabled() {
|
||||
return Hardware.getFlashlightEnabled();
|
||||
}
|
||||
|
||||
|
||||
public void setFlashlightEnabled(boolean on) {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
|
||||
!= PackageManager.PERMISSION_GRANTED &&
|
||||
mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
|
||||
mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
|
||||
}
|
||||
@@ -186,60 +266,40 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
}
|
||||
|
||||
public void enableCameraFlash(int milliseconds) {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED &&
|
||||
mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
|
||||
mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission");
|
||||
}
|
||||
Hardware.enableCameraFlash(milliseconds);
|
||||
}
|
||||
|
||||
public void setBacklights(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);
|
||||
setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness);
|
||||
setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness);
|
||||
setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mBatteryStats.noteScreenBrightness(brightness);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
void setLightOff_UNCHECKED(int light) {
|
||||
setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0);
|
||||
setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0);
|
||||
}
|
||||
|
||||
void setLightBrightness_UNCHECKED(int light, int brightness) {
|
||||
void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {
|
||||
int b = brightness & 0x000000ff;
|
||||
b = 0xff000000 | (b << 16) | (b << 8) | b;
|
||||
setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0);
|
||||
setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
|
||||
}
|
||||
|
||||
void setLightColor_UNCHECKED(int light, int color) {
|
||||
setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0);
|
||||
setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0);
|
||||
}
|
||||
|
||||
void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
|
||||
setLight_native(mNativePointer, light, color, mode, onMS, offMS);
|
||||
setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0);
|
||||
}
|
||||
|
||||
public void setAttentionLight(boolean on) {
|
||||
public void setAttentionLight(boolean on, int color) {
|
||||
// Not worthy of a permission. We shouldn't have a flashlight permission.
|
||||
synchronized (this) {
|
||||
mAttentionLightOn = on;
|
||||
mPulsing = false;
|
||||
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, on ? 0xffffffff : 0,
|
||||
LIGHT_FLASH_NONE, 0, 0);
|
||||
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
|
||||
LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,8 +313,8 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
}
|
||||
if (!mAttentionLightOn && !mPulsing) {
|
||||
mPulsing = true;
|
||||
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0xff101010,
|
||||
LIGHT_FLASH_NONE, 0, 0);
|
||||
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
|
||||
LIGHT_FLASH_HARDWARE, 7, 0, 0);
|
||||
mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
|
||||
}
|
||||
}
|
||||
@@ -271,33 +331,80 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
mPulsing = false;
|
||||
setLight_native(mNativePointer, LIGHT_ID_ATTENTION,
|
||||
mAttentionLightOn ? 0xffffffff : 0,
|
||||
LIGHT_FLASH_NONE, 0, 0);
|
||||
LIGHT_FLASH_NONE, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void doCancelVibrate() {
|
||||
synchronized (this) {
|
||||
if (mThread != null) {
|
||||
synchronized (mThread) {
|
||||
mThread.mDone = true;
|
||||
mThread.notify();
|
||||
}
|
||||
mThread = null;
|
||||
private final Runnable mVibrationRunnable = new Runnable() {
|
||||
public void run() {
|
||||
synchronized (mVibrations) {
|
||||
doCancelVibrateLocked();
|
||||
startNextVibrationLocked();
|
||||
}
|
||||
vibratorOff();
|
||||
}
|
||||
};
|
||||
|
||||
// Lock held on mVibrations
|
||||
private void doCancelVibrateLocked() {
|
||||
if (mThread != null) {
|
||||
synchronized (mThread) {
|
||||
mThread.mDone = true;
|
||||
mThread.notify();
|
||||
}
|
||||
mThread = null;
|
||||
}
|
||||
vibratorOff();
|
||||
mH.removeCallbacks(mVibrationRunnable);
|
||||
}
|
||||
|
||||
// Lock held on mVibrations
|
||||
private void startNextVibrationLocked() {
|
||||
if (mVibrations.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
mCurrentVibration = mVibrations.getFirst();
|
||||
startVibrationLocked(mCurrentVibration);
|
||||
}
|
||||
|
||||
// Lock held on mVibrations
|
||||
private void startVibrationLocked(final Vibration vib) {
|
||||
if (vib.mTimeout != 0) {
|
||||
vibratorOn(vib.mTimeout);
|
||||
mH.postDelayed(mVibrationRunnable, vib.mTimeout);
|
||||
} else {
|
||||
// mThread better be null here. doCancelVibrate should always be
|
||||
// called before startNextVibrationLocked or startVibrationLocked.
|
||||
mThread = new VibrateThread(vib);
|
||||
mThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Lock held on mVibrations
|
||||
private Vibration removeVibrationLocked(IBinder token) {
|
||||
ListIterator<Vibration> iter = mVibrations.listIterator(0);
|
||||
while (iter.hasNext()) {
|
||||
Vibration vib = iter.next();
|
||||
if (vib.mToken == token) {
|
||||
iter.remove();
|
||||
return vib;
|
||||
}
|
||||
}
|
||||
// We might be looking for a simple vibration which is only stored in
|
||||
// mCurrentVibration.
|
||||
if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
|
||||
return mCurrentVibration;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class VibrateThread extends Thread {
|
||||
long[] mPattern;
|
||||
int mRepeat;
|
||||
final Vibration mVibration;
|
||||
boolean mDone;
|
||||
|
||||
VibrateThread(long[] pattern, int repeat) {
|
||||
mPattern = pattern;
|
||||
mRepeat = repeat;
|
||||
|
||||
VibrateThread(Vibration vib) {
|
||||
mVibration = vib;
|
||||
mWakeLock.acquire();
|
||||
}
|
||||
|
||||
@@ -323,12 +430,13 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
|
||||
synchronized (this) {
|
||||
int index = 0;
|
||||
long[] pattern = mPattern;
|
||||
long[] pattern = mVibration.mPattern;
|
||||
int len = pattern.length;
|
||||
int repeat = mVibration.mRepeat;
|
||||
long duration = 0;
|
||||
|
||||
while (!mDone) {
|
||||
// add off-time duration to any accumulated on-time duration
|
||||
// add off-time duration to any accumulated on-time duration
|
||||
if (index < len) {
|
||||
duration += pattern[index++];
|
||||
}
|
||||
@@ -347,68 +455,53 @@ public class HardwareService extends IHardwareService.Stub {
|
||||
HardwareService.this.vibratorOn(duration);
|
||||
}
|
||||
} else {
|
||||
if (mRepeat < 0) {
|
||||
if (repeat < 0) {
|
||||
break;
|
||||
} else {
|
||||
index = mRepeat;
|
||||
index = repeat;
|
||||
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) {
|
||||
synchronized (mVibrations) {
|
||||
if (mThread == this) {
|
||||
mThread = null;
|
||||
}
|
||||
if (!mDone) {
|
||||
// If this vibration finished naturally, start the next
|
||||
// vibration.
|
||||
mVibrations.remove(mVibration);
|
||||
startNextVibrationLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
synchronized (mVibrations) {
|
||||
doCancelVibrateLocked();
|
||||
mVibrations.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private static native int init_native();
|
||||
private static native void finalize_native(int ptr);
|
||||
|
||||
private static native void setLight_native(int ptr, int light, int color, int mode,
|
||||
int onMS, int offMS);
|
||||
int onMS, int offMS, int brightnessMode);
|
||||
|
||||
private final Context mContext;
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
|
||||
private final IBatteryStats mBatteryStats;
|
||||
|
||||
|
||||
volatile VibrateThread mThread;
|
||||
volatile Death mDeath;
|
||||
volatile IBinder mToken;
|
||||
|
||||
private int mNativePointer;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user