Fields Summary |
---|
private static final String | TAG |
private static final boolean | DEBUG |
private final LinkedList | mVibrations |
private Vibration | mCurrentVibration |
private final android.os.WorkSource | mTmpWorkSource |
private final android.os.Handler | mH |
private final android.content.Context | mContext |
private final PowerManager.WakeLock | mWakeLock |
private final com.android.internal.app.IAppOpsService | mAppOpsService |
private final com.android.internal.app.IBatteryStats | mBatteryStatsService |
private android.os.PowerManagerInternal | mPowerManagerInternal |
private android.hardware.input.InputManager | mIm |
volatile VibrateThread | mThread |
private final ArrayList | mInputDeviceVibrators |
private boolean | mVibrateInputDevicesSetting |
private boolean | mInputDeviceListenerRegistered |
private int | mCurVibUid |
private boolean | mLowPowerMode |
private SettingsObserver | mSettingObserver |
private final Runnable | mVibrationRunnable |
android.content.BroadcastReceiver | mIntentReceiver |
Methods Summary |
---|
public void | cancelVibrate(android.os.IBinder token)
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.VIBRATE,
"cancelVibrate");
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
synchronized (mVibrations) {
final Vibration vib = removeVibrationLocked(token);
if (vib == mCurrentVibration) {
if (DEBUG) {
Slog.d(TAG, "Canceling vibration.");
}
doCancelVibrateLocked();
startNextVibrationLocked();
}
}
}
finally {
Binder.restoreCallingIdentity(identity);
}
|
private void | doCancelVibrateLocked()
// Lock held on mVibrations
if (mThread != null) {
synchronized (mThread) {
mThread.mDone = true;
mThread.notify();
}
mThread = null;
}
doVibratorOff();
mH.removeCallbacks(mVibrationRunnable);
reportFinishVibrationLocked();
|
private boolean | doVibratorExists()
// For now, we choose to ignore the presence of input devices that have vibrators
// when reporting whether the device has a vibrator. Applications often use this
// information to decide whether to enable certain features so they expect the
// result of hasVibrator() to be constant. For now, just report whether
// the device has a built-in vibrator.
//synchronized (mInputDeviceVibrators) {
// return !mInputDeviceVibrators.isEmpty() || vibratorExists();
//}
return vibratorExists();
|
private void | doVibratorOff()
synchronized (mInputDeviceVibrators) {
if (DEBUG) {
Slog.d(TAG, "Turning vibrator off.");
}
if (mCurVibUid >= 0) {
try {
mBatteryStatsService.noteVibratorOff(mCurVibUid);
} catch (RemoteException e) {
}
mCurVibUid = -1;
}
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
for (int i = 0; i < vibratorCount; i++) {
mInputDeviceVibrators.get(i).cancel();
}
} else {
vibratorOff();
}
}
|
private void | doVibratorOn(long millis, int uid, int usageHint)
synchronized (mInputDeviceVibrators) {
if (DEBUG) {
Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
}
try {
mBatteryStatsService.noteVibratorOn(uid, millis);
mCurVibUid = uid;
} catch (RemoteException e) {
}
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
.build();
for (int i = 0; i < vibratorCount; i++) {
mInputDeviceVibrators.get(i).vibrate(millis, attributes);
}
} else {
vibratorOn(millis);
}
}
|
public boolean | hasVibrator()
return doVibratorExists();
|
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 | onInputDeviceAdded(int deviceId)
updateInputDeviceVibrators();
|
public void | onInputDeviceChanged(int deviceId)
updateInputDeviceVibrators();
|
public void | onInputDeviceRemoved(int deviceId)
updateInputDeviceVibrators();
|
private com.android.server.VibratorService$Vibration | removeVibrationLocked(android.os.IBinder token)
ListIterator<Vibration> iter = mVibrations.listIterator(0);
while (iter.hasNext()) {
Vibration vib = iter.next();
if (vib.mToken == token) {
iter.remove();
unlinkVibration(vib);
return vib;
}
}
// We might be looking for a simple vibration which is only stored in
// mCurrentVibration.
if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
unlinkVibration(mCurrentVibration);
return mCurrentVibration;
}
return null;
|
private void | reportFinishVibrationLocked()
if (mCurrentVibration != null) {
try {
mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
mCurrentVibration.mOpPkg);
} catch (RemoteException e) {
}
mCurrentVibration = null;
}
|
private void | startNextVibrationLocked()
if (mVibrations.size() <= 0) {
reportFinishVibrationLocked();
mCurrentVibration = null;
return;
}
mCurrentVibration = mVibrations.getFirst();
startVibrationLocked(mCurrentVibration);
|
private void | startVibrationLocked(com.android.server.VibratorService$Vibration vib)
try {
if (mLowPowerMode
&& vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
return;
}
int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
vib.mUsageHint, vib.mUid, vib.mOpPkg);
if (mode == AppOpsManager.MODE_ALLOWED) {
mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
}
if (mode != AppOpsManager.MODE_ALLOWED) {
if (mode == AppOpsManager.MODE_ERRORED) {
Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
}
mH.post(mVibrationRunnable);
return;
}
} catch (RemoteException e) {
}
if (vib.mTimeout != 0) {
doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
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();
}
|
public void | systemReady()
mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
mSettingObserver = new SettingsObserver(mH);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public void onLowPowerModeChanged(boolean enabled) {
updateInputDeviceVibrators();
}
});
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
true, mSettingObserver, UserHandle.USER_ALL);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateInputDeviceVibrators();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
updateInputDeviceVibrators();
|
private void | unlinkVibration(com.android.server.VibratorService$Vibration vib)
if (vib.mPattern != null) {
// If Vibration object has a pattern,
// the Vibration object has also been linkedToDeath.
vib.mToken.unlinkToDeath(vib, 0);
}
|
private void | updateInputDeviceVibrators()
synchronized (mVibrations) {
doCancelVibrateLocked();
synchronized (mInputDeviceVibrators) {
mVibrateInputDevicesSetting = false;
try {
mVibrateInputDevicesSetting = Settings.System.getIntForUser(
mContext.getContentResolver(),
Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
} catch (SettingNotFoundException snfe) {
}
mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
if (mVibrateInputDevicesSetting) {
if (!mInputDeviceListenerRegistered) {
mInputDeviceListenerRegistered = true;
mIm.registerInputDeviceListener(this, mH);
}
} else {
if (mInputDeviceListenerRegistered) {
mInputDeviceListenerRegistered = false;
mIm.unregisterInputDeviceListener(this);
}
}
mInputDeviceVibrators.clear();
if (mVibrateInputDevicesSetting) {
int[] ids = mIm.getInputDeviceIds();
for (int i = 0; i < ids.length; i++) {
InputDevice device = mIm.getInputDevice(ids[i]);
Vibrator vibrator = device.getVibrator();
if (vibrator.hasVibrator()) {
mInputDeviceVibrators.add(vibrator);
}
}
}
}
startNextVibrationLocked();
}
|
private void | verifyIncomingUid(int uid)
if (uid == Binder.getCallingUid()) {
return;
}
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
|
public void | vibrate(int uid, java.lang.String opPkg, long milliseconds, int usageHint, android.os.IBinder token)
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
verifyIncomingUid(uid);
// 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;
}
if (DEBUG) {
Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
}
Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mVibrations) {
removeVibrationLocked(token);
doCancelVibrateLocked();
mCurrentVibration = vib;
startVibrationLocked(vib);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
|
public void | vibratePattern(int uid, java.lang.String packageName, long[] pattern, int repeat, int usageHint, android.os.IBinder token)
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
verifyIncomingUid(uid);
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
if (DEBUG) {
String s = "";
int N = pattern.length;
for (int i=0; i<N; i++) {
s += " " + pattern[i];
}
Slog.d(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;
}
Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
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);
}
}
}
finally {
Binder.restoreCallingIdentity(identity);
}
|
static native boolean | vibratorExists()
|
static native void | vibratorOff()
|
static native void | vibratorOn(long milliseconds)
|