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 17package com.android.server; 18 19import android.content.BroadcastReceiver; 20import android.content.Context; 21import android.content.Intent; 22import android.content.IntentFilter; 23import android.content.pm.PackageManager; 24import android.database.ContentObserver; 25import android.hardware.input.InputManager; 26import android.os.Handler; 27import android.os.IVibratorService; 28import android.os.PowerManager; 29import android.os.Process; 30import android.os.RemoteException; 31import android.os.IBinder; 32import android.os.Binder; 33import android.os.SystemClock; 34import android.os.UserHandle; 35import android.os.Vibrator; 36import android.os.WorkSource; 37import android.provider.Settings; 38import android.provider.Settings.SettingNotFoundException; 39import android.util.Slog; 40import android.view.InputDevice; 41 42import java.util.ArrayList; 43import java.util.LinkedList; 44import java.util.ListIterator; 45 46public class VibratorService extends IVibratorService.Stub 47 implements InputManager.InputDeviceListener { 48 private static final String TAG = "VibratorService"; 49 50 private final LinkedList<Vibration> mVibrations; 51 private Vibration mCurrentVibration; 52 private final WorkSource mTmpWorkSource = new WorkSource(); 53 private final Handler mH = new Handler(); 54 55 private final Context mContext; 56 private final PowerManager.WakeLock mWakeLock; 57 private InputManager mIm; 58 59 volatile VibrateThread mThread; 60 61 // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are 62 // to be acquired 63 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>(); 64 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators 65 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators 66 67 native static boolean vibratorExists(); 68 native static void vibratorOn(long milliseconds); 69 native static void vibratorOff(); 70 71 private class Vibration implements IBinder.DeathRecipient { 72 private final IBinder mToken; 73 private final long mTimeout; 74 private final long mStartTime; 75 private final long[] mPattern; 76 private final int mRepeat; 77 private final int mUid; 78 79 Vibration(IBinder token, long millis, int uid) { 80 this(token, millis, null, 0, uid); 81 } 82 83 Vibration(IBinder token, long[] pattern, int repeat, int uid) { 84 this(token, 0, pattern, repeat, uid); 85 } 86 87 private Vibration(IBinder token, long millis, long[] pattern, 88 int repeat, int uid) { 89 mToken = token; 90 mTimeout = millis; 91 mStartTime = SystemClock.uptimeMillis(); 92 mPattern = pattern; 93 mRepeat = repeat; 94 mUid = uid; 95 } 96 97 public void binderDied() { 98 synchronized (mVibrations) { 99 mVibrations.remove(this); 100 if (this == mCurrentVibration) { 101 doCancelVibrateLocked(); 102 startNextVibrationLocked(); 103 } 104 } 105 } 106 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 123 VibratorService(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 mContext = context; 129 PowerManager pm = (PowerManager)context.getSystemService( 130 Context.POWER_SERVICE); 131 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); 132 mWakeLock.setReferenceCounted(true); 133 134 mVibrations = new LinkedList<Vibration>(); 135 136 IntentFilter filter = new IntentFilter(); 137 filter.addAction(Intent.ACTION_SCREEN_OFF); 138 context.registerReceiver(mIntentReceiver, filter); 139 } 140 141 public void systemReady() { 142 mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE); 143 144 mContext.getContentResolver().registerContentObserver( 145 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true, 146 new ContentObserver(mH) { 147 @Override 148 public void onChange(boolean selfChange) { 149 updateInputDeviceVibrators(); 150 } 151 }, UserHandle.USER_ALL); 152 153 mContext.registerReceiver(new BroadcastReceiver() { 154 @Override 155 public void onReceive(Context context, Intent intent) { 156 updateInputDeviceVibrators(); 157 } 158 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH); 159 160 updateInputDeviceVibrators(); 161 } 162 163 public boolean hasVibrator() { 164 return doVibratorExists(); 165 } 166 167 public void vibrate(long milliseconds, IBinder token) { 168 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 169 != PackageManager.PERMISSION_GRANTED) { 170 throw new SecurityException("Requires VIBRATE permission"); 171 } 172 int uid = Binder.getCallingUid(); 173 // We're running in the system server so we cannot crash. Check for a 174 // timeout of 0 or negative. This will ensure that a vibration has 175 // either a timeout of > 0 or a non-null pattern. 176 if (milliseconds <= 0 || (mCurrentVibration != null 177 && mCurrentVibration.hasLongerTimeout(milliseconds))) { 178 // Ignore this vibration since the current vibration will play for 179 // longer than milliseconds. 180 return; 181 } 182 183 Vibration vib = new Vibration(token, milliseconds, uid); 184 synchronized (mVibrations) { 185 removeVibrationLocked(token); 186 doCancelVibrateLocked(); 187 mCurrentVibration = vib; 188 startVibrationLocked(vib); 189 } 190 } 191 192 private boolean isAll0(long[] pattern) { 193 int N = pattern.length; 194 for (int i = 0; i < N; i++) { 195 if (pattern[i] != 0) { 196 return false; 197 } 198 } 199 return true; 200 } 201 202 public void vibratePattern(long[] pattern, int repeat, IBinder token) { 203 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 204 != PackageManager.PERMISSION_GRANTED) { 205 throw new SecurityException("Requires VIBRATE permission"); 206 } 207 int uid = Binder.getCallingUid(); 208 // so wakelock calls will succeed 209 long identity = Binder.clearCallingIdentity(); 210 try { 211 if (false) { 212 String s = ""; 213 int N = pattern.length; 214 for (int i=0; i<N; i++) { 215 s += " " + pattern[i]; 216 } 217 Slog.i(TAG, "vibrating with pattern: " + s); 218 } 219 220 // we're running in the server so we can't fail 221 if (pattern == null || pattern.length == 0 222 || isAll0(pattern) 223 || repeat >= pattern.length || token == null) { 224 return; 225 } 226 227 Vibration vib = new Vibration(token, pattern, repeat, uid); 228 try { 229 token.linkToDeath(vib, 0); 230 } catch (RemoteException e) { 231 return; 232 } 233 234 synchronized (mVibrations) { 235 removeVibrationLocked(token); 236 doCancelVibrateLocked(); 237 if (repeat >= 0) { 238 mVibrations.addFirst(vib); 239 startNextVibrationLocked(); 240 } else { 241 // A negative repeat means that this pattern is not meant 242 // to repeat. Treat it like a simple vibration. 243 mCurrentVibration = vib; 244 startVibrationLocked(vib); 245 } 246 } 247 } 248 finally { 249 Binder.restoreCallingIdentity(identity); 250 } 251 } 252 253 public void cancelVibrate(IBinder token) { 254 mContext.enforceCallingOrSelfPermission( 255 android.Manifest.permission.VIBRATE, 256 "cancelVibrate"); 257 258 // so wakelock calls will succeed 259 long identity = Binder.clearCallingIdentity(); 260 try { 261 synchronized (mVibrations) { 262 final Vibration vib = removeVibrationLocked(token); 263 if (vib == mCurrentVibration) { 264 doCancelVibrateLocked(); 265 startNextVibrationLocked(); 266 } 267 } 268 } 269 finally { 270 Binder.restoreCallingIdentity(identity); 271 } 272 } 273 274 private final Runnable mVibrationRunnable = new Runnable() { 275 public void run() { 276 synchronized (mVibrations) { 277 doCancelVibrateLocked(); 278 startNextVibrationLocked(); 279 } 280 } 281 }; 282 283 // Lock held on mVibrations 284 private void doCancelVibrateLocked() { 285 if (mThread != null) { 286 synchronized (mThread) { 287 mThread.mDone = true; 288 mThread.notify(); 289 } 290 mThread = null; 291 } 292 doVibratorOff(); 293 mH.removeCallbacks(mVibrationRunnable); 294 } 295 296 // Lock held on mVibrations 297 private void startNextVibrationLocked() { 298 if (mVibrations.size() <= 0) { 299 mCurrentVibration = null; 300 return; 301 } 302 mCurrentVibration = mVibrations.getFirst(); 303 startVibrationLocked(mCurrentVibration); 304 } 305 306 // Lock held on mVibrations 307 private void startVibrationLocked(final Vibration vib) { 308 if (vib.mTimeout != 0) { 309 doVibratorOn(vib.mTimeout); 310 mH.postDelayed(mVibrationRunnable, vib.mTimeout); 311 } else { 312 // mThread better be null here. doCancelVibrate should always be 313 // called before startNextVibrationLocked or startVibrationLocked. 314 mThread = new VibrateThread(vib); 315 mThread.start(); 316 } 317 } 318 319 // Lock held on mVibrations 320 private Vibration removeVibrationLocked(IBinder token) { 321 ListIterator<Vibration> iter = mVibrations.listIterator(0); 322 while (iter.hasNext()) { 323 Vibration vib = iter.next(); 324 if (vib.mToken == token) { 325 iter.remove(); 326 unlinkVibration(vib); 327 return vib; 328 } 329 } 330 // We might be looking for a simple vibration which is only stored in 331 // mCurrentVibration. 332 if (mCurrentVibration != null && mCurrentVibration.mToken == token) { 333 unlinkVibration(mCurrentVibration); 334 return mCurrentVibration; 335 } 336 return null; 337 } 338 339 private void unlinkVibration(Vibration vib) { 340 if (vib.mPattern != null) { 341 // If Vibration object has a pattern, 342 // the Vibration object has also been linkedToDeath. 343 vib.mToken.unlinkToDeath(vib, 0); 344 } 345 } 346 347 private void updateInputDeviceVibrators() { 348 synchronized (mVibrations) { 349 doCancelVibrateLocked(); 350 351 synchronized (mInputDeviceVibrators) { 352 mVibrateInputDevicesSetting = false; 353 try { 354 mVibrateInputDevicesSetting = Settings.System.getIntForUser( 355 mContext.getContentResolver(), 356 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 357 } catch (SettingNotFoundException snfe) { 358 } 359 360 if (mVibrateInputDevicesSetting) { 361 if (!mInputDeviceListenerRegistered) { 362 mInputDeviceListenerRegistered = true; 363 mIm.registerInputDeviceListener(this, mH); 364 } 365 } else { 366 if (mInputDeviceListenerRegistered) { 367 mInputDeviceListenerRegistered = false; 368 mIm.unregisterInputDeviceListener(this); 369 } 370 } 371 372 mInputDeviceVibrators.clear(); 373 if (mVibrateInputDevicesSetting) { 374 int[] ids = mIm.getInputDeviceIds(); 375 for (int i = 0; i < ids.length; i++) { 376 InputDevice device = mIm.getInputDevice(ids[i]); 377 Vibrator vibrator = device.getVibrator(); 378 if (vibrator.hasVibrator()) { 379 mInputDeviceVibrators.add(vibrator); 380 } 381 } 382 } 383 } 384 385 startNextVibrationLocked(); 386 } 387 } 388 389 @Override 390 public void onInputDeviceAdded(int deviceId) { 391 updateInputDeviceVibrators(); 392 } 393 394 @Override 395 public void onInputDeviceChanged(int deviceId) { 396 updateInputDeviceVibrators(); 397 } 398 399 @Override 400 public void onInputDeviceRemoved(int deviceId) { 401 updateInputDeviceVibrators(); 402 } 403 404 private boolean doVibratorExists() { 405 // For now, we choose to ignore the presence of input devices that have vibrators 406 // when reporting whether the device has a vibrator. Applications often use this 407 // information to decide whether to enable certain features so they expect the 408 // result of hasVibrator() to be constant. For now, just report whether 409 // the device has a built-in vibrator. 410 //synchronized (mInputDeviceVibrators) { 411 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 412 //} 413 return vibratorExists(); 414 } 415 416 private void doVibratorOn(long millis) { 417 synchronized (mInputDeviceVibrators) { 418 final int vibratorCount = mInputDeviceVibrators.size(); 419 if (vibratorCount != 0) { 420 for (int i = 0; i < vibratorCount; i++) { 421 mInputDeviceVibrators.get(i).vibrate(millis); 422 } 423 } else { 424 vibratorOn(millis); 425 } 426 } 427 } 428 429 private void doVibratorOff() { 430 synchronized (mInputDeviceVibrators) { 431 final int vibratorCount = mInputDeviceVibrators.size(); 432 if (vibratorCount != 0) { 433 for (int i = 0; i < vibratorCount; i++) { 434 mInputDeviceVibrators.get(i).cancel(); 435 } 436 } else { 437 vibratorOff(); 438 } 439 } 440 } 441 442 private class VibrateThread extends Thread { 443 final Vibration mVibration; 444 boolean mDone; 445 446 VibrateThread(Vibration vib) { 447 mVibration = vib; 448 mTmpWorkSource.set(vib.mUid); 449 mWakeLock.setWorkSource(mTmpWorkSource); 450 mWakeLock.acquire(); 451 } 452 453 private void delay(long duration) { 454 if (duration > 0) { 455 long bedtime = duration + SystemClock.uptimeMillis(); 456 do { 457 try { 458 this.wait(duration); 459 } 460 catch (InterruptedException e) { 461 } 462 if (mDone) { 463 break; 464 } 465 duration = bedtime - SystemClock.uptimeMillis(); 466 } while (duration > 0); 467 } 468 } 469 470 public void run() { 471 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 472 synchronized (this) { 473 int index = 0; 474 long[] pattern = mVibration.mPattern; 475 int len = pattern.length; 476 int repeat = mVibration.mRepeat; 477 long duration = 0; 478 479 while (!mDone) { 480 // add off-time duration to any accumulated on-time duration 481 if (index < len) { 482 duration += pattern[index++]; 483 } 484 485 // sleep until it is time to start the vibrator 486 delay(duration); 487 if (mDone) { 488 break; 489 } 490 491 if (index < len) { 492 // read on-time duration and start the vibrator 493 // duration is saved for delay() at top of loop 494 duration = pattern[index++]; 495 if (duration > 0) { 496 VibratorService.this.doVibratorOn(duration); 497 } 498 } else { 499 if (repeat < 0) { 500 break; 501 } else { 502 index = repeat; 503 duration = 0; 504 } 505 } 506 } 507 mWakeLock.release(); 508 } 509 synchronized (mVibrations) { 510 if (mThread == this) { 511 mThread = null; 512 } 513 if (!mDone) { 514 // If this vibration finished naturally, start the next 515 // vibration. 516 mVibrations.remove(mVibration); 517 unlinkVibration(mVibration); 518 startNextVibrationLocked(); 519 } 520 } 521 } 522 }; 523 524 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 525 public void onReceive(Context context, Intent intent) { 526 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 527 synchronized (mVibrations) { 528 doCancelVibrateLocked(); 529 530 int size = mVibrations.size(); 531 for(int i = 0; i < size; i++) { 532 unlinkVibration(mVibrations.get(i)); 533 } 534 535 mVibrations.clear(); 536 } 537 } 538 } 539 }; 540} 541