DisplayPowerState.java revision 122415f5c813408fe2c7b81e33144f2beff9c3d5
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 static final int DIRTY_ALL = 0xffffffff; 53 54 private final Choreographer mChoreographer; 55 private final ElectronBeam mElectronBeam; 56 private final PhotonicModulator mScreenBrightnessModulator; 57 58 private int mDirty; 59 private boolean mScreenOn; 60 private float mElectronBeamLevel; 61 private int mScreenBrightness; 62 63 private Runnable mCleanListener; 64 65 public DisplayPowerState(ElectronBeam electronBean, 66 PhotonicModulator screenBrightnessModulator) { 67 mChoreographer = Choreographer.getInstance(); 68 mElectronBeam = electronBean; 69 mScreenBrightnessModulator = screenBrightnessModulator; 70 71 mScreenOn = true; 72 mElectronBeamLevel = 1.0f; 73 mScreenBrightness = PowerManager.BRIGHTNESS_ON; 74 invalidate(DIRTY_ALL); 75 } 76 77 public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL = 78 new FloatProperty<DisplayPowerState>("electronBeamLevel") { 79 @Override 80 public void setValue(DisplayPowerState object, float value) { 81 object.setElectronBeamLevel(value); 82 } 83 84 @Override 85 public Float get(DisplayPowerState object) { 86 return object.getElectronBeamLevel(); 87 } 88 }; 89 90 public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS = 91 new IntProperty<DisplayPowerState>("screenBrightness") { 92 @Override 93 public void setValue(DisplayPowerState object, int value) { 94 object.setScreenBrightness(value); 95 } 96 97 @Override 98 public Integer get(DisplayPowerState object) { 99 return object.getScreenBrightness(); 100 } 101 }; 102 103 /** 104 * Sets whether the screen is on or off. 105 */ 106 public void setScreenOn(boolean on) { 107 if (mScreenOn != on) { 108 if (DEBUG) { 109 Slog.d(TAG, "setScreenOn: on=" + on); 110 } 111 112 mScreenOn = on; 113 invalidate(DIRTY_SCREEN_ON); 114 } 115 } 116 117 /** 118 * Returns true if the screen is on. 119 */ 120 public boolean isScreenOn() { 121 return mScreenOn; 122 } 123 124 /** 125 * Prepares the electron beam to turn on or off. 126 * This method should be called before starting an animation because it 127 * can take a fair amount of time to prepare the electron beam surface. 128 * 129 * @param warmUp True if the electron beam should start warming up. 130 * @return True if the electron beam was prepared. 131 */ 132 public boolean prepareElectronBeam(boolean warmUp) { 133 boolean success = mElectronBeam.prepare(warmUp); 134 invalidate(DIRTY_ELECTRON_BEAM); 135 return success; 136 } 137 138 /** 139 * Dismisses the electron beam surface. 140 */ 141 public void dismissElectronBeam() { 142 mElectronBeam.dismiss(); 143 } 144 145 /** 146 * Sets the level of the electron beam steering current. 147 * 148 * The display is blanked when the level is 0.0. In normal use, the electron 149 * beam should have a value of 1.0. The electron beam is unstable in between 150 * these states and the picture quality may be compromised. For best effect, 151 * the electron beam should be warmed up or cooled off slowly. 152 * 153 * Warning: Electron beam emits harmful radiation. Avoid direct exposure to 154 * skin or eyes. 155 * 156 * @param level The level, ranges from 0.0 (full off) to 1.0 (full on). 157 */ 158 public void setElectronBeamLevel(float level) { 159 if (mElectronBeamLevel != level) { 160 if (DEBUG) { 161 Slog.d(TAG, "setElectronBeamLevel: level=" + level); 162 } 163 164 mElectronBeamLevel = level; 165 invalidate(DIRTY_ELECTRON_BEAM); 166 } 167 } 168 169 /** 170 * Gets the level of the electron beam steering current. 171 */ 172 public float getElectronBeamLevel() { 173 return mElectronBeamLevel; 174 } 175 176 /** 177 * Sets the display brightness. 178 * 179 * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest). 180 */ 181 public void setScreenBrightness(int brightness) { 182 if (mScreenBrightness != brightness) { 183 if (DEBUG) { 184 Slog.d(TAG, "setScreenBrightness: brightness=" + brightness); 185 } 186 187 mScreenBrightness = brightness; 188 invalidate(DIRTY_BRIGHTNESS); 189 } 190 } 191 192 /** 193 * Gets the screen brightness. 194 */ 195 public int getScreenBrightness() { 196 return mScreenBrightness; 197 } 198 199 /** 200 * Returns true if no properties have been invalidated. 201 * Otherwise, returns false and promises to invoke the specified listener 202 * when the properties have all been applied. 203 * The listener always overrides any previously set listener. 204 */ 205 public boolean waitUntilClean(Runnable listener) { 206 if (mDirty != 0) { 207 mCleanListener = listener; 208 return false; 209 } else { 210 mCleanListener = null; 211 return true; 212 } 213 } 214 215 public void dump(PrintWriter pw) { 216 pw.println(); 217 pw.println("Display Power State:"); 218 pw.println(" mDirty=" + Integer.toHexString(mDirty)); 219 pw.println(" mScreenOn=" + mScreenOn); 220 pw.println(" mScreenBrightness=" + mScreenBrightness); 221 pw.println(" mElectronBeamLevel=" + mElectronBeamLevel); 222 223 mElectronBeam.dump(pw); 224 } 225 226 private void invalidate(int dirty) { 227 if (mDirty == 0) { 228 mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, 229 mTraversalRunnable, null); 230 } 231 232 mDirty |= dirty; 233 } 234 235 private void apply() { 236 if (mDirty != 0) { 237 if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) { 238 PowerManagerService.nativeSetScreenState(false); 239 } 240 241 if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) { 242 mElectronBeam.draw(mElectronBeamLevel); 243 } 244 245 if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON)) != 0) { 246 mScreenBrightnessModulator.setBrightness(mScreenOn ? mScreenBrightness : 0); 247 } 248 249 if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) { 250 PowerManagerService.nativeSetScreenState(true); 251 } 252 253 mDirty = 0; 254 255 if (mCleanListener != null) { 256 mCleanListener.run(); 257 } 258 } 259 } 260 261 private final Runnable mTraversalRunnable = new Runnable() { 262 @Override 263 public void run() { 264 if (mDirty != 0) { 265 apply(); 266 } 267 } 268 }; 269} 270