blob: dba45b39dbb10a32587557b05d5551fd95260122 [file] [log] [blame]
Jeff Brown96307042012-07-27 15:51:34 -07001/*
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
17package com.android.server.power;
18
19import android.os.Looper;
20import android.os.PowerManager;
21import android.util.FloatProperty;
22import android.util.IntProperty;
23import android.util.Slog;
24import android.view.Choreographer;
25
26import java.io.PrintWriter;
27
28/**
29 * Represents the current display power state and realizes it.
30 *
31 * This component is similar in nature to a {@link View} except that it describes
32 * the properties of a display. When properties are changed, the component
33 * invalidates itself and posts a callback to the {@link Choreographer} to
34 * apply the changes. This mechanism enables the display power state to be
35 * animated smoothly by the animation framework.
36 *
37 * This component must only be created or accessed by the {@link Looper} thread
38 * that belongs to the {@link DisplayPowerController}.
39 *
40 * We don't need to worry about holding a suspend blocker here because the
41 * {@link DisplayPowerController} does that for us whenever there is a pending invalidate.
42 */
43final class DisplayPowerState {
44 private static final String TAG = "DisplayPowerState";
45
46 private static boolean DEBUG = false;
47
48 private static final int DIRTY_SCREEN_ON = 1 << 0;
49 private static final int DIRTY_ELECTRON_BEAM = 1 << 1;
50 private static final int DIRTY_BRIGHTNESS = 1 << 2;
51
Jeff Brown96307042012-07-27 15:51:34 -070052 private final Choreographer mChoreographer;
Jeff Browna52772f2012-10-04 18:38:09 -070053 private final ElectronBeam mElectronBeam; // may be null if only animating backlights
Jeff Brown96307042012-07-27 15:51:34 -070054 private final PhotonicModulator mScreenBrightnessModulator;
55
56 private int mDirty;
57 private boolean mScreenOn;
58 private float mElectronBeamLevel;
59 private int mScreenBrightness;
60
61 private Runnable mCleanListener;
62
63 public DisplayPowerState(ElectronBeam electronBean,
64 PhotonicModulator screenBrightnessModulator) {
65 mChoreographer = Choreographer.getInstance();
66 mElectronBeam = electronBean;
67 mScreenBrightnessModulator = screenBrightnessModulator;
68
Jeff Brownf75724b2012-08-25 13:34:32 -070069 // At boot time, we know that the screen is on and the electron beam
70 // animation is not playing. We don't know the screen's brightness though,
71 // so prepare to set it to a known state when the state is next applied.
72 // Although we set the brightness to full on here, the display power controller
73 // will reset the brightness to a new level immediately before the changes
74 // actually have a chance to be applied.
Jeff Brown96307042012-07-27 15:51:34 -070075 mScreenOn = true;
76 mElectronBeamLevel = 1.0f;
77 mScreenBrightness = PowerManager.BRIGHTNESS_ON;
Jeff Brownf75724b2012-08-25 13:34:32 -070078 invalidate(DIRTY_BRIGHTNESS);
Jeff Brown96307042012-07-27 15:51:34 -070079 }
80
81 public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
82 new FloatProperty<DisplayPowerState>("electronBeamLevel") {
83 @Override
84 public void setValue(DisplayPowerState object, float value) {
85 object.setElectronBeamLevel(value);
86 }
87
88 @Override
89 public Float get(DisplayPowerState object) {
90 return object.getElectronBeamLevel();
91 }
92 };
93
94 public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
95 new IntProperty<DisplayPowerState>("screenBrightness") {
96 @Override
97 public void setValue(DisplayPowerState object, int value) {
98 object.setScreenBrightness(value);
99 }
100
101 @Override
102 public Integer get(DisplayPowerState object) {
103 return object.getScreenBrightness();
104 }
105 };
106
107 /**
108 * Sets whether the screen is on or off.
109 */
110 public void setScreenOn(boolean on) {
111 if (mScreenOn != on) {
112 if (DEBUG) {
113 Slog.d(TAG, "setScreenOn: on=" + on);
114 }
115
116 mScreenOn = on;
117 invalidate(DIRTY_SCREEN_ON);
118 }
119 }
120
121 /**
122 * Returns true if the screen is on.
123 */
124 public boolean isScreenOn() {
125 return mScreenOn;
126 }
127
128 /**
129 * Prepares the electron beam to turn on or off.
130 * This method should be called before starting an animation because it
131 * can take a fair amount of time to prepare the electron beam surface.
132 *
133 * @param warmUp True if the electron beam should start warming up.
134 * @return True if the electron beam was prepared.
135 */
136 public boolean prepareElectronBeam(boolean warmUp) {
Jeff Browna52772f2012-10-04 18:38:09 -0700137 if (mElectronBeam != null) {
138 boolean success = mElectronBeam.prepare(warmUp);
139 invalidate(DIRTY_ELECTRON_BEAM);
140 return success;
141 } else {
142 return true;
143 }
Jeff Brown96307042012-07-27 15:51:34 -0700144 }
145
146 /**
147 * Dismisses the electron beam surface.
148 */
149 public void dismissElectronBeam() {
Jeff Browna52772f2012-10-04 18:38:09 -0700150 if (mElectronBeam != null) {
151 mElectronBeam.dismiss();
152 }
Jeff Brown96307042012-07-27 15:51:34 -0700153 }
154
155 /**
156 * Sets the level of the electron beam steering current.
157 *
158 * The display is blanked when the level is 0.0. In normal use, the electron
159 * beam should have a value of 1.0. The electron beam is unstable in between
160 * these states and the picture quality may be compromised. For best effect,
161 * the electron beam should be warmed up or cooled off slowly.
162 *
163 * Warning: Electron beam emits harmful radiation. Avoid direct exposure to
164 * skin or eyes.
165 *
166 * @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
167 */
168 public void setElectronBeamLevel(float level) {
169 if (mElectronBeamLevel != level) {
170 if (DEBUG) {
171 Slog.d(TAG, "setElectronBeamLevel: level=" + level);
172 }
173
174 mElectronBeamLevel = level;
175 invalidate(DIRTY_ELECTRON_BEAM);
176 }
177 }
178
179 /**
180 * Gets the level of the electron beam steering current.
181 */
182 public float getElectronBeamLevel() {
183 return mElectronBeamLevel;
184 }
185
186 /**
187 * Sets the display brightness.
188 *
189 * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
190 */
191 public void setScreenBrightness(int brightness) {
192 if (mScreenBrightness != brightness) {
193 if (DEBUG) {
194 Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
195 }
196
197 mScreenBrightness = brightness;
198 invalidate(DIRTY_BRIGHTNESS);
199 }
200 }
201
202 /**
203 * Gets the screen brightness.
204 */
205 public int getScreenBrightness() {
206 return mScreenBrightness;
207 }
208
209 /**
210 * Returns true if no properties have been invalidated.
211 * Otherwise, returns false and promises to invoke the specified listener
212 * when the properties have all been applied.
213 * The listener always overrides any previously set listener.
214 */
215 public boolean waitUntilClean(Runnable listener) {
216 if (mDirty != 0) {
217 mCleanListener = listener;
218 return false;
219 } else {
220 mCleanListener = null;
221 return true;
222 }
223 }
224
225 public void dump(PrintWriter pw) {
226 pw.println();
227 pw.println("Display Power State:");
228 pw.println(" mDirty=" + Integer.toHexString(mDirty));
229 pw.println(" mScreenOn=" + mScreenOn);
230 pw.println(" mScreenBrightness=" + mScreenBrightness);
231 pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
232
Jeff Browna52772f2012-10-04 18:38:09 -0700233 if (mElectronBeam != null) {
234 mElectronBeam.dump(pw);
235 }
Jeff Brown96307042012-07-27 15:51:34 -0700236 }
237
238 private void invalidate(int dirty) {
239 if (mDirty == 0) {
240 mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
241 mTraversalRunnable, null);
242 }
243
244 mDirty |= dirty;
245 }
246
247 private void apply() {
248 if (mDirty != 0) {
249 if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
Jeff Brown735f740f2012-09-16 13:09:41 -0700250 mScreenBrightnessModulator.setBrightness(0, true /*sync*/);
Jeff Brown96307042012-07-27 15:51:34 -0700251 PowerManagerService.nativeSetScreenState(false);
252 }
253
Jeff Browna52772f2012-10-04 18:38:09 -0700254 if ((mDirty & DIRTY_ELECTRON_BEAM) != 0 && mElectronBeam != null) {
Jeff Brown96307042012-07-27 15:51:34 -0700255 mElectronBeam.draw(mElectronBeamLevel);
256 }
257
Jeff Brown96307042012-07-27 15:51:34 -0700258 if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
259 PowerManagerService.nativeSetScreenState(true);
260 }
261
Jeff Brown735f740f2012-09-16 13:09:41 -0700262 if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0
263 && mScreenOn) {
264 mScreenBrightnessModulator.setBrightness(
265 (int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/);
266 }
267
Jeff Brown96307042012-07-27 15:51:34 -0700268 mDirty = 0;
269
270 if (mCleanListener != null) {
271 mCleanListener.run();
272 }
273 }
274 }
275
276 private final Runnable mTraversalRunnable = new Runnable() {
277 @Override
278 public void run() {
279 if (mDirty != 0) {
280 apply();
281 }
282 }
283 };
284}