12981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos/*
22981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * Copyright (C) 2017 The Android Open Source Project
32981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos *
42981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * Licensed under the Apache License, Version 2.0 (the "License");
52981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * you may not use this file except in compliance with the License.
62981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * You may obtain a copy of the License at
72981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos *
82981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos *      http://www.apache.org/licenses/LICENSE-2.0
92981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos *
102981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * Unless required by applicable law or agreed to in writing, software
112981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * distributed under the License is distributed on an "AS IS" BASIS,
122981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * See the License for the specific language governing permissions and
142981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * limitations under the License
152981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos */
162981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos
172981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roospackage com.android.systemui.doze;
182981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos
198db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roosimport android.os.Handler;
205854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupinimport android.util.Log;
212981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roosimport android.view.Display;
222981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos
2312663d30baa5d691f3d132d9242e6186b0791807Lucas Dupinimport com.android.systemui.statusbar.phone.DozeParameters;
2439880be88c3b40c45e189199d7b7a633410bd85dAdrian Roosimport com.android.systemui.util.wakelock.SettableWakeLock;
2516cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupinimport com.android.systemui.util.wakelock.WakeLock;
2612663d30baa5d691f3d132d9242e6186b0791807Lucas Dupin
272981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos/**
282981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos * Controls the screen when dozing.
292981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos */
302981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roospublic class DozeScreenState implements DozeMachine.Part {
315854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupin
325854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupin    private static final boolean DEBUG = DozeService.DEBUG;
335854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupin    private static final String TAG = "DozeScreenState";
345854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupin
3516cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin    /**
3616cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin     * Delay entering low power mode when animating to make sure that we'll have
3716cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin     * time to move all elements into their final positions while still at 60 fps.
3816cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin     */
39cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin    private static final int ENTER_DOZE_DELAY = 6000;
40cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin    /**
41cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin     * Hide wallpaper earlier when entering low power mode. The gap between
42cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin     * hiding the wallpaper and changing the display mode is necessary to hide
43cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin     * the black frame that's inherent to hardware specs.
44cbe0596c4d7d438ac840fffe4b819ef5f5bea6f9Lucas Dupin     */
4561b8eaf289e736cbc40f489c8c6f270daf094dd1Lucas Dupin    public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 4500;
4616cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin
472981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos    private final DozeMachine.Service mDozeService;
488db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    private final Handler mHandler;
49a79ad59d49cdb3ef6f4cf864094063e3e9111586Adrian Roos    private final Runnable mApplyPendingScreenState = this::applyPendingScreenState;
5012663d30baa5d691f3d132d9242e6186b0791807Lucas Dupin    private final DozeParameters mParameters;
51a79ad59d49cdb3ef6f4cf864094063e3e9111586Adrian Roos
528db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    private int mPendingScreenState = Display.STATE_UNKNOWN;
5339880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos    private SettableWakeLock mWakeLock;
542981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos
5512663d30baa5d691f3d132d9242e6186b0791807Lucas Dupin    public DozeScreenState(DozeMachine.Service service, Handler handler,
5616cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            DozeParameters parameters, WakeLock wakeLock) {
572981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos        mDozeService = service;
588db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        mHandler = handler;
5912663d30baa5d691f3d132d9242e6186b0791807Lucas Dupin        mParameters = parameters;
6039880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos        mWakeLock = new SettableWakeLock(wakeLock);
612981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos    }
622981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos
632981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos    @Override
642981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos    public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
6512663d30baa5d691f3d132d9242e6186b0791807Lucas Dupin        int screenState = newState.screenState(mParameters);
665502b8942f15e7141686a623f6176339e2389b8dAdrian Roos
675502b8942f15e7141686a623f6176339e2389b8dAdrian Roos        if (newState == DozeMachine.State.FINISH) {
685502b8942f15e7141686a623f6176339e2389b8dAdrian Roos            // Make sure not to apply the screen state after DozeService was destroyed.
695502b8942f15e7141686a623f6176339e2389b8dAdrian Roos            mPendingScreenState = Display.STATE_UNKNOWN;
705502b8942f15e7141686a623f6176339e2389b8dAdrian Roos            mHandler.removeCallbacks(mApplyPendingScreenState);
715502b8942f15e7141686a623f6176339e2389b8dAdrian Roos
725502b8942f15e7141686a623f6176339e2389b8dAdrian Roos            applyScreenState(screenState);
7339880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos            mWakeLock.setAcquired(false);
745502b8942f15e7141686a623f6176339e2389b8dAdrian Roos            return;
755502b8942f15e7141686a623f6176339e2389b8dAdrian Roos        }
765502b8942f15e7141686a623f6176339e2389b8dAdrian Roos
778db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        if (screenState == Display.STATE_UNKNOWN) {
788db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            // We'll keep it in the existing state
798db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            return;
808db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        }
815502b8942f15e7141686a623f6176339e2389b8dAdrian Roos
828db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
833d7ccaf8b5e81378770cb3e18ff66d19418b8135Lucas Dupin        boolean pulseEnding = oldState  == DozeMachine.State.DOZE_PULSE_DONE
843d7ccaf8b5e81378770cb3e18ff66d19418b8135Lucas Dupin                && newState == DozeMachine.State.DOZE_AOD;
853d7ccaf8b5e81378770cb3e18ff66d19418b8135Lucas Dupin        if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) {
868db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            // During initialization, we hide the navigation bar. That is however only applied after
878db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            // a traversal; setting the screen state here is immediate however, so it can happen
888db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            // that the screen turns on again before the navigation bar is hidden. To work around
898db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            // that, wait for a traversal to happen before applying the initial screen state.
908db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            mPendingScreenState = screenState;
9116cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin
9216cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            // Delay screen state transitions even longer while animations are running.
9316cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD
9416cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                    && mParameters.shouldControlScreenOff();
9516cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin
9639880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos            if (shouldDelayTransition) {
9739880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos                mWakeLock.setAcquired(true);
9816cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            }
9916cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin
1008db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            if (!messagePending) {
10116cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                if (DEBUG) {
10216cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                    Log.d(TAG, "Display state changed to " + screenState + " delayed by "
10316cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                            + (shouldDelayTransition ? ENTER_DOZE_DELAY : 1));
10416cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                }
10516cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin
10616cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                if (shouldDelayTransition) {
10716cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                    mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY);
10816cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                } else {
10916cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                    mHandler.post(mApplyPendingScreenState);
11016cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                }
11116cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            } else if (DEBUG) {
11216cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin                Log.d(TAG, "Pending display state change to " + screenState);
1138db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            }
11416cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin        } else {
11516cfe45dec96154d37b36364f67cedce16ca2484Lucas Dupin            applyScreenState(screenState);
1168db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        }
1178db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    }
1188db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos
1198db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    private void applyPendingScreenState() {
1208db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        applyScreenState(mPendingScreenState);
1218db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos        mPendingScreenState = Display.STATE_UNKNOWN;
1228db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    }
1238db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos
1248db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos    private void applyScreenState(int screenState) {
1252981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos        if (screenState != Display.STATE_UNKNOWN) {
1265854384a6a32a2e7753a0442453045a66ee3e98fLucas Dupin            if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")");
1272981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos            mDozeService.setDozeScreenState(screenState);
1288db9311cb683c58b7d61f812ae4975feca926aa4Adrian Roos            mPendingScreenState = Display.STATE_UNKNOWN;
12939880be88c3b40c45e189199d7b7a633410bd85dAdrian Roos            mWakeLock.setAcquired(false);
1302981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos        }
1312981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos    }
1322981eb0d59f3568bfe84ce905c82fc17d62d21c5Adrian Roos}
133