1 /* 2 * Copyright (C) 2015 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 package com.android.car; 17 18 import android.os.Handler; 19 import android.os.HandlerThread; 20 import android.os.Looper; 21 import android.os.Message; 22 import android.os.SystemClock; 23 import android.util.Log; 24 25 import com.android.car.hal.PowerHalService; 26 import com.android.car.hal.PowerHalService.PowerState; 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.internal.annotations.VisibleForTesting; 29 30 import java.io.PrintWriter; 31 import java.util.LinkedList; 32 import java.util.Timer; 33 import java.util.TimerTask; 34 import java.util.concurrent.CopyOnWriteArrayList; 35 36 public class CarPowerManagementService implements CarServiceBase, 37 PowerHalService.PowerEventListener { 38 39 /** 40 * Listener for other services to monitor power events. 41 */ 42 public interface PowerServiceEventListener { 43 /** 44 * Shutdown is happening 45 */ onShutdown()46 void onShutdown(); 47 48 /** 49 * Entering deep sleep. 50 */ onSleepEntry()51 void onSleepEntry(); 52 53 /** 54 * Got out of deep sleep. 55 */ onSleepExit()56 void onSleepExit(); 57 } 58 59 /** 60 * Interface for components requiring processing time before shutting-down or 61 * entering sleep, and wake-up after shut-down. 62 */ 63 public interface PowerEventProcessingHandler { 64 /** 65 * Called before shutdown or sleep entry to allow running some processing. This call 66 * should only queue such task in different thread and should return quickly. 67 * Blocking inside this call can trigger watchdog timer which can terminate the 68 * whole system. 69 * @param shuttingDown whether system is shutting down or not (= sleep entry). 70 * @return time necessary to run processing in ms. should return 0 if there is no 71 * processing necessary. 72 */ onPrepareShutdown(boolean shuttingDown)73 long onPrepareShutdown(boolean shuttingDown); 74 75 /** 76 * Called when power state is changed to ON state. Display can be either on or off. 77 * @param displayOn 78 */ onPowerOn(boolean displayOn)79 void onPowerOn(boolean displayOn); 80 81 /** 82 * Returns wake up time after system is fully shutdown. Power controller will power on 83 * the system after this time. This power on is meant for regular maintenance kind of 84 * operation. 85 * @return 0 of wake up is not necessary. 86 */ getWakeupTime()87 int getWakeupTime(); 88 } 89 90 private final PowerHalService mHal; 91 private final SystemInterface mSystemInterface; 92 93 private final CopyOnWriteArrayList<PowerServiceEventListener> mListeners = 94 new CopyOnWriteArrayList<>(); 95 private final CopyOnWriteArrayList<PowerEventProcessingHandlerWrapper> 96 mPowerEventProcessingHandlers = new CopyOnWriteArrayList<>(); 97 98 @GuardedBy("this") 99 private PowerState mCurrentState; 100 @GuardedBy("this") 101 private Timer mTimer; 102 @GuardedBy("this") 103 private long mProcessingStartTime; 104 @GuardedBy("this") 105 private long mLastSleepEntryTime; 106 @GuardedBy("this") 107 private final LinkedList<PowerState> mPendingPowerStates = new LinkedList<>(); 108 @GuardedBy("this") 109 private HandlerThread mHandlerThread; 110 @GuardedBy("this") 111 private PowerHandler mHandler; 112 113 private final static int SHUTDOWN_POLLING_INTERVAL_MS = 2000; 114 private final static int SHUTDOWN_EXTEND_MAX_MS = 5000; 115 CarPowerManagementService(PowerHalService powerHal, SystemInterface systemInterface)116 public CarPowerManagementService(PowerHalService powerHal, SystemInterface systemInterface) { 117 mHal = powerHal; 118 mSystemInterface = systemInterface; 119 } 120 121 /** 122 * Create a dummy instance for unit testing purpose only. Instance constructed in this way 123 * is not safe as members expected to be non-null are null. 124 */ 125 @VisibleForTesting CarPowerManagementService()126 protected CarPowerManagementService() { 127 mHal = null; 128 mSystemInterface = null; 129 mHandlerThread = null; 130 mHandler = new PowerHandler(Looper.getMainLooper()); 131 } 132 133 @Override init()134 public void init() { 135 synchronized (this) { 136 mHandlerThread = new HandlerThread(CarLog.TAG_POWER); 137 mHandlerThread.start(); 138 mHandler = new PowerHandler(mHandlerThread.getLooper()); 139 } 140 141 mHal.setListener(this); 142 if (mHal.isPowerStateSupported()) { 143 mHal.sendBootComplete(); 144 PowerState currentState = mHal.getCurrentPowerState(); 145 if (currentState != null) { 146 onApPowerStateChange(currentState); 147 } else { 148 Log.w(CarLog.TAG_POWER, "Unable to get get current power state during " 149 + "initialization"); 150 } 151 } else { 152 Log.w(CarLog.TAG_POWER, "Vehicle hal does not support power state yet."); 153 onApPowerStateChange(new PowerState(PowerHalService.STATE_ON_FULL, 0)); 154 mSystemInterface.switchToFullWakeLock(); 155 } 156 mSystemInterface.startDisplayStateMonitoring(this); 157 } 158 159 @Override release()160 public void release() { 161 HandlerThread handlerThread; 162 synchronized (this) { 163 releaseTimerLocked(); 164 mCurrentState = null; 165 mHandler.cancelAll(); 166 handlerThread = mHandlerThread; 167 } 168 handlerThread.quitSafely(); 169 try { 170 handlerThread.join(1000); 171 } catch (InterruptedException e) { 172 Log.e(CarLog.TAG_POWER, "Timeout while joining for handler thread to join."); 173 } 174 mSystemInterface.stopDisplayStateMonitoring(); 175 mListeners.clear(); 176 mPowerEventProcessingHandlers.clear(); 177 mSystemInterface.releaseAllWakeLocks(); 178 } 179 180 /** 181 * Register listener to monitor power event. There is no unregister counter-part and the list 182 * will be cleared when the service is released. 183 * @param listener 184 */ registerPowerEventListener(PowerServiceEventListener listener)185 public synchronized void registerPowerEventListener(PowerServiceEventListener listener) { 186 mListeners.add(listener); 187 } 188 189 /** 190 * Register PowerEventPreprocessingHandler to run pre-processing before shutdown or 191 * sleep entry. There is no unregister counter-part and the list 192 * will be cleared when the service is released. 193 * @param handler 194 */ registerPowerEventProcessingHandler( PowerEventProcessingHandler handler)195 public synchronized void registerPowerEventProcessingHandler( 196 PowerEventProcessingHandler handler) { 197 mPowerEventProcessingHandlers.add(new PowerEventProcessingHandlerWrapper(handler)); 198 // onPowerOn will not be called if power on notification is already done inside the 199 // handler thread. So request it once again here. Wrapper will have its own 200 // gatekeeping to prevent calling onPowerOn twice. 201 mHandler.handlePowerOn(); 202 } 203 204 /** 205 * Notifies earlier completion of power event processing. PowerEventProcessingHandler quotes 206 * time necessary from onPrePowerEvent() call, but actual processing can finish earlier than 207 * that, and this call can be called in such case to trigger shutdown without waiting further. 208 * 209 * @param handler PowerEventProcessingHandler that was already registered with 210 * {@link #registerPowerEventListener(PowerServiceEventListener)} call. If it was not 211 * registered before, this call will be ignored. 212 */ notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler)213 public void notifyPowerEventProcessingCompletion(PowerEventProcessingHandler handler) { 214 long processingTime = 0; 215 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 216 if (wrapper.handler == handler) { 217 wrapper.markProcessingDone(); 218 } else if (!wrapper.isProcessingDone()) { 219 processingTime = Math.max(processingTime, wrapper.getProcessingTime()); 220 } 221 } 222 long now = SystemClock.elapsedRealtime(); 223 long startTime; 224 boolean shouldShutdown = true; 225 PowerHandler powerHandler; 226 synchronized (this) { 227 startTime = mProcessingStartTime; 228 if (mCurrentState == null) { 229 return; 230 } 231 if (mCurrentState.mState != PowerHalService.STATE_SHUTDOWN_PREPARE) { 232 return; 233 } 234 if (mCurrentState.canEnterDeepSleep()) { 235 shouldShutdown = false; 236 if (mLastSleepEntryTime > mProcessingStartTime && mLastSleepEntryTime < now) { 237 // already slept 238 return; 239 } 240 } 241 powerHandler = mHandler; 242 } 243 if ((startTime + processingTime) <= now) { 244 Log.i(CarLog.TAG_POWER, "Processing all done"); 245 powerHandler.handleProcessingComplete(shouldShutdown); 246 } 247 } 248 249 @Override dump(PrintWriter writer)250 public void dump(PrintWriter writer) { 251 writer.println("*PowerManagementService*"); 252 writer.print("mCurrentState:" + mCurrentState); 253 writer.print(",mProcessingStartTime:" + mProcessingStartTime); 254 writer.println(",mLastSleepEntryTime:" + mLastSleepEntryTime); 255 writer.println("**PowerEventProcessingHandlers"); 256 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 257 writer.println(wrapper.toString()); 258 } 259 } 260 261 @Override onApPowerStateChange(PowerState state)262 public void onApPowerStateChange(PowerState state) { 263 PowerHandler handler; 264 synchronized (this) { 265 mPendingPowerStates.addFirst(state); 266 handler = mHandler; 267 } 268 handler.handlePowerStateChange(); 269 } 270 doHandlePowerStateChange()271 private void doHandlePowerStateChange() { 272 PowerState state = null; 273 PowerHandler handler; 274 synchronized (this) { 275 state = mPendingPowerStates.peekFirst(); 276 mPendingPowerStates.clear(); 277 if (state == null) { 278 return; 279 } 280 if (!needPowerStateChange(state)) { 281 return; 282 } 283 // now real power change happens. Whatever was queued before should be all cancelled. 284 releaseTimerLocked(); 285 handler = mHandler; 286 } 287 handler.cancelProcessingComplete(); 288 289 Log.i(CarLog.TAG_POWER, "Power state change:" + state); 290 switch (state.mState) { 291 case PowerHalService.STATE_ON_DISP_OFF: 292 handleDisplayOff(state); 293 notifyPowerOn(false); 294 break; 295 case PowerHalService.STATE_ON_FULL: 296 handleFullOn(state); 297 notifyPowerOn(true); 298 break; 299 case PowerHalService.STATE_SHUTDOWN_PREPARE: 300 handleShutdownPrepare(state); 301 break; 302 } 303 } 304 handleDisplayOff(PowerState newState)305 private void handleDisplayOff(PowerState newState) { 306 setCurrentState(newState); 307 mSystemInterface.setDisplayState(false); 308 } 309 handleFullOn(PowerState newState)310 private void handleFullOn(PowerState newState) { 311 setCurrentState(newState); 312 mSystemInterface.setDisplayState(true); 313 } 314 315 @VisibleForTesting notifyPowerOn(boolean displayOn)316 protected void notifyPowerOn(boolean displayOn) { 317 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 318 wrapper.callOnPowerOn(displayOn); 319 } 320 } 321 322 @VisibleForTesting notifyPrepareShutdown(boolean shuttingDown)323 protected long notifyPrepareShutdown(boolean shuttingDown) { 324 long processingTimeMs = 0; 325 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 326 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown); 327 if (handlerProcessingTime > processingTimeMs) { 328 processingTimeMs = handlerProcessingTime; 329 } 330 } 331 return processingTimeMs; 332 } 333 handleShutdownPrepare(PowerState newState)334 private void handleShutdownPrepare(PowerState newState) { 335 setCurrentState(newState); 336 mSystemInterface.setDisplayState(false);; 337 boolean shouldShutdown = true; 338 if (mHal.isDeepSleepAllowed() && mSystemInterface.isSystemSupportingDeepSleep() && 339 newState.canEnterDeepSleep()) { 340 Log.i(CarLog.TAG_POWER, "starting sleep"); 341 shouldShutdown = false; 342 doHandlePreprocessing(shouldShutdown); 343 return; 344 } else if (newState.canPostponeShutdown()) { 345 Log.i(CarLog.TAG_POWER, "starting shutdown with processing"); 346 doHandlePreprocessing(shouldShutdown); 347 } else { 348 Log.i(CarLog.TAG_POWER, "starting shutdown immediately"); 349 synchronized (this) { 350 releaseTimerLocked(); 351 } 352 doHandleShutdown(); 353 } 354 } 355 releaseTimerLocked()356 private void releaseTimerLocked() { 357 if (mTimer != null) { 358 mTimer.cancel(); 359 } 360 mTimer = null; 361 } 362 doHandlePreprocessing(boolean shuttingDown)363 private void doHandlePreprocessing(boolean shuttingDown) { 364 long processingTimeMs = 0; 365 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 366 long handlerProcessingTime = wrapper.handler.onPrepareShutdown(shuttingDown); 367 if (handlerProcessingTime > 0) { 368 wrapper.setProcessingTimeAndResetProcessingDone(handlerProcessingTime); 369 } 370 if (handlerProcessingTime > processingTimeMs) { 371 processingTimeMs = handlerProcessingTime; 372 } 373 } 374 if (processingTimeMs > 0) { 375 int pollingCount = (int)(processingTimeMs / SHUTDOWN_POLLING_INTERVAL_MS) + 1; 376 Log.i(CarLog.TAG_POWER, "processing before shutdown expected for :" + processingTimeMs + 377 " ms, adding polling:" + pollingCount); 378 synchronized (this) { 379 mProcessingStartTime = SystemClock.elapsedRealtime(); 380 releaseTimerLocked(); 381 mTimer = new Timer(); 382 mTimer.scheduleAtFixedRate(new ShutdownProcessingTimerTask(shuttingDown, 383 pollingCount), 384 0 /*delay*/, 385 SHUTDOWN_POLLING_INTERVAL_MS); 386 } 387 } else { 388 PowerHandler handler; 389 synchronized (this) { 390 handler = mHandler; 391 } 392 handler.handleProcessingComplete(shuttingDown); 393 } 394 } 395 doHandleDeepSleep()396 private void doHandleDeepSleep() { 397 // keep holding partial wakelock to prevent entering sleep before enterDeepSleep call 398 // enterDeepSleep should force sleep entry even if wake lock is kept. 399 mSystemInterface.switchToPartialWakeLock(); 400 PowerHandler handler; 401 synchronized (this) { 402 handler = mHandler; 403 } 404 handler.cancelProcessingComplete(); 405 for (PowerServiceEventListener listener : mListeners) { 406 listener.onSleepEntry(); 407 } 408 int wakeupTimeSec = getWakeupTime(); 409 mHal.sendSleepEntry(); 410 synchronized (this) { 411 mLastSleepEntryTime = SystemClock.elapsedRealtime(); 412 } 413 mSystemInterface.enterDeepSleep(wakeupTimeSec); 414 mHal.sendSleepExit(); 415 for (PowerServiceEventListener listener : mListeners) { 416 listener.onSleepExit(); 417 } 418 if (mSystemInterface.isWakeupCausedByTimer()) { 419 doHandlePreprocessing(false /*shuttingDown*/); 420 } else { 421 PowerState currentState = mHal.getCurrentPowerState(); 422 if (currentState != null && needPowerStateChange(currentState)) { 423 onApPowerStateChange(currentState); 424 } else { // power controller woke-up but no power state change. Just shutdown. 425 Log.w(CarLog.TAG_POWER, "external sleep wake up, but no power state change:" + 426 currentState); 427 doHandleShutdown(); 428 } 429 } 430 } 431 doHandleNotifyPowerOn()432 private void doHandleNotifyPowerOn() { 433 boolean displayOn = false; 434 synchronized (this) { 435 if (mCurrentState != null && mCurrentState.mState == PowerHalService.STATE_ON_FULL) { 436 displayOn = true; 437 } 438 } 439 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 440 // wrapper will not send it forward if it is already called. 441 wrapper.callOnPowerOn(displayOn); 442 } 443 } 444 needPowerStateChange(PowerState newState)445 private boolean needPowerStateChange(PowerState newState) { 446 synchronized (this) { 447 if (mCurrentState != null && mCurrentState.equals(newState)) { 448 return false; 449 } 450 return true; 451 } 452 } 453 doHandleShutdown()454 private void doHandleShutdown() { 455 // now shutdown 456 for (PowerServiceEventListener listener : mListeners) { 457 listener.onShutdown(); 458 } 459 int wakeupTimeSec = 0; 460 if (mHal.isTimedWakeupAllowed()) { 461 wakeupTimeSec = getWakeupTime(); 462 } 463 mHal.sendShutdownStart(wakeupTimeSec); 464 mSystemInterface.shutdown(); 465 } 466 getWakeupTime()467 private int getWakeupTime() { 468 int wakeupTimeSec = 0; 469 for (PowerEventProcessingHandlerWrapper wrapper : mPowerEventProcessingHandlers) { 470 int t = wrapper.handler.getWakeupTime(); 471 if (t > wakeupTimeSec) { 472 wakeupTimeSec = t; 473 } 474 } 475 return wakeupTimeSec; 476 } 477 doHandleProcessingComplete(boolean shutdownWhenCompleted)478 private void doHandleProcessingComplete(boolean shutdownWhenCompleted) { 479 synchronized (this) { 480 releaseTimerLocked(); 481 if (!shutdownWhenCompleted && mLastSleepEntryTime > mProcessingStartTime) { 482 // entered sleep after processing start. So this could be duplicate request. 483 Log.w(CarLog.TAG_POWER, "Duplicate sleep entry request, ignore"); 484 return; 485 } 486 } 487 if (shutdownWhenCompleted) { 488 doHandleShutdown(); 489 } else { 490 doHandleDeepSleep(); 491 } 492 } 493 setCurrentState(PowerState state)494 private synchronized void setCurrentState(PowerState state) { 495 mCurrentState = state; 496 } 497 498 @Override onDisplayBrightnessChange(int brightness)499 public void onDisplayBrightnessChange(int brightness) { 500 // TODO bug: 32065231 501 } 502 doHandleDisplayBrightnessChange(int brightness)503 private void doHandleDisplayBrightnessChange(int brightness) { 504 //TODO bug: 32065231 505 } 506 doHandleMainDisplayStateChange(boolean on)507 private void doHandleMainDisplayStateChange(boolean on) { 508 //TODO bug: 32065231 509 } 510 handleMainDisplayChanged(boolean on)511 public void handleMainDisplayChanged(boolean on) { 512 PowerHandler handler; 513 synchronized (this) { 514 handler = mHandler; 515 } 516 handler.handleMainDisplayStateChange(on); 517 } 518 getHandler()519 public synchronized Handler getHandler() { 520 return mHandler; 521 } 522 523 private class PowerHandler extends Handler { 524 525 private final int MSG_POWER_STATE_CHANGE = 0; 526 private final int MSG_DISPLAY_BRIGHTNESS_CHANGE = 1; 527 private final int MSG_MAIN_DISPLAY_STATE_CHANGE = 2; 528 private final int MSG_PROCESSING_COMPLETE = 3; 529 private final int MSG_NOTIFY_POWER_ON = 4; 530 531 // Do not handle this immediately but with some delay as there can be a race between 532 // display off due to rear view camera and delivery to here. 533 private final long MAIN_DISPLAY_EVENT_DELAY_MS = 500; 534 PowerHandler(Looper looper)535 private PowerHandler(Looper looper) { 536 super(looper); 537 } 538 handlePowerStateChange()539 private void handlePowerStateChange() { 540 Message msg = obtainMessage(MSG_POWER_STATE_CHANGE); 541 sendMessage(msg); 542 } 543 handleDisplayBrightnessChange(int brightness)544 private void handleDisplayBrightnessChange(int brightness) { 545 Message msg = obtainMessage(MSG_DISPLAY_BRIGHTNESS_CHANGE, brightness, 0); 546 sendMessage(msg); 547 } 548 handleMainDisplayStateChange(boolean on)549 private void handleMainDisplayStateChange(boolean on) { 550 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 551 Message msg = obtainMessage(MSG_MAIN_DISPLAY_STATE_CHANGE, Boolean.valueOf(on)); 552 sendMessageDelayed(msg, MAIN_DISPLAY_EVENT_DELAY_MS); 553 } 554 handleProcessingComplete(boolean shutdownWhenCompleted)555 private void handleProcessingComplete(boolean shutdownWhenCompleted) { 556 removeMessages(MSG_PROCESSING_COMPLETE); 557 Message msg = obtainMessage(MSG_PROCESSING_COMPLETE, shutdownWhenCompleted ? 1 : 0, 0); 558 sendMessage(msg); 559 } 560 handlePowerOn()561 private void handlePowerOn() { 562 Message msg = obtainMessage(MSG_NOTIFY_POWER_ON); 563 sendMessage(msg); 564 } 565 cancelProcessingComplete()566 private void cancelProcessingComplete() { 567 removeMessages(MSG_PROCESSING_COMPLETE); 568 } 569 cancelAll()570 private void cancelAll() { 571 removeMessages(MSG_POWER_STATE_CHANGE); 572 removeMessages(MSG_DISPLAY_BRIGHTNESS_CHANGE); 573 removeMessages(MSG_MAIN_DISPLAY_STATE_CHANGE); 574 removeMessages(MSG_PROCESSING_COMPLETE); 575 removeMessages(MSG_NOTIFY_POWER_ON); 576 } 577 578 @Override handleMessage(Message msg)579 public void handleMessage(Message msg) { 580 switch (msg.what) { 581 case MSG_POWER_STATE_CHANGE: 582 doHandlePowerStateChange(); 583 break; 584 case MSG_DISPLAY_BRIGHTNESS_CHANGE: 585 doHandleDisplayBrightnessChange(msg.arg1); 586 break; 587 case MSG_MAIN_DISPLAY_STATE_CHANGE: 588 doHandleMainDisplayStateChange((Boolean) msg.obj); 589 break; 590 case MSG_PROCESSING_COMPLETE: 591 doHandleProcessingComplete(msg.arg1 == 1); 592 break; 593 case MSG_NOTIFY_POWER_ON: 594 doHandleNotifyPowerOn(); 595 break; 596 } 597 } 598 } 599 600 private class ShutdownProcessingTimerTask extends TimerTask { 601 private final boolean mShutdownWhenCompleted; 602 private final int mExpirationCount; 603 private int mCurrentCount; 604 ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount)605 private ShutdownProcessingTimerTask(boolean shutdownWhenCompleted, int expirationCount) { 606 mShutdownWhenCompleted = shutdownWhenCompleted; 607 mExpirationCount = expirationCount; 608 mCurrentCount = 0; 609 } 610 611 @Override run()612 public void run() { 613 mCurrentCount++; 614 if (mCurrentCount > mExpirationCount) { 615 PowerHandler handler; 616 synchronized (CarPowerManagementService.this) { 617 releaseTimerLocked(); 618 handler = mHandler; 619 } 620 handler.handleProcessingComplete(mShutdownWhenCompleted); 621 } else { 622 mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS); 623 } 624 } 625 } 626 627 private static class PowerEventProcessingHandlerWrapper { 628 public final PowerEventProcessingHandler handler; 629 private long mProcessingTime = 0; 630 private boolean mProcessingDone = true; 631 private boolean mPowerOnSent = false; 632 private int mLastDisplayState = -1; 633 PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler)634 public PowerEventProcessingHandlerWrapper(PowerEventProcessingHandler handler) { 635 this.handler = handler; 636 } 637 setProcessingTimeAndResetProcessingDone(long processingTime)638 public synchronized void setProcessingTimeAndResetProcessingDone(long processingTime) { 639 mProcessingTime = processingTime; 640 mProcessingDone = false; 641 } 642 getProcessingTime()643 public synchronized long getProcessingTime() { 644 return mProcessingTime; 645 } 646 markProcessingDone()647 public synchronized void markProcessingDone() { 648 mProcessingDone = true; 649 } 650 isProcessingDone()651 public synchronized boolean isProcessingDone() { 652 return mProcessingDone; 653 } 654 callOnPowerOn(boolean displayOn)655 public void callOnPowerOn(boolean displayOn) { 656 int newDisplayState = displayOn ? 1 : 0; 657 boolean shouldCall = false; 658 synchronized (this) { 659 if (!mPowerOnSent || (mLastDisplayState != newDisplayState)) { 660 shouldCall = true; 661 mPowerOnSent = true; 662 mLastDisplayState = newDisplayState; 663 } 664 } 665 if (shouldCall) { 666 handler.onPowerOn(displayOn); 667 } 668 } 669 670 @Override toString()671 public String toString() { 672 return "PowerEventProcessingHandlerWrapper [handler=" + handler + ", mProcessingTime=" 673 + mProcessingTime + ", mProcessingDone=" + mProcessingDone + "]"; 674 } 675 } 676 } 677