19630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/*
29630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Copyright (C) 2012 The Android Open Source Project
39630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
49630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
59630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * you may not use this file except in compliance with the License.
69630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * You may obtain a copy of the License at
79630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
89630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
99630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown *
109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Unless required by applicable law or agreed to in writing, software
119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * See the License for the specific language governing permissions and
149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * limitations under the License.
159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */
169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownpackage com.android.server.power;
189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brownimport com.android.server.LightsService;
2032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
2132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brownimport android.os.AsyncTask;
2232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brownimport android.os.Handler;
239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.os.Looper;
249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.os.PowerManager;
259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.FloatProperty;
269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.IntProperty;
279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.Slog;
289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.Choreographer;
299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport java.io.PrintWriter;
319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/**
3332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * Controls the display power state.
3432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * <p>
359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * This component is similar in nature to a {@link View} except that it describes
369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * the properties of a display.  When properties are changed, the component
3732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * invalidates itself and posts a callback to apply the changes in a consistent order.
3832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * This mechanism enables multiple properties of the display power state to be animated
3932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * together smoothly by the animation framework.  Some of the work to blank or unblank
4032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * the display is done on a separate thread to avoid blocking the looper.
4132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * </p><p>
429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * This component must only be created or accessed by the {@link Looper} thread
439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * that belongs to the {@link DisplayPowerController}.
4432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * </p><p>
459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * We don't need to worry about holding a suspend blocker here because the
4632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * {@link PowerManagerService} does that for us whenever there is a change
4732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * in progress.
4832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown * </p>
499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */
509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownfinal class DisplayPowerState {
519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static final String TAG = "DisplayPowerState";
529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private static boolean DEBUG = false;
549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
5532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final Handler mHandler;
569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private final Choreographer mChoreographer;
578b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    private final ElectronBeam mElectronBeam;
589e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown    private final DisplayBlanker mDisplayBlanker;
5932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final LightsService.Light mBacklight;
6032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final PhotonicModulator mPhotonicModulator;
619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private boolean mScreenOn;
639630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private int mScreenBrightness;
6432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private boolean mScreenReady;
6532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private boolean mScreenUpdatePending;
6632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
6732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private boolean mElectronBeamPrepared;
6832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private float mElectronBeamLevel;
6932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private boolean mElectronBeamReady;
7032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private boolean mElectronBeamDrawPending;
719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
729630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    private Runnable mCleanListener;
739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public DisplayPowerState(ElectronBeam electronBean,
7532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            DisplayBlanker displayBlanker, LightsService.Light backlight) {
7632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mHandler = new Handler(true /*async*/);
779630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mChoreographer = Choreographer.getInstance();
789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mElectronBeam = electronBean;
799e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        mDisplayBlanker = displayBlanker;
8032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mBacklight = backlight;
8132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mPhotonicModulator = new PhotonicModulator();
829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
83f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // At boot time, we know that the screen is on and the electron beam
84f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // animation is not playing.  We don't know the screen's brightness though,
85f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // so prepare to set it to a known state when the state is next applied.
86f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // Although we set the brightness to full on here, the display power controller
87f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // will reset the brightness to a new level immediately before the changes
88f75724b3d36d84c881d4052cfd4be766d454c98fJeff Brown        // actually have a chance to be applied.
899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mScreenOn = true;
909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        mScreenBrightness = PowerManager.BRIGHTNESS_ON;
9132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        scheduleScreenUpdate();
9232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
9332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamPrepared = false;
9432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamLevel = 1.0f;
9532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamReady = true;
969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            new FloatProperty<DisplayPowerState>("electronBeamLevel") {
1009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        @Override
1019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        public void setValue(DisplayPowerState object, float value) {
1029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            object.setElectronBeamLevel(value);
1039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        @Override
1069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        public Float get(DisplayPowerState object) {
1079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return object.getElectronBeamLevel();
1089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    };
1109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
1129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            new IntProperty<DisplayPowerState>("screenBrightness") {
1139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        @Override
1149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        public void setValue(DisplayPowerState object, int value) {
1159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            object.setScreenBrightness(value);
1169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        @Override
1199630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        public Integer get(DisplayPowerState object) {
1209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return object.getScreenBrightness();
1219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    };
1239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
1259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Sets whether the screen is on or off.
1269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void setScreenOn(boolean on) {
1289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mScreenOn != on) {
1299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (DEBUG) {
1309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                Slog.d(TAG, "setScreenOn: on=" + on);
1319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
1329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mScreenOn = on;
13432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mScreenReady = false;
13532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            scheduleScreenUpdate();
1369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
1379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
1409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Returns true if the screen is on.
1419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public boolean isScreenOn() {
1439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return mScreenOn;
1449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
14732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     * Sets the display brightness.
14832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     *
14932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
15032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     */
15132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    public void setScreenBrightness(int brightness) {
15232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (mScreenBrightness != brightness) {
15332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            if (DEBUG) {
15432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
15532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            }
15632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
15732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mScreenBrightness = brightness;
15832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            if (mScreenOn) {
15932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                mScreenReady = false;
16032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                scheduleScreenUpdate();
16132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            }
16232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
16332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
16432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
16532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    /**
16632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     * Gets the screen brightness.
16732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     */
16832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    public int getScreenBrightness() {
16932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        return mScreenBrightness;
17032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
17132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
17232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    /**
1739630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Prepares the electron beam to turn on or off.
1749630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * This method should be called before starting an animation because it
1759630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * can take a fair amount of time to prepare the electron beam surface.
1769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
1778b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown     * @param mode The electron beam animation mode to prepare.
1789630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @return True if the electron beam was prepared.
1799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1808b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown    public boolean prepareElectronBeam(int mode) {
18132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (!mElectronBeam.prepare(mode)) {
18232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mElectronBeamPrepared = false;
18332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mElectronBeamReady = true;
18432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            return false;
18532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
18632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
18732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamPrepared = true;
18832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamReady = false;
18932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        scheduleElectronBeamDraw();
19032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        return true;
1919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
1929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
1939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
1949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Dismisses the electron beam surface.
1959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
1969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void dismissElectronBeam() {
1978b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        mElectronBeam.dismiss();
19832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamPrepared = false;
19932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mElectronBeamReady = true;
2009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
2039630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Sets the level of the electron beam steering current.
2049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
2059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * The display is blanked when the level is 0.0.  In normal use, the electron
2069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * beam should have a value of 1.0.  The electron beam is unstable in between
2079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * these states and the picture quality may be compromised.  For best effect,
2089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * the electron beam should be warmed up or cooled off slowly.
2099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
2109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Warning: Electron beam emits harmful radiation.  Avoid direct exposure to
2119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * skin or eyes.
2129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     *
2139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
2149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
2159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void setElectronBeamLevel(float level) {
2169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        if (mElectronBeamLevel != level) {
2179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            if (DEBUG) {
2189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown                Slog.d(TAG, "setElectronBeamLevel: level=" + level);
2199630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
2209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mElectronBeamLevel = level;
22232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            if (mScreenOn) {
22332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                mScreenReady = false;
22432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                scheduleScreenUpdate(); // update backlight brightness
22532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            }
22632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            if (mElectronBeamPrepared) {
22732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                mElectronBeamReady = false;
22832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                scheduleElectronBeamDraw();
22932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            }
2309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
2349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Gets the level of the electron beam steering current.
2359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
2369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public float getElectronBeamLevel() {
2379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        return mElectronBeamLevel;
2389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    /**
2419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Returns true if no properties have been invalidated.
2429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * Otherwise, returns false and promises to invoke the specified listener
2439630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * when the properties have all been applied.
2449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     * The listener always overrides any previously set listener.
2459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown     */
2469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public boolean waitUntilClean(Runnable listener) {
24732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (!mScreenReady || !mElectronBeamReady) {
2489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mCleanListener = listener;
2499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return false;
2509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        } else {
2519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mCleanListener = null;
2529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            return true;
2539630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
2549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
2569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    public void dump(PrintWriter pw) {
2579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println();
2589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("Display Power State:");
2599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mScreenOn=" + mScreenOn);
2609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mScreenBrightness=" + mScreenBrightness);
26132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        pw.println("  mScreenReady=" + mScreenReady);
26232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
26332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        pw.println("  mElectronBeamPrepared=" + mElectronBeamPrepared);
2649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        pw.println("  mElectronBeamLevel=" + mElectronBeamLevel);
26532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        pw.println("  mElectronBeamReady=" + mElectronBeamReady);
26632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        pw.println("  mElectronBeamDrawPending=" + mElectronBeamDrawPending);
2679630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
26832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mPhotonicModulator.dump(pw);
2698b9cf1c8000eb581457713a5c0ce41c59f90c353Jeff Brown        mElectronBeam.dump(pw);
2709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
27232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private void scheduleScreenUpdate() {
27332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (!mScreenUpdatePending) {
27432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mScreenUpdatePending = true;
27532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            postScreenUpdateThreadSafe();
27632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
27732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
27832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
27932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private void postScreenUpdateThreadSafe() {
28032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mHandler.removeCallbacks(mScreenUpdateRunnable);
28132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        mHandler.post(mScreenUpdateRunnable);
28232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
28332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
28432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private void scheduleElectronBeamDraw() {
28532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (!mElectronBeamDrawPending) {
28632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mElectronBeamDrawPending = true;
2879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
28832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    mElectronBeamDrawRunnable, null);
2899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
29032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
2919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
29232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private void invokeCleanListenerIfNeeded() {
29332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        final Runnable listener = mCleanListener;
29432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        if (listener != null && mScreenReady && mElectronBeamReady) {
29532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mCleanListener = null;
29632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            listener.run();
29732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
2989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown    }
2999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
30032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final Runnable mScreenUpdateRunnable = new Runnable() {
30132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        @Override
30232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        public void run() {
30332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mScreenUpdatePending = false;
3049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
305356bd4cf2c6db38c61c79e81fd5d9d119d299b8dJeff Brown            int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
306356bd4cf2c6db38c61c79e81fd5d9d119d299b8dJeff Brown            if (mPhotonicModulator.setState(mScreenOn, brightness)) {
30732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                mScreenReady = true;
30832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                invokeCleanListenerIfNeeded();
3099630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
31032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
31132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    };
3129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
31332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final Runnable mElectronBeamDrawRunnable = new Runnable() {
31432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        @Override
31532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        public void run() {
31632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mElectronBeamDrawPending = false;
3179630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
31832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            if (mElectronBeamPrepared) {
31932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                mElectronBeam.draw(mElectronBeamLevel);
320735f740fe81b7172d0b208d584eecf632533ec4aJeff Brown            }
321735f740fe81b7172d0b208d584eecf632533ec4aJeff Brown
32232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            mElectronBeamReady = true;
32332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            invokeCleanListenerIfNeeded();
32432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        }
32532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    };
3269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
32732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    /**
32832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     * Updates the state of the screen and backlight asynchronously on a separate thread.
32932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown     */
33032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    private final class PhotonicModulator {
33132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
33232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private static final int INITIAL_BACKLIGHT = -1; // unknown
33332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
33432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private final Object mLock = new Object();
33532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
33632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private boolean mPendingOn = INITIAL_SCREEN_ON;
33732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private int mPendingBacklight = INITIAL_BACKLIGHT;
33832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private boolean mActualOn = INITIAL_SCREEN_ON;
33932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private int mActualBacklight = INITIAL_BACKLIGHT;
34032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private boolean mChangeInProgress;
34132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
34232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        public boolean setState(boolean on, int backlight) {
34332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            synchronized (mLock) {
34432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                if (on != mPendingOn || backlight != mPendingBacklight) {
34532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (DEBUG) {
34632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        Slog.d(TAG, "Requesting new screen state: on=" + on
34732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                                + ", backlight=" + backlight);
34832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
34932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
35032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    mPendingOn = on;
35132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    mPendingBacklight = backlight;
35232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
35332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (!mChangeInProgress) {
35432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mChangeInProgress = true;
35532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask);
35632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
35732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                }
35832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                return mChangeInProgress;
3599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown            }
3609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
3619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown
36232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        public void dump(PrintWriter pw) {
36332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println();
36432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("Photonic Modulator State:");
36532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("  mPendingOn=" + mPendingOn);
36632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("  mPendingBacklight=" + mPendingBacklight);
36732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("  mActualOn=" + mActualOn);
36832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("  mActualBacklight=" + mActualBacklight);
36932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            pw.println("  mChangeInProgress=" + mChangeInProgress);
3709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown        }
37132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
37232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        private final Runnable mTask = new Runnable() {
37332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            @Override
37432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            public void run() {
37532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                // Apply pending changes until done.
37632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                for (;;) {
37732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    final boolean on;
37832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    final boolean onChanged;
37932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    final int backlight;
38032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    final boolean backlightChanged;
38132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    synchronized (mLock) {
38232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        on = mPendingOn;
38332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        onChanged = (on != mActualOn);
38432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        backlight = mPendingBacklight;
38532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        backlightChanged = (backlight != mActualBacklight);
38632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        if (!onChanged && !backlightChanged) {
38732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                            mChangeInProgress = false;
38832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                            break;
38932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        }
39032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mActualOn = on;
39132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mActualBacklight = backlight;
39232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
39332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
39432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (DEBUG) {
39532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        Slog.d(TAG, "Updating screen state: on=" + on
39632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                                + ", backlight=" + backlight);
39732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
39832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (onChanged && on) {
39932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mDisplayBlanker.unblankAllDisplays();
40032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
40132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (backlightChanged) {
40232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mBacklight.setBrightness(backlight);
40332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
40432dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    if (onChanged && !on) {
40532dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                        mDisplayBlanker.blankAllDisplays();
40632dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                    }
40732dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                }
40832dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown
40932dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                // Let the outer class know that all changes have been applied.
41032dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown                postScreenUpdateThreadSafe();
41132dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown            }
41232dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown        };
41332dafe25ac2e06f127f48d6a5826537e11575f52Jeff Brown    }
4149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown}
415