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 com.android.internal.app.IBatteryStats; 20import com.android.server.am.BatteryStatsService; 21 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.PackageManager; 27import android.os.Handler; 28import android.os.Hardware; 29import android.os.IHardwareService; 30import android.os.Message; 31import android.os.Power; 32import android.os.PowerManager; 33import android.os.Process; 34import android.os.RemoteException; 35import android.os.IBinder; 36import android.os.Binder; 37import android.os.SystemClock; 38import android.util.Log; 39 40public class HardwareService extends IHardwareService.Stub { 41 private static final String TAG = "HardwareService"; 42 43 static final int LIGHT_ID_BACKLIGHT = 0; 44 static final int LIGHT_ID_KEYBOARD = 1; 45 static final int LIGHT_ID_BUTTONS = 2; 46 static final int LIGHT_ID_BATTERY = 3; 47 static final int LIGHT_ID_NOTIFICATIONS = 4; 48 static final int LIGHT_ID_ATTENTION = 5; 49 50 static final int LIGHT_FLASH_NONE = 0; 51 static final int LIGHT_FLASH_TIMED = 1; 52 53 private boolean mAttentionLightOn; 54 private boolean mPulsing; 55 56 HardwareService(Context context) { 57 // Reset the hardware to a default state, in case this is a runtime 58 // restart instead of a fresh boot. 59 vibratorOff(); 60 61 mNativePointer = init_native(); 62 63 mContext = context; 64 PowerManager pm = (PowerManager)context.getSystemService( 65 Context.POWER_SERVICE); 66 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 67 mWakeLock.setReferenceCounted(true); 68 69 mBatteryStats = BatteryStatsService.getService(); 70 71 IntentFilter filter = new IntentFilter(); 72 filter.addAction(Intent.ACTION_SCREEN_OFF); 73 context.registerReceiver(mIntentReceiver, filter); 74 } 75 76 protected void finalize() throws Throwable { 77 finalize_native(mNativePointer); 78 super.finalize(); 79 } 80 81 public void vibrate(long milliseconds) { 82 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 83 != PackageManager.PERMISSION_GRANTED) { 84 throw new SecurityException("Requires VIBRATE permission"); 85 } 86 doCancelVibrate(); 87 vibratorOn(milliseconds); 88 } 89 90 private boolean isAll0(long[] pattern) { 91 int N = pattern.length; 92 for (int i = 0; i < N; i++) { 93 if (pattern[i] != 0) { 94 return false; 95 } 96 } 97 return true; 98 } 99 100 public void vibratePattern(long[] pattern, int repeat, IBinder token) { 101 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 102 != PackageManager.PERMISSION_GRANTED) { 103 throw new SecurityException("Requires VIBRATE permission"); 104 } 105 // so wakelock calls will succeed 106 long identity = Binder.clearCallingIdentity(); 107 try { 108 if (false) { 109 String s = ""; 110 int N = pattern.length; 111 for (int i=0; i<N; i++) { 112 s += " " + pattern[i]; 113 } 114 Log.i(TAG, "vibrating with pattern: " + s); 115 } 116 117 // we're running in the server so we can't fail 118 if (pattern == null || pattern.length == 0 119 || isAll0(pattern) 120 || repeat >= pattern.length || token == null) { 121 return; 122 } 123 124 synchronized (this) { 125 Death death = new Death(token); 126 try { 127 token.linkToDeath(death, 0); 128 } catch (RemoteException e) { 129 return; 130 } 131 132 Thread oldThread = mThread; 133 134 if (oldThread != null) { 135 // stop the old one 136 synchronized (mThread) { 137 mThread.mDone = true; 138 mThread.notify(); 139 } 140 } 141 142 if (mDeath != null) { 143 mToken.unlinkToDeath(mDeath, 0); 144 } 145 146 mDeath = death; 147 mToken = token; 148 149 // start the new thread 150 mThread = new VibrateThread(pattern, repeat); 151 mThread.start(); 152 } 153 } 154 finally { 155 Binder.restoreCallingIdentity(identity); 156 } 157 } 158 159 public void cancelVibrate() { 160 mContext.enforceCallingOrSelfPermission( 161 android.Manifest.permission.VIBRATE, 162 "cancelVibrate"); 163 164 // so wakelock calls will succeed 165 long identity = Binder.clearCallingIdentity(); 166 try { 167 doCancelVibrate(); 168 } 169 finally { 170 Binder.restoreCallingIdentity(identity); 171 } 172 } 173 174 public boolean getFlashlightEnabled() { 175 return Hardware.getFlashlightEnabled(); 176 } 177 178 public void setFlashlightEnabled(boolean on) { 179 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) 180 != PackageManager.PERMISSION_GRANTED && 181 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 182 != PackageManager.PERMISSION_GRANTED) { 183 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission"); 184 } 185 Hardware.setFlashlightEnabled(on); 186 } 187 188 public void enableCameraFlash(int milliseconds) { 189 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA) 190 != PackageManager.PERMISSION_GRANTED && 191 mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 192 != PackageManager.PERMISSION_GRANTED) { 193 throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission"); 194 } 195 Hardware.enableCameraFlash(milliseconds); 196 } 197 198 public void setBacklights(int brightness) { 199 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) 200 != PackageManager.PERMISSION_GRANTED) { 201 throw new SecurityException("Requires HARDWARE_TEST permission"); 202 } 203 // Don't let applications turn the screen all the way off 204 brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); 205 setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness); 206 setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness); 207 setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness); 208 long identity = Binder.clearCallingIdentity(); 209 try { 210 mBatteryStats.noteScreenBrightness(brightness); 211 } catch (RemoteException e) { 212 Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e); 213 } finally { 214 Binder.restoreCallingIdentity(identity); 215 } 216 } 217 218 void setLightOff_UNCHECKED(int light) { 219 setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0); 220 } 221 222 void setLightBrightness_UNCHECKED(int light, int brightness) { 223 int b = brightness & 0x000000ff; 224 b = 0xff000000 | (b << 16) | (b << 8) | b; 225 setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0); 226 } 227 228 void setLightColor_UNCHECKED(int light, int color) { 229 setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0); 230 } 231 232 void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) { 233 setLight_native(mNativePointer, light, color, mode, onMS, offMS); 234 } 235 236 public void setAttentionLight(boolean on) { 237 // Not worthy of a permission. We shouldn't have a flashlight permission. 238 synchronized (this) { 239 mAttentionLightOn = on; 240 mPulsing = false; 241 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, on ? 0xffffffff : 0, 242 LIGHT_FLASH_NONE, 0, 0); 243 } 244 } 245 246 public void pulseBreathingLight() { 247 synchronized (this) { 248 // HACK: Added at the last minute of cupcake -- design this better; 249 // Don't reuse the attention light -- make another one. 250 if (false) { 251 Log.d(TAG, "pulseBreathingLight mAttentionLightOn=" + mAttentionLightOn 252 + " mPulsing=" + mPulsing); 253 } 254 if (!mAttentionLightOn && !mPulsing) { 255 mPulsing = true; 256 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0xff101010, 257 LIGHT_FLASH_NONE, 0, 0); 258 mH.sendMessageDelayed(Message.obtain(mH, 1), 3000); 259 } 260 } 261 } 262 263 private Handler mH = new Handler() { 264 @Override 265 public void handleMessage(Message msg) { 266 synchronized (this) { 267 if (false) { 268 Log.d(TAG, "pulse cleanup handler firing mPulsing=" + mPulsing); 269 } 270 if (mPulsing) { 271 mPulsing = false; 272 setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 273 mAttentionLightOn ? 0xffffffff : 0, 274 LIGHT_FLASH_NONE, 0, 0); 275 } 276 } 277 } 278 }; 279 280 private void doCancelVibrate() { 281 synchronized (this) { 282 if (mThread != null) { 283 synchronized (mThread) { 284 mThread.mDone = true; 285 mThread.notify(); 286 } 287 mThread = null; 288 } 289 vibratorOff(); 290 } 291 } 292 293 private class VibrateThread extends Thread { 294 long[] mPattern; 295 int mRepeat; 296 boolean mDone; 297 298 VibrateThread(long[] pattern, int repeat) { 299 mPattern = pattern; 300 mRepeat = repeat; 301 mWakeLock.acquire(); 302 } 303 304 private void delay(long duration) { 305 if (duration > 0) { 306 long bedtime = SystemClock.uptimeMillis(); 307 do { 308 try { 309 this.wait(duration); 310 } 311 catch (InterruptedException e) { 312 } 313 if (mDone) { 314 break; 315 } 316 duration = duration 317 - SystemClock.uptimeMillis() - bedtime; 318 } while (duration > 0); 319 } 320 } 321 322 public void run() { 323 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 324 synchronized (this) { 325 int index = 0; 326 long[] pattern = mPattern; 327 int len = pattern.length; 328 long duration = 0; 329 330 while (!mDone) { 331 // add off-time duration to any accumulated on-time duration 332 if (index < len) { 333 duration += pattern[index++]; 334 } 335 336 // sleep until it is time to start the vibrator 337 delay(duration); 338 if (mDone) { 339 break; 340 } 341 342 if (index < len) { 343 // read on-time duration and start the vibrator 344 // duration is saved for delay() at top of loop 345 duration = pattern[index++]; 346 if (duration > 0) { 347 HardwareService.this.vibratorOn(duration); 348 } 349 } else { 350 if (mRepeat < 0) { 351 break; 352 } else { 353 index = mRepeat; 354 duration = 0; 355 } 356 } 357 } 358 if (mDone) { 359 // make sure vibrator is off if we were cancelled. 360 // otherwise, it will turn off automatically 361 // when the last timeout expires. 362 HardwareService.this.vibratorOff(); 363 } 364 mWakeLock.release(); 365 } 366 synchronized (HardwareService.this) { 367 if (mThread == this) { 368 mThread = null; 369 } 370 } 371 } 372 }; 373 374 private class Death implements IBinder.DeathRecipient { 375 IBinder mMe; 376 377 Death(IBinder me) { 378 mMe = me; 379 } 380 381 public void binderDied() { 382 synchronized (HardwareService.this) { 383 if (mMe == mToken) { 384 doCancelVibrate(); 385 } 386 } 387 } 388 } 389 390 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 391 public void onReceive(Context context, Intent intent) { 392 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 393 doCancelVibrate(); 394 } 395 } 396 }; 397 398 private static native int init_native(); 399 private static native void finalize_native(int ptr); 400 401 private static native void setLight_native(int ptr, int light, int color, int mode, 402 int onMS, int offMS); 403 404 private final Context mContext; 405 private final PowerManager.WakeLock mWakeLock; 406 407 private final IBatteryStats mBatteryStats; 408 409 volatile VibrateThread mThread; 410 volatile Death mDeath; 411 volatile IBinder mToken; 412 413 private int mNativePointer; 414 415 native static void vibratorOn(long milliseconds); 416 native static void vibratorOff(); 417} 418