diff options
Diffstat (limited to 'services/java/com/android/server/VibratorService.java')
-rw-r--r-- | services/java/com/android/server/VibratorService.java | 613 |
1 files changed, 0 insertions, 613 deletions
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java deleted file mode 100644 index 28eb948..0000000 --- a/services/java/com/android/server/VibratorService.java +++ /dev/null @@ -1,613 +0,0 @@ -/* - * 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.app.AppOpsManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.hardware.input.InputManager; -import android.os.BatteryStats; -import android.os.Handler; -import android.os.IVibratorService; -import android.os.PowerManager; -import android.os.Process; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.Binder; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.Vibrator; -import android.os.WorkSource; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.util.Slog; -import android.view.InputDevice; - -import com.android.internal.app.IAppOpsService; -import com.android.internal.app.IBatteryStats; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.ListIterator; - -public class VibratorService extends IVibratorService.Stub - implements InputManager.InputDeviceListener { - private static final String TAG = "VibratorService"; - - private final LinkedList<Vibration> mVibrations; - private Vibration mCurrentVibration; - private final WorkSource mTmpWorkSource = new WorkSource(); - private final Handler mH = new Handler(); - - private final Context mContext; - private final PowerManager.WakeLock mWakeLock; - private final IAppOpsService mAppOpsService; - private final IBatteryStats mBatteryStatsService; - private InputManager mIm; - - volatile VibrateThread mThread; - - // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are - // to be acquired - private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>(); - private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators - private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators - - private int mCurVibUid = -1; - - native static boolean vibratorExists(); - native static void vibratorOn(long milliseconds); - native static void vibratorOff(); - - 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; - private final int mUid; - private final String mPackageName; - - Vibration(IBinder token, long millis, int uid, String packageName) { - this(token, millis, null, 0, uid, packageName); - } - - Vibration(IBinder token, long[] pattern, int repeat, int uid, String packageName) { - this(token, 0, pattern, repeat, uid, packageName); - } - - private Vibration(IBinder token, long millis, long[] pattern, - int repeat, int uid, String packageName) { - mToken = token; - mTimeout = millis; - mStartTime = SystemClock.uptimeMillis(); - mPattern = pattern; - mRepeat = repeat; - mUid = uid; - mPackageName = packageName; - } - - 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; - } - } - - VibratorService(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, "*vibrator*"); - mWakeLock.setReferenceCounted(true); - - mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE)); - mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( - BatteryStats.SERVICE_NAME)); - - mVibrations = new LinkedList<Vibration>(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - context.registerReceiver(mIntentReceiver, filter); - } - - public void systemReady() { - mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE); - - mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true, - new ContentObserver(mH) { - @Override - public void onChange(boolean selfChange) { - updateInputDeviceVibrators(); - } - }, 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(); - } - - public boolean hasVibrator() { - return doVibratorExists(); - } - - 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, String packageName, long milliseconds, 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; - } - - Vibration vib = new Vibration(token, milliseconds, uid, packageName); - - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mVibrations) { - removeVibrationLocked(token); - doCancelVibrateLocked(); - mCurrentVibration = vib; - startVibrationLocked(vib); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - 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(int uid, String packageName, long[] pattern, int repeat, - 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 (false) { - String s = ""; - int N = pattern.length; - for (int i=0; i<N; i++) { - s += " " + pattern[i]; - } - Slog.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; - } - - Vibration vib = new Vibration(token, pattern, repeat, 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); - } - } - - public void cancelVibrate(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) { - doCancelVibrateLocked(); - startNextVibrationLocked(); - } - } - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - private final Runnable mVibrationRunnable = new Runnable() { - public void run() { - synchronized (mVibrations) { - doCancelVibrateLocked(); - startNextVibrationLocked(); - } - } - }; - - // Lock held on mVibrations - private void doCancelVibrateLocked() { - if (mThread != null) { - synchronized (mThread) { - mThread.mDone = true; - mThread.notify(); - } - mThread = null; - } - doVibratorOff(); - mH.removeCallbacks(mVibrationRunnable); - reportFinishVibrationLocked(); - } - - // Lock held on mVibrations - private void startNextVibrationLocked() { - if (mVibrations.size() <= 0) { - reportFinishVibrationLocked(); - mCurrentVibration = null; - return; - } - mCurrentVibration = mVibrations.getFirst(); - startVibrationLocked(mCurrentVibration); - } - - // Lock held on mVibrations - private void startVibrationLocked(final Vibration vib) { - try { - int mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName); - 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); - 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(); - } - } - - private void reportFinishVibrationLocked() { - if (mCurrentVibration != null) { - try { - mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, - mCurrentVibration.mPackageName); - } catch (RemoteException e) { - } - mCurrentVibration = null; - } - } - - // 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(); - 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 unlinkVibration(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) { - } - - 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(); - } - } - - @Override - public void onInputDeviceAdded(int deviceId) { - updateInputDeviceVibrators(); - } - - @Override - public void onInputDeviceChanged(int deviceId) { - updateInputDeviceVibrators(); - } - - @Override - public void onInputDeviceRemoved(int deviceId) { - updateInputDeviceVibrators(); - } - - 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 doVibratorOn(long millis, int uid) { - synchronized (mInputDeviceVibrators) { - try { - mBatteryStatsService.noteVibratorOn(uid, millis); - mCurVibUid = uid; - } catch (RemoteException e) { - } - final int vibratorCount = mInputDeviceVibrators.size(); - if (vibratorCount != 0) { - for (int i = 0; i < vibratorCount; i++) { - mInputDeviceVibrators.get(i).vibrate(millis); - } - } else { - vibratorOn(millis); - } - } - } - - private void doVibratorOff() { - synchronized (mInputDeviceVibrators) { - 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 class VibrateThread extends Thread { - final Vibration mVibration; - boolean mDone; - - VibrateThread(Vibration vib) { - mVibration = vib; - mTmpWorkSource.set(vib.mUid); - mWakeLock.setWorkSource(mTmpWorkSource); - mWakeLock.acquire(); - } - - private void delay(long duration) { - if (duration > 0) { - long bedtime = duration + SystemClock.uptimeMillis(); - do { - try { - this.wait(duration); - } - catch (InterruptedException e) { - } - if (mDone) { - break; - } - duration = bedtime - SystemClock.uptimeMillis(); - } while (duration > 0); - } - } - - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); - synchronized (this) { - final long[] pattern = mVibration.mPattern; - final int len = pattern.length; - final int repeat = mVibration.mRepeat; - final int uid = mVibration.mUid; - int index = 0; - 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) { - VibratorService.this.doVibratorOn(duration, uid); - } - } else { - if (repeat < 0) { - break; - } else { - index = repeat; - duration = 0; - } - } - } - mWakeLock.release(); - } - synchronized (mVibrations) { - if (mThread == this) { - mThread = null; - } - if (!mDone) { - // If this vibration finished naturally, start the next - // vibration. - mVibrations.remove(mVibration); - unlinkVibration(mVibration); - startNextVibrationLocked(); - } - } - } - }; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - synchronized (mVibrations) { - doCancelVibrateLocked(); - - int size = mVibrations.size(); - for(int i = 0; i < size; i++) { - unlinkVibration(mVibrations.get(i)); - } - - mVibrations.clear(); - } - } - } - }; -} |