DisplayPowerState.java revision 735f740fe81b7172d0b208d584eecf632533ec4a
1/* 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 52 private final Choreographer mChoreographer; 53 private final ElectronBeam mElectronBeam; 54 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 69 // 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. 75 mScreenOn = true; 76 mElectronBeamLevel = 1.0f; 77 mScreenBrightness = PowerManager.BRIGHTNESS_ON; 78 invalidate(DIRTY_BRIGHTNESS); 79 } 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) { 137 boolean success = mElectronBeam.prepare(warmUp); 138 invalidate(DIRTY_ELECTRON_BEAM); 139 return success; 140 } 141 142 /** 143 * Dismisses the electron beam surface. 144 */ 145 public void dismissElectronBeam() { 146 mElectronBeam.dismiss(); 147 } 148 149 /** 150 * Sets the level of the electron beam steering current. 151 * 152 * The display is blanked when the level is 0.0. In normal use, the electron 153 * beam should have a value of 1.0. The electron beam is unstable in between 154 * these states and the picture quality may be compromised. For best effect, 155 * the electron beam should be warmed up or cooled off slowly. 156 * 157 * Warning: Electron beam emits harmful radiation. Avoid direct exposure to 158 * skin or eyes. 159 * 160 * @param level The level, ranges from 0.0 (full off) to 1.0 (full on). 161 */ 162 public void setElectronBeamLevel(float level) { 163 if (mElectronBeamLevel != level) { 164 if (DEBUG) { 165 Slog.d(TAG, "setElectronBeamLevel: level=" + level); 166 } 167 168 mElectronBeamLevel = level; 169 invalidate(DIRTY_ELECTRON_BEAM); 170 } 171 } 172 173 /** 174 * Gets the level of the electron beam steering current. 175 */ 176 public float getElectronBeamLevel() { 177 return mElectronBeamLevel; 178 } 179 180 /** 181 * Sets the display brightness. 182 * 183 * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest). 184 */ 185 public void setScreenBrightness(int brightness) { 186 if (mScreenBrightness != brightness) { 187 if (DEBUG) { 188 Slog.d(TAG, "setScreenBrightness: brightness=" + brightness); 189 } 190 191 mScreenBrightness = brightness; 192 invalidate(DIRTY_BRIGHTNESS); 193 } 194 } 195 196 /** 197 * Gets the screen brightness. 198 */ 199 public int getScreenBrightness() { 200 return mScreenBrightness; 201 } 202 203 /** 204 * Returns true if no properties have been invalidated. 205 * Otherwise, returns false and promises to invoke the specified listener 206 * when the properties have all been applied. 207 * The listener always overrides any previously set listener. 208 */ 209 public boolean waitUntilClean(Runnable listener) { 210 if (mDirty != 0) { 211 mCleanListener = listener; 212 return false; 213 } else { 214 mCleanListener = null; 215 return true; 216 } 217 } 218 219 public void dump(PrintWriter pw) { 220 pw.println(); 221 pw.println("Display Power State:"); 222 pw.println(" mDirty=" + Integer.toHexString(mDirty)); 223 pw.println(" mScreenOn=" + mScreenOn); 224 pw.println(" mScreenBrightness=" + mScreenBrightness); 225 pw.println(" mElectronBeamLevel=" + mElectronBeamLevel); 226 227 mElectronBeam.dump(pw); 228 } 229 230 private void invalidate(int dirty) { 231 if (mDirty == 0) { 232 mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, 233 mTraversalRunnable, null); 234 } 235 236 mDirty |= dirty; 237 } 238 239 private void apply() { 240 if (mDirty != 0) { 241 if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) { 242 mScreenBrightnessModulator.setBrightness(0, true /*sync*/); 243 PowerManagerService.nativeSetScreenState(false); 244 } 245 246 if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) { 247 mElectronBeam.draw(mElectronBeamLevel); 248 } 249 250 if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) { 251 PowerManagerService.nativeSetScreenState(true); 252 } 253 254 if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0 255 && mScreenOn) { 256 mScreenBrightnessModulator.setBrightness( 257 (int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/); 258 } 259 260 mDirty = 0; 261 262 if (mCleanListener != null) { 263 mCleanListener.run(); 264 } 265 } 266 } 267 268 private final Runnable mTraversalRunnable = new Runnable() { 269 @Override 270 public void run() { 271 if (mDirty != 0) { 272 apply(); 273 } 274 } 275 }; 276} 277