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 17 package com.android.server; 18 19 import com.android.internal.app.IBatteryStats; 20 import com.android.server.am.BatteryStatsService; 21 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.os.Handler; 28 import android.os.Hardware; 29 import android.os.IHardwareService; 30 import android.os.Message; 31 import android.os.Power; 32 import android.os.PowerManager; 33 import android.os.Process; 34 import android.os.RemoteException; 35 import android.os.IBinder; 36 import android.os.Binder; 37 import android.os.SystemClock; 38 import android.util.Log; 39 40 import java.util.LinkedList; 41 import java.util.ListIterator; 42 43 public class HardwareService extends IHardwareService.Stub { 44 private static final String TAG = "HardwareService"; 45 46 static final int LIGHT_ID_BACKLIGHT = 0; 47 static final int LIGHT_ID_KEYBOARD = 1; 48 static final int LIGHT_ID_BUTTONS = 2; 49 static final int LIGHT_ID_BATTERY = 3; 50 static final int LIGHT_ID_NOTIFICATIONS = 4; 51 static final int LIGHT_ID_ATTENTION = 5; 52 53 static final int LIGHT_FLASH_NONE = 0; 54 static final int LIGHT_FLASH_TIMED = 1; 55 static final int LIGHT_FLASH_HARDWARE = 2; 56 57 /** 58 * Light brightness is managed by a user setting. 59 */ 60 static final int BRIGHTNESS_MODE_USER = 0; 61 62 /** 63 * Light brightness is managed by a light sensor. 64 */ 65 static final int BRIGHTNESS_MODE_SENSOR = 1; 66 67 private final LinkedList<Vibration> mVibrations; 68 private Vibration mCurrentVibration; 69 70 private boolean mAttentionLightOn; 71 private boolean mPulsing; 72 73 private class Vibration implements IBinder.DeathRecipient { 74 private final IBinder mToken; 75 private final long mTimeout; 76 private final long mStartTime; 77 private final long[] mPattern; 78 private final int mRepeat; 79 Vibration(IBinder token, long millis)80 Vibration(IBinder token, long millis) { 81 this(token, millis, null, 0); 82 } 83 Vibration(IBinder token, long[] pattern, int repeat)84 Vibration(IBinder token, long[] pattern, int repeat) { 85 this(token, 0, pattern, repeat); 86 } 87 Vibration(IBinder token, long millis, long[] pattern, int repeat)88 private Vibration(IBinder token, long millis, long[] pattern, 89 int repeat) { 90 mToken = token; 91 mTimeout = millis; 92 mStartTime = SystemClock.uptimeMillis(); 93 mPattern = pattern; 94 mRepeat = repeat; 95 } 96 binderDied()97 public void binderDied() { 98 synchronized (mVibrations) { 99 mVibrations.remove(this); 100 if (this == mCurrentVibration) { 101 doCancelVibrateLocked(); 102 startNextVibrationLocked(); 103 } 104 } 105 } 106 hasLongerTimeout(long millis)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 HardwareService(Context context)123 HardwareService(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 mNativePointer = init_native(); 129 130 mContext = context; 131 PowerManager pm = (PowerManager)context.getSystemService( 132 Context.POWER_SERVICE); 133 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 134 mWakeLock.setReferenceCounted(true); 135 136 mVibrations = new LinkedList<Vibration>(); 137 138 mBatteryStats = BatteryStatsService.getService(); 139 140 IntentFilter filter = new IntentFilter(); 141 filter.addAction(Intent.ACTION_SCREEN_OFF); 142 context.registerReceiver(mIntentReceiver, filter); 143 } 144 finalize()145 protected void finalize() throws Throwable { 146 finalize_native(mNativePointer); 147 super.finalize(); 148 } 149 vibrate(long milliseconds, IBinder token)150 public void vibrate(long milliseconds, IBinder token) { 151 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 152 != PackageManager.PERMISSION_GRANTED) { 153 throw new SecurityException("Requires VIBRATE permission"); 154 } 155 // We're running in the system server so we cannot crash. Check for a 156 // timeout of 0 or negative. This will ensure that a vibration has 157 // either a timeout of > 0 or a non-null pattern. 158 if (milliseconds <= 0 || (mCurrentVibration != null 159 && mCurrentVibration.hasLongerTimeout(milliseconds))) { 160 // Ignore this vibration since the current vibration will play for 161 // longer than milliseconds. 162 return; 163 } 164 Vibration vib = new Vibration(token, milliseconds); 165 synchronized (mVibrations) { 166 removeVibrationLocked(token); 167 doCancelVibrateLocked(); 168 mCurrentVibration = vib; 169 startVibrationLocked(vib); 170 } 171 } 172 isAll0(long[] pattern)173 private boolean isAll0(long[] pattern) { 174 int N = pattern.length; 175 for (int i = 0; i < N; i++) { 176 if (pattern[i] != 0) { 177 return false; 178 } 179 } 180 return true; 181 } 182 vibratePattern(long[] pattern, int repeat, IBinder token)183 public void vibratePattern(long[] pattern, int repeat, IBinder token) { 184 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 185 != PackageManager.PERMISSION_GRANTED) { 186 throw new SecurityException("Requires VIBRATE permission"); 187 } 188 // so wakelock calls will succeed 189 long identity = Binder.clearCallingIdentity(); 190 try { 191 if (false) { 192 String s = ""; 193 int N = pattern.length; 194 for (int i=0; i<N; i++) { 195 s += " " + pattern[i]; 196 } 197 Log.i(TAG, "vibrating with pattern: " + s); 198 } 199 200 // we're running in the server so we can't fail 201 if (pattern == null || pattern.length == 0 202 || isAll0(pattern) 203 || repeat >= pattern.length || token == null) { 204 return; 205 } 206 207 Vibration vib = new Vibration(token, pattern, repeat); 208 try { 209 token.linkToDeath(vib, 0); 210 } catch (RemoteException e) { 211 return; 212 } 213 214 synchronized (mVibrations) { 215 removeVibrationLocked(token); 216 doCancelVibrateLocked(); 217 if (repeat >= 0) { 218 mVibrations.addFirst(vib); 219 startNextVibrationLocked(); 220 } else { 221 // A negative repeat means that this pattern is not meant 222 // to repeat. Treat it like a simple vibration. 223 mCurrentVibration = vib; 224 startVibrationLocked(vib); 225 } 226 } 227 } 228 finally { 229 Binder.restoreCallingIdentity(identity); 230 } 231 } 232 cancelVibrate(IBinder token)233 public void cancelVibrate(IBinder token) { 234 mContext.enforceCallingOrSelfPermission( 235 android.Manifest.permission.VIBRATE, 236 "cancelVibrate"); 237 238 // so wakelock calls will succeed 239 long identity = Binder.clearCallingIdentity(); 240 try { 241 synchronized (mVibrations) { 242 final Vibration vib = removeVibrationLocked(token); 243 if (vib == mCurrentVibration) { 244 doCancelVibrateLocked(); 245 startNextVibrationLocked(); 246 } 247 } 248 } 249 finally { 250 Binder.restoreCallingIdentity(identity); 251 } 252 } 253 getFlashlightEnabled()254 public boolean getFlashlightEnabled() { 255 return Hardware.getFlashlightEnabled(); 256 } 257 setFlashlightEnabled(boolean on)258 public void setFlashlightEnabled(boolean on) { 259 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) 260 != PackageManager.PERMISSION_GRANTED && 261 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 262 != PackageManager.PERMISSION_GRANTED) { 263 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission"); 264 } 265 Hardware.setFlashlightEnabled(on); 266 } 267 enableCameraFlash(int milliseconds)268 public void enableCameraFlash(int milliseconds) { 269 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA) 270 != PackageManager.PERMISSION_GRANTED && 271 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 272 != PackageManager.PERMISSION_GRANTED) { 273 throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission"); 274 } 275 Hardware.enableCameraFlash(milliseconds); 276 } 277 setLightOff_UNCHECKED(int light)278 void setLightOff_UNCHECKED(int light) { 279 setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0); 280 } 281 setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode)282 void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) { 283 int b = brightness & 0x000000ff; 284 b = 0xff000000 | (b << 16) | (b << 8) | b; 285 setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode); 286 } 287 setLightColor_UNCHECKED(int light, int color)288 void setLightColor_UNCHECKED(int light, int color) { 289 setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0); 290 } 291 setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS)292 void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) { 293 setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0); 294 } 295 setAttentionLight(boolean on, int color)296 public void setAttentionLight(boolean on, int color) { 297 // Not worthy of a permission. We shouldn't have a flashlight permission. 298 synchronized (this) { 299 mAttentionLightOn = on; 300 mPulsing = false; 301 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color, 302 LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0); 303 } 304 } 305 pulseBreathingLight()306 public void pulseBreathingLight() { 307 synchronized (this) { 308 // HACK: Added at the last minute of cupcake -- design this better; 309 // Don't reuse the attention light -- make another one. 310 if (false) { 311 Log.d(TAG, "pulseBreathingLight mAttentionLightOn=" + mAttentionLightOn 312 + " mPulsing=" + mPulsing); 313 } 314 if (!mAttentionLightOn && !mPulsing) { 315 mPulsing = true; 316 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff, 317 LIGHT_FLASH_HARDWARE, 7, 0, 0); 318 mH.sendMessageDelayed(Message.obtain(mH, 1), 3000); 319 } 320 } 321 } 322 323 private Handler mH = new Handler() { 324 @Override 325 public void handleMessage(Message msg) { 326 synchronized (this) { 327 if (false) { 328 Log.d(TAG, "pulse cleanup handler firing mPulsing=" + mPulsing); 329 } 330 if (mPulsing) { 331 mPulsing = false; 332 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 333 mAttentionLightOn ? 0xffffffff : 0, 334 LIGHT_FLASH_NONE, 0, 0, 0); 335 } 336 } 337 } 338 }; 339 340 private final Runnable mVibrationRunnable = new Runnable() { 341 public void run() { 342 synchronized (mVibrations) { 343 doCancelVibrateLocked(); 344 startNextVibrationLocked(); 345 } 346 } 347 }; 348 349 // Lock held on mVibrations doCancelVibrateLocked()350 private void doCancelVibrateLocked() { 351 if (mThread != null) { 352 synchronized (mThread) { 353 mThread.mDone = true; 354 mThread.notify(); 355 } 356 mThread = null; 357 } 358 vibratorOff(); 359 mH.removeCallbacks(mVibrationRunnable); 360 } 361 362 // Lock held on mVibrations startNextVibrationLocked()363 private void startNextVibrationLocked() { 364 if (mVibrations.size() <= 0) { 365 return; 366 } 367 mCurrentVibration = mVibrations.getFirst(); 368 startVibrationLocked(mCurrentVibration); 369 } 370 371 // Lock held on mVibrations startVibrationLocked(final Vibration vib)372 private void startVibrationLocked(final Vibration vib) { 373 if (vib.mTimeout != 0) { 374 vibratorOn(vib.mTimeout); 375 mH.postDelayed(mVibrationRunnable, vib.mTimeout); 376 } else { 377 // mThread better be null here. doCancelVibrate should always be 378 // called before startNextVibrationLocked or startVibrationLocked. 379 mThread = new VibrateThread(vib); 380 mThread.start(); 381 } 382 } 383 384 // Lock held on mVibrations removeVibrationLocked(IBinder token)385 private Vibration removeVibrationLocked(IBinder token) { 386 ListIterator<Vibration> iter = mVibrations.listIterator(0); 387 while (iter.hasNext()) { 388 Vibration vib = iter.next(); 389 if (vib.mToken == token) { 390 iter.remove(); 391 return vib; 392 } 393 } 394 // We might be looking for a simple vibration which is only stored in 395 // mCurrentVibration. 396 if (mCurrentVibration != null && mCurrentVibration.mToken == token) { 397 return mCurrentVibration; 398 } 399 return null; 400 } 401 402 private class VibrateThread extends Thread { 403 final Vibration mVibration; 404 boolean mDone; 405 VibrateThread(Vibration vib)406 VibrateThread(Vibration vib) { 407 mVibration = vib; 408 mWakeLock.acquire(); 409 } 410 delay(long duration)411 private void delay(long duration) { 412 if (duration > 0) { 413 long bedtime = SystemClock.uptimeMillis(); 414 do { 415 try { 416 this.wait(duration); 417 } 418 catch (InterruptedException e) { 419 } 420 if (mDone) { 421 break; 422 } 423 duration = duration 424 - SystemClock.uptimeMillis() - bedtime; 425 } while (duration > 0); 426 } 427 } 428 run()429 public void run() { 430 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 431 synchronized (this) { 432 int index = 0; 433 long[] pattern = mVibration.mPattern; 434 int len = pattern.length; 435 int repeat = mVibration.mRepeat; 436 long duration = 0; 437 438 while (!mDone) { 439 // add off-time duration to any accumulated on-time duration 440 if (index < len) { 441 duration += pattern[index++]; 442 } 443 444 // sleep until it is time to start the vibrator 445 delay(duration); 446 if (mDone) { 447 break; 448 } 449 450 if (index < len) { 451 // read on-time duration and start the vibrator 452 // duration is saved for delay() at top of loop 453 duration = pattern[index++]; 454 if (duration > 0) { 455 HardwareService.this.vibratorOn(duration); 456 } 457 } else { 458 if (repeat < 0) { 459 break; 460 } else { 461 index = repeat; 462 duration = 0; 463 } 464 } 465 } 466 mWakeLock.release(); 467 } 468 synchronized (mVibrations) { 469 if (mThread == this) { 470 mThread = null; 471 } 472 if (!mDone) { 473 // If this vibration finished naturally, start the next 474 // vibration. 475 mVibrations.remove(mVibration); 476 startNextVibrationLocked(); 477 } 478 } 479 } 480 }; 481 482 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 483 public void onReceive(Context context, Intent intent) { 484 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 485 synchronized (mVibrations) { 486 doCancelVibrateLocked(); 487 mVibrations.clear(); 488 } 489 } 490 } 491 }; 492 init_native()493 private static native int init_native(); finalize_native(int ptr)494 private static native void finalize_native(int ptr); 495 setLight_native(int ptr, int light, int color, int mode, int onMS, int offMS, int brightnessMode)496 private static native void setLight_native(int ptr, int light, int color, int mode, 497 int onMS, int offMS, int brightnessMode); 498 499 private final Context mContext; 500 private final PowerManager.WakeLock mWakeLock; 501 502 private final IBatteryStats mBatteryStats; 503 504 volatile VibrateThread mThread; 505 506 private int mNativePointer; 507 vibratorOn(long milliseconds)508 native static void vibratorOn(long milliseconds); vibratorOff()509 native static void vibratorOff(); 510 } 511