1 /* 2 * Copyright (C) 2012 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.power; 18 19 import android.annotation.Nullable; 20 import android.annotation.UserIdInt; 21 import android.app.ActivityManagerInternal; 22 import android.app.AppOpsManager; 23 import android.app.trust.TrustManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.hardware.input.InputManagerInternal; 28 import android.media.AudioAttributes; 29 import android.media.AudioManager; 30 import android.media.Ringtone; 31 import android.media.RingtoneManager; 32 import android.metrics.LogMaker; 33 import android.net.Uri; 34 import android.os.BatteryStats; 35 import android.os.Handler; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.PowerManager; 39 import android.os.PowerManagerInternal; 40 import android.os.Process; 41 import android.os.RemoteException; 42 import android.os.SystemClock; 43 import android.os.UserHandle; 44 import android.os.VibrationEffect; 45 import android.os.Vibrator; 46 import android.os.WorkSource; 47 import android.provider.Settings; 48 import android.util.EventLog; 49 import android.util.Slog; 50 import android.view.inputmethod.InputMethodManagerInternal; 51 52 import com.android.internal.app.IBatteryStats; 53 import com.android.internal.logging.MetricsLogger; 54 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 55 import com.android.server.EventLogTags; 56 import com.android.server.LocalServices; 57 import com.android.server.policy.WindowManagerPolicy; 58 import com.android.server.statusbar.StatusBarManagerInternal; 59 60 /** 61 * Sends broadcasts about important power state changes. 62 * <p> 63 * This methods of this class may be called by the power manager service while 64 * its lock is being held. Internally it takes care of sending broadcasts to 65 * notify other components of the system or applications asynchronously. 66 * </p><p> 67 * The notifier is designed to collapse unnecessary broadcasts when it is not 68 * possible for the system to have observed an intermediate state. 69 * </p><p> 70 * For example, if the device wakes up, goes to sleep, wakes up again and goes to 71 * sleep again before the wake up notification is sent, then the system will 72 * be told about only one wake up and sleep. However, we always notify the 73 * fact that at least one transition occurred. It is especially important to 74 * tell the system when we go to sleep so that it can lock the keyguard if needed. 75 * </p> 76 */ 77 final class Notifier { 78 private static final String TAG = "PowerManagerNotifier"; 79 80 private static final boolean DEBUG = false; 81 82 private static final int INTERACTIVE_STATE_UNKNOWN = 0; 83 private static final int INTERACTIVE_STATE_AWAKE = 1; 84 private static final int INTERACTIVE_STATE_ASLEEP = 2; 85 86 private static final int MSG_USER_ACTIVITY = 1; 87 private static final int MSG_BROADCAST = 2; 88 private static final int MSG_WIRELESS_CHARGING_STARTED = 3; 89 private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4; 90 private static final int MSG_PROFILE_TIMED_OUT = 5; 91 private static final int MSG_WIRED_CHARGING_STARTED = 6; 92 93 private static final long[] WIRELESS_VIBRATION_TIME = { 94 40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms 95 40, 40, 40, 40, 40, 40, 40 // ramp-down sampling rate = 40ms 96 }; 97 private static final int[] WIRELESS_VIBRATION_AMPLITUDE = { 98 1, 4, 11, 25, 44, 67, 91, 114, 123, // ramp-up amplitude (from 0 to 50%) 99 103, 79, 55, 34, 17, 7, 2 // ramp-up amplitude 100 }; 101 private static final VibrationEffect WIRELESS_CHARGING_VIBRATION_EFFECT = 102 VibrationEffect.createWaveform(WIRELESS_VIBRATION_TIME, WIRELESS_VIBRATION_AMPLITUDE, 103 -1); 104 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() 105 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 106 .build(); 107 108 private final Object mLock = new Object(); 109 110 private final Context mContext; 111 private final IBatteryStats mBatteryStats; 112 private final AppOpsManager mAppOps; 113 private final SuspendBlocker mSuspendBlocker; 114 private final WindowManagerPolicy mPolicy; 115 private final ActivityManagerInternal mActivityManagerInternal; 116 private final InputManagerInternal mInputManagerInternal; 117 private final InputMethodManagerInternal mInputMethodManagerInternal; 118 @Nullable private final StatusBarManagerInternal mStatusBarManagerInternal; 119 private final TrustManager mTrustManager; 120 private final Vibrator mVibrator; 121 122 private final NotifierHandler mHandler; 123 private final Intent mScreenOnIntent; 124 private final Intent mScreenOffIntent; 125 private final Intent mScreenBrightnessBoostIntent; 126 127 // True if the device should suspend when the screen is off due to proximity. 128 private final boolean mSuspendWhenScreenOffDueToProximityConfig; 129 130 // The current interactive state. This is set as soon as an interactive state 131 // transition begins so as to capture the reason that it happened. At some point 132 // this state will propagate to the pending state then eventually to the 133 // broadcasted state over the course of reporting the transition asynchronously. 134 private boolean mInteractive = true; 135 private int mInteractiveChangeReason; 136 private boolean mInteractiveChanging; 137 138 // The pending interactive state that we will eventually want to broadcast. 139 // This is designed so that we can collapse redundant sequences of awake/sleep 140 // transition pairs while still guaranteeing that at least one transition is observed 141 // whenever this happens. 142 private int mPendingInteractiveState; 143 private boolean mPendingWakeUpBroadcast; 144 private boolean mPendingGoToSleepBroadcast; 145 146 // The currently broadcasted interactive state. This reflects what other parts of the 147 // system have observed. 148 private int mBroadcastedInteractiveState; 149 private boolean mBroadcastInProgress; 150 private long mBroadcastStartTime; 151 152 // True if a user activity message should be sent. 153 private boolean mUserActivityPending; 154 Notifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy)155 public Notifier(Looper looper, Context context, IBatteryStats batteryStats, 156 SuspendBlocker suspendBlocker, WindowManagerPolicy policy) { 157 mContext = context; 158 mBatteryStats = batteryStats; 159 mAppOps = mContext.getSystemService(AppOpsManager.class); 160 mSuspendBlocker = suspendBlocker; 161 mPolicy = policy; 162 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 163 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); 164 mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); 165 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class); 166 mTrustManager = mContext.getSystemService(TrustManager.class); 167 mVibrator = mContext.getSystemService(Vibrator.class); 168 169 mHandler = new NotifierHandler(looper); 170 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); 171 mScreenOnIntent.addFlags( 172 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND 173 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); 174 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); 175 mScreenOffIntent.addFlags( 176 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND 177 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); 178 mScreenBrightnessBoostIntent = 179 new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED); 180 mScreenBrightnessBoostIntent.addFlags( 181 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 182 183 mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean( 184 com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity); 185 186 // Initialize interactive state for battery stats. 187 try { 188 mBatteryStats.noteInteractive(true); 189 } catch (RemoteException ex) { } 190 } 191 192 /** 193 * Called when a wake lock is acquired. 194 */ onWakeLockAcquired(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)195 public void onWakeLockAcquired(int flags, String tag, String packageName, 196 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 197 if (DEBUG) { 198 Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag 199 + "\", packageName=" + packageName 200 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 201 + ", workSource=" + workSource); 202 } 203 204 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 205 if (monitorType >= 0) { 206 try { 207 final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID 208 && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; 209 if (workSource != null) { 210 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, 211 historyTag, monitorType, unimportantForLogging); 212 } else { 213 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, 214 monitorType, unimportantForLogging); 215 // XXX need to deal with disabled operations. 216 mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 217 } 218 } catch (RemoteException ex) { 219 // Ignore 220 } 221 } 222 } 223 onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource, String historyTag)224 public void onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource, 225 String historyTag) { 226 if (DEBUG) { 227 Slog.d(TAG, "onLongPartialWakeLockStart: ownerUid=" + ownerUid 228 + ", workSource=" + workSource); 229 } 230 231 try { 232 if (workSource != null) { 233 mBatteryStats.noteLongPartialWakelockStartFromSource(tag, historyTag, workSource); 234 } else { 235 mBatteryStats.noteLongPartialWakelockStart(tag, historyTag, ownerUid); 236 } 237 } catch (RemoteException ex) { 238 // Ignore 239 } 240 } 241 onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource, String historyTag)242 public void onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource, 243 String historyTag) { 244 if (DEBUG) { 245 Slog.d(TAG, "onLongPartialWakeLockFinish: ownerUid=" + ownerUid 246 + ", workSource=" + workSource); 247 } 248 249 try { 250 if (workSource != null) { 251 mBatteryStats.noteLongPartialWakelockFinishFromSource(tag, historyTag, workSource); 252 } else { 253 mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, ownerUid); 254 } 255 } catch (RemoteException ex) { 256 // Ignore 257 } 258 } 259 260 /** 261 * Called when a wake lock is changing. 262 */ onWakeLockChanging(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, int newFlags, String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag)263 public void onWakeLockChanging(int flags, String tag, String packageName, 264 int ownerUid, int ownerPid, WorkSource workSource, String historyTag, 265 int newFlags, String newTag, String newPackageName, int newOwnerUid, 266 int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { 267 268 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 269 final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); 270 if (workSource != null && newWorkSource != null 271 && monitorType >= 0 && newMonitorType >= 0) { 272 if (DEBUG) { 273 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag 274 + "\", packageName=" + newPackageName 275 + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid 276 + ", workSource=" + newWorkSource); 277 } 278 279 final boolean unimportantForLogging = newOwnerUid == Process.SYSTEM_UID 280 && (newFlags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; 281 try { 282 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag, 283 monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag, 284 newMonitorType, unimportantForLogging); 285 } catch (RemoteException ex) { 286 // Ignore 287 } 288 } else { 289 onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag); 290 onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, 291 newWorkSource, newHistoryTag); 292 } 293 } 294 295 /** 296 * Called when a wake lock is released. 297 */ onWakeLockReleased(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)298 public void onWakeLockReleased(int flags, String tag, String packageName, 299 int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { 300 if (DEBUG) { 301 Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag 302 + "\", packageName=" + packageName 303 + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid 304 + ", workSource=" + workSource); 305 } 306 307 final int monitorType = getBatteryStatsWakeLockMonitorType(flags); 308 if (monitorType >= 0) { 309 try { 310 if (workSource != null) { 311 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, 312 historyTag, monitorType); 313 } else { 314 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, 315 historyTag, monitorType); 316 mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); 317 } 318 } catch (RemoteException ex) { 319 // Ignore 320 } 321 } 322 } 323 getBatteryStatsWakeLockMonitorType(int flags)324 private int getBatteryStatsWakeLockMonitorType(int flags) { 325 switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 326 case PowerManager.PARTIAL_WAKE_LOCK: 327 return BatteryStats.WAKE_TYPE_PARTIAL; 328 329 case PowerManager.SCREEN_DIM_WAKE_LOCK: 330 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: 331 return BatteryStats.WAKE_TYPE_FULL; 332 333 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: 334 if (mSuspendWhenScreenOffDueToProximityConfig) { 335 return -1; 336 } 337 return BatteryStats.WAKE_TYPE_PARTIAL; 338 339 case PowerManager.DRAW_WAKE_LOCK: 340 return BatteryStats.WAKE_TYPE_DRAW; 341 342 case PowerManager.DOZE_WAKE_LOCK: 343 // Doze wake locks are an internal implementation detail of the 344 // communication between dream manager service and power manager 345 // service. They have no additive battery impact. 346 return -1; 347 348 default: 349 return -1; 350 } 351 } 352 353 /** 354 * Notifies that the device is changing wakefulness. 355 * This function may be called even if the previous change hasn't finished in 356 * which case it will assume that the state did not fully converge before the 357 * next transition began and will recover accordingly. 358 */ onWakefulnessChangeStarted(final int wakefulness, int reason)359 public void onWakefulnessChangeStarted(final int wakefulness, int reason) { 360 final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); 361 if (DEBUG) { 362 Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness 363 + ", reason=" + reason + ", interactive=" + interactive); 364 } 365 366 // Tell the activity manager about changes in wakefulness, not just interactivity. 367 // It needs more granularity than other components. 368 mHandler.post(new Runnable() { 369 @Override 370 public void run() { 371 mActivityManagerInternal.onWakefulnessChanged(wakefulness); 372 } 373 }); 374 375 // Handle any early interactive state changes. 376 // Finish pending incomplete ones from a previous cycle. 377 if (mInteractive != interactive) { 378 // Finish up late behaviors if needed. 379 if (mInteractiveChanging) { 380 handleLateInteractiveChange(); 381 } 382 383 // Start input as soon as we start waking up or going to sleep. 384 mInputManagerInternal.setInteractive(interactive); 385 mInputMethodManagerInternal.setInteractive(interactive); 386 387 // Notify battery stats. 388 try { 389 mBatteryStats.noteInteractive(interactive); 390 } catch (RemoteException ex) { } 391 392 // Handle early behaviors. 393 mInteractive = interactive; 394 mInteractiveChangeReason = reason; 395 mInteractiveChanging = true; 396 handleEarlyInteractiveChange(); 397 } 398 } 399 400 /** 401 * Notifies that the device has finished changing wakefulness. 402 */ onWakefulnessChangeFinished()403 public void onWakefulnessChangeFinished() { 404 if (DEBUG) { 405 Slog.d(TAG, "onWakefulnessChangeFinished"); 406 } 407 408 if (mInteractiveChanging) { 409 mInteractiveChanging = false; 410 handleLateInteractiveChange(); 411 } 412 } 413 414 /** 415 * Handle early interactive state changes such as getting applications or the lock 416 * screen running and ready for the user to see (such as when turning on the screen). 417 */ handleEarlyInteractiveChange()418 private void handleEarlyInteractiveChange() { 419 synchronized (mLock) { 420 if (mInteractive) { 421 // Waking up... 422 mHandler.post(new Runnable() { 423 @Override 424 public void run() { 425 // Note a SCREEN tron event is logged in PowerManagerService. 426 mPolicy.startedWakingUp(); 427 } 428 }); 429 430 // Send interactive broadcast. 431 mPendingInteractiveState = INTERACTIVE_STATE_AWAKE; 432 mPendingWakeUpBroadcast = true; 433 updatePendingBroadcastLocked(); 434 } else { 435 // Going to sleep... 436 // Tell the policy that we started going to sleep. 437 final int why = translateOffReason(mInteractiveChangeReason); 438 mHandler.post(new Runnable() { 439 @Override 440 public void run() { 441 mPolicy.startedGoingToSleep(why); 442 } 443 }); 444 } 445 } 446 } 447 448 /** 449 * Handle late interactive state changes once they are finished so that the system can 450 * finish pending transitions (such as turning the screen off) before causing 451 * applications to change state visibly. 452 */ handleLateInteractiveChange()453 private void handleLateInteractiveChange() { 454 synchronized (mLock) { 455 if (mInteractive) { 456 // Finished waking up... 457 mHandler.post(new Runnable() { 458 @Override 459 public void run() { 460 mPolicy.finishedWakingUp(); 461 } 462 }); 463 } else { 464 // Finished going to sleep... 465 // This is a good time to make transitions that we don't want the user to see, 466 // such as bringing the key guard to focus. There's no guarantee for this 467 // however because the user could turn the device on again at any time. 468 // Some things may need to be protected by other mechanisms that defer screen on. 469 470 // Cancel pending user activity. 471 if (mUserActivityPending) { 472 mUserActivityPending = false; 473 mHandler.removeMessages(MSG_USER_ACTIVITY); 474 } 475 476 // Tell the policy we finished going to sleep. 477 final int why = translateOffReason(mInteractiveChangeReason); 478 mHandler.post(new Runnable() { 479 @Override 480 public void run() { 481 LogMaker log = new LogMaker(MetricsEvent.SCREEN); 482 log.setType(MetricsEvent.TYPE_CLOSE); 483 log.setSubtype(why); 484 MetricsLogger.action(log); 485 EventLogTags.writePowerScreenState(0, why, 0, 0, 0); 486 mPolicy.finishedGoingToSleep(why); 487 } 488 }); 489 490 // Send non-interactive broadcast. 491 mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP; 492 mPendingGoToSleepBroadcast = true; 493 updatePendingBroadcastLocked(); 494 } 495 } 496 } 497 translateOffReason(int reason)498 private static int translateOffReason(int reason) { 499 switch (reason) { 500 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: 501 return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN; 502 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: 503 return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT; 504 default: 505 return WindowManagerPolicy.OFF_BECAUSE_OF_USER; 506 } 507 } 508 509 /** 510 * Called when screen brightness boost begins or ends. 511 */ onScreenBrightnessBoostChanged()512 public void onScreenBrightnessBoostChanged() { 513 if (DEBUG) { 514 Slog.d(TAG, "onScreenBrightnessBoostChanged"); 515 } 516 517 mSuspendBlocker.acquire(); 518 Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED); 519 msg.setAsynchronous(true); 520 mHandler.sendMessage(msg); 521 } 522 523 /** 524 * Called when there has been user activity. 525 */ onUserActivity(int event, int uid)526 public void onUserActivity(int event, int uid) { 527 if (DEBUG) { 528 Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid); 529 } 530 531 try { 532 mBatteryStats.noteUserActivity(uid, event); 533 } catch (RemoteException ex) { 534 // Ignore 535 } 536 537 synchronized (mLock) { 538 if (!mUserActivityPending) { 539 mUserActivityPending = true; 540 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY); 541 msg.setAsynchronous(true); 542 mHandler.sendMessage(msg); 543 } 544 } 545 } 546 547 /** 548 * Called when the screen has turned on. 549 */ onWakeUp(String reason, int reasonUid, String opPackageName, int opUid)550 public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) { 551 if (DEBUG) { 552 Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid 553 + " opPackageName=" + opPackageName + " opUid=" + opUid); 554 } 555 556 try { 557 mBatteryStats.noteWakeUp(reason, reasonUid); 558 if (opPackageName != null) { 559 mAppOps.noteOpNoThrow(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName); 560 } 561 } catch (RemoteException ex) { 562 // Ignore 563 } 564 } 565 566 /** 567 * Called when profile screen lock timeout has expired. 568 */ onProfileTimeout(@serIdInt int userId)569 public void onProfileTimeout(@UserIdInt int userId) { 570 final Message msg = mHandler.obtainMessage(MSG_PROFILE_TIMED_OUT); 571 msg.setAsynchronous(true); 572 msg.arg1 = userId; 573 mHandler.sendMessage(msg); 574 } 575 576 /** 577 * Called when wireless charging has started so as to provide user feedback (sound and visual). 578 */ onWirelessChargingStarted(int batteryLevel)579 public void onWirelessChargingStarted(int batteryLevel) { 580 if (DEBUG) { 581 Slog.d(TAG, "onWirelessChargingStarted"); 582 } 583 584 mSuspendBlocker.acquire(); 585 Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED); 586 msg.setAsynchronous(true); 587 msg.arg1 = batteryLevel; 588 mHandler.sendMessage(msg); 589 } 590 591 /** 592 * Called when wired charging has started so as to provide user feedback 593 */ onWiredChargingStarted()594 public void onWiredChargingStarted() { 595 if (DEBUG) { 596 Slog.d(TAG, "onWiredChargingStarted"); 597 } 598 599 mSuspendBlocker.acquire(); 600 Message msg = mHandler.obtainMessage(MSG_WIRED_CHARGING_STARTED); 601 msg.setAsynchronous(true); 602 mHandler.sendMessage(msg); 603 } 604 updatePendingBroadcastLocked()605 private void updatePendingBroadcastLocked() { 606 if (!mBroadcastInProgress 607 && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN 608 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 609 || mPendingInteractiveState != mBroadcastedInteractiveState)) { 610 mBroadcastInProgress = true; 611 mSuspendBlocker.acquire(); 612 Message msg = mHandler.obtainMessage(MSG_BROADCAST); 613 msg.setAsynchronous(true); 614 mHandler.sendMessage(msg); 615 } 616 } 617 finishPendingBroadcastLocked()618 private void finishPendingBroadcastLocked() { 619 mBroadcastInProgress = false; 620 mSuspendBlocker.release(); 621 } 622 sendUserActivity()623 private void sendUserActivity() { 624 synchronized (mLock) { 625 if (!mUserActivityPending) { 626 return; 627 } 628 mUserActivityPending = false; 629 } 630 mPolicy.userActivity(); 631 } 632 sendNextBroadcast()633 private void sendNextBroadcast() { 634 final int powerState; 635 synchronized (mLock) { 636 if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) { 637 // Broadcasted power state is unknown. Send wake up. 638 mPendingWakeUpBroadcast = false; 639 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE; 640 } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) { 641 // Broadcasted power state is awake. Send asleep if needed. 642 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 643 || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) { 644 mPendingGoToSleepBroadcast = false; 645 mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP; 646 } else { 647 finishPendingBroadcastLocked(); 648 return; 649 } 650 } else { 651 // Broadcasted power state is asleep. Send awake if needed. 652 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast 653 || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) { 654 mPendingWakeUpBroadcast = false; 655 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE; 656 } else { 657 finishPendingBroadcastLocked(); 658 return; 659 } 660 } 661 662 mBroadcastStartTime = SystemClock.uptimeMillis(); 663 powerState = mBroadcastedInteractiveState; 664 } 665 666 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1); 667 668 if (powerState == INTERACTIVE_STATE_AWAKE) { 669 sendWakeUpBroadcast(); 670 } else { 671 sendGoToSleepBroadcast(); 672 } 673 } 674 sendBrightnessBoostChangedBroadcast()675 private void sendBrightnessBoostChangedBroadcast() { 676 if (DEBUG) { 677 Slog.d(TAG, "Sending brightness boost changed broadcast."); 678 } 679 680 mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null, 681 mScreeBrightnessBoostChangedDone, mHandler, 0, null, null); 682 } 683 684 private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() { 685 @Override 686 public void onReceive(Context context, Intent intent) { 687 mSuspendBlocker.release(); 688 } 689 }; 690 sendWakeUpBroadcast()691 private void sendWakeUpBroadcast() { 692 if (DEBUG) { 693 Slog.d(TAG, "Sending wake up broadcast."); 694 } 695 696 if (mActivityManagerInternal.isSystemReady()) { 697 mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, 698 mWakeUpBroadcastDone, mHandler, 0, null, null); 699 } else { 700 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1); 701 sendNextBroadcast(); 702 } 703 } 704 705 private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 706 @Override 707 public void onReceive(Context context, Intent intent) { 708 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1, 709 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 710 sendNextBroadcast(); 711 } 712 }; 713 sendGoToSleepBroadcast()714 private void sendGoToSleepBroadcast() { 715 if (DEBUG) { 716 Slog.d(TAG, "Sending go to sleep broadcast."); 717 } 718 719 if (mActivityManagerInternal.isSystemReady()) { 720 mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, 721 mGoToSleepBroadcastDone, mHandler, 0, null, null); 722 } else { 723 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1); 724 sendNextBroadcast(); 725 } 726 } 727 728 private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() { 729 @Override 730 public void onReceive(Context context, Intent intent) { 731 EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, 732 SystemClock.uptimeMillis() - mBroadcastStartTime, 1); 733 sendNextBroadcast(); 734 } 735 }; 736 737 /** 738 * Plays the wireless charging sound for both wireless and non-wireless charging 739 */ playChargingStartedSound()740 private void playChargingStartedSound() { 741 final String soundPath = Settings.Global.getString(mContext.getContentResolver(), 742 Settings.Global.CHARGING_STARTED_SOUND); 743 if (isChargingFeedbackEnabled() && soundPath != null) { 744 final Uri soundUri = Uri.parse("file://" + soundPath); 745 if (soundUri != null) { 746 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 747 if (sfx != null) { 748 sfx.setStreamType(AudioManager.STREAM_SYSTEM); 749 sfx.play(); 750 } 751 } 752 } 753 } 754 showWirelessChargingStarted(int batteryLevel)755 private void showWirelessChargingStarted(int batteryLevel) { 756 playWirelessChargingVibration(); 757 playChargingStartedSound(); 758 if (mStatusBarManagerInternal != null) { 759 mStatusBarManagerInternal.showChargingAnimation(batteryLevel); 760 } 761 mSuspendBlocker.release(); 762 } 763 showWiredChargingStarted()764 private void showWiredChargingStarted() { 765 playChargingStartedSound(); 766 mSuspendBlocker.release(); 767 } 768 lockProfile(@serIdInt int userId)769 private void lockProfile(@UserIdInt int userId) { 770 mTrustManager.setDeviceLockedForUser(userId, true /*locked*/); 771 } 772 playWirelessChargingVibration()773 private void playWirelessChargingVibration() { 774 final boolean vibrateEnabled = Settings.Global.getInt(mContext.getContentResolver(), 775 Settings.Global.CHARGING_VIBRATION_ENABLED, 0) != 0; 776 if (vibrateEnabled && isChargingFeedbackEnabled()) { 777 mVibrator.vibrate(WIRELESS_CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES); 778 } 779 } 780 isChargingFeedbackEnabled()781 private boolean isChargingFeedbackEnabled() { 782 final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(), 783 Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0; 784 final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(), 785 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) 786 == Settings.Global.ZEN_MODE_OFF; 787 return enabled && dndOff; 788 } 789 790 private final class NotifierHandler extends Handler { 791 NotifierHandler(Looper looper)792 public NotifierHandler(Looper looper) { 793 super(looper, null, true /*async*/); 794 } 795 @Override handleMessage(Message msg)796 public void handleMessage(Message msg) { 797 switch (msg.what) { 798 case MSG_USER_ACTIVITY: 799 sendUserActivity(); 800 break; 801 case MSG_BROADCAST: 802 sendNextBroadcast(); 803 break; 804 case MSG_WIRELESS_CHARGING_STARTED: 805 showWirelessChargingStarted(msg.arg1); 806 break; 807 case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED: 808 sendBrightnessBoostChangedBroadcast(); 809 break; 810 case MSG_PROFILE_TIMED_OUT: 811 lockProfile(msg.arg1); 812 break; 813 case MSG_WIRED_CHARGING_STARTED: 814 showWiredChargingStarted(); 815 break; 816 } 817 } 818 } 819 } 820