1 /* 2 * Copyright (C) 2017 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.systemui.doze; 18 19 import android.os.Handler; 20 import android.util.Log; 21 import android.view.Display; 22 23 import com.android.systemui.statusbar.phone.DozeParameters; 24 import com.android.systemui.util.wakelock.SettableWakeLock; 25 import com.android.systemui.util.wakelock.WakeLock; 26 27 /** 28 * Controls the screen when dozing. 29 */ 30 public class DozeScreenState implements DozeMachine.Part { 31 32 private static final boolean DEBUG = DozeService.DEBUG; 33 private static final String TAG = "DozeScreenState"; 34 35 /** 36 * Delay entering low power mode when animating to make sure that we'll have 37 * time to move all elements into their final positions while still at 60 fps. 38 */ 39 private static final int ENTER_DOZE_DELAY = 6000; 40 /** 41 * Hide wallpaper earlier when entering low power mode. The gap between 42 * hiding the wallpaper and changing the display mode is necessary to hide 43 * the black frame that's inherent to hardware specs. 44 */ 45 public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 4500; 46 47 private final DozeMachine.Service mDozeService; 48 private final Handler mHandler; 49 private final Runnable mApplyPendingScreenState = this::applyPendingScreenState; 50 private final DozeParameters mParameters; 51 52 private int mPendingScreenState = Display.STATE_UNKNOWN; 53 private SettableWakeLock mWakeLock; 54 DozeScreenState(DozeMachine.Service service, Handler handler, DozeParameters parameters, WakeLock wakeLock)55 public DozeScreenState(DozeMachine.Service service, Handler handler, 56 DozeParameters parameters, WakeLock wakeLock) { 57 mDozeService = service; 58 mHandler = handler; 59 mParameters = parameters; 60 mWakeLock = new SettableWakeLock(wakeLock, TAG); 61 } 62 63 @Override transitionTo(DozeMachine.State oldState, DozeMachine.State newState)64 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { 65 int screenState = newState.screenState(mParameters); 66 67 if (newState == DozeMachine.State.FINISH) { 68 // Make sure not to apply the screen state after DozeService was destroyed. 69 mPendingScreenState = Display.STATE_UNKNOWN; 70 mHandler.removeCallbacks(mApplyPendingScreenState); 71 72 applyScreenState(screenState); 73 mWakeLock.setAcquired(false); 74 return; 75 } 76 77 if (screenState == Display.STATE_UNKNOWN) { 78 // We'll keep it in the existing state 79 return; 80 } 81 82 boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState); 83 boolean pulseEnding = oldState == DozeMachine.State.DOZE_PULSE_DONE 84 && newState == DozeMachine.State.DOZE_AOD; 85 if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) { 86 // During initialization, we hide the navigation bar. That is however only applied after 87 // a traversal; setting the screen state here is immediate however, so it can happen 88 // that the screen turns on again before the navigation bar is hidden. To work around 89 // that, wait for a traversal to happen before applying the initial screen state. 90 mPendingScreenState = screenState; 91 92 // Delay screen state transitions even longer while animations are running. 93 boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD 94 && mParameters.shouldControlScreenOff(); 95 96 if (shouldDelayTransition) { 97 mWakeLock.setAcquired(true); 98 } 99 100 if (!messagePending) { 101 if (DEBUG) { 102 Log.d(TAG, "Display state changed to " + screenState + " delayed by " 103 + (shouldDelayTransition ? ENTER_DOZE_DELAY : 1)); 104 } 105 106 if (shouldDelayTransition) { 107 mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY); 108 } else { 109 mHandler.post(mApplyPendingScreenState); 110 } 111 } else if (DEBUG) { 112 Log.d(TAG, "Pending display state change to " + screenState); 113 } 114 } else { 115 applyScreenState(screenState); 116 } 117 } 118 applyPendingScreenState()119 private void applyPendingScreenState() { 120 applyScreenState(mPendingScreenState); 121 mPendingScreenState = Display.STATE_UNKNOWN; 122 } 123 applyScreenState(int screenState)124 private void applyScreenState(int screenState) { 125 if (screenState != Display.STATE_UNKNOWN) { 126 if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")"); 127 mDozeService.setDozeScreenState(screenState); 128 mPendingScreenState = Display.STATE_UNKNOWN; 129 mWakeLock.setAcquired(false); 130 } 131 } 132 } 133