New screen shut down animation.

Bug: 16845774

Change-Id: I355f8d73f54a873f6df180dc48c177b993f170f9
diff --git a/core/res/res/raw/color_fade_frag.frag b/core/res/res/raw/color_fade_frag.frag
new file mode 100644
index 0000000..a66a5a7
--- /dev/null
+++ b/core/res/res/raw/color_fade_frag.frag
@@ -0,0 +1,42 @@
+#extension GL_OES_EGL_image_external : require
+
+precision mediump float;
+uniform samplerExternalOES texUnit;
+uniform float opacity;
+uniform float saturation;
+uniform float gamma;
+varying vec2 UV;
+
+vec3 rgb2hsl(vec3 rgb)
+{
+    float e = 1.0e-7;
+
+    vec4 p = rgb.g < rgb.b ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0);
+    vec4 q = rgb.r < p.x ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx);
+
+    float v = q.x;
+    float c = v - min(q.w, q.y);
+    float h = abs((q.w - q.y) / (6.0 * c + e) + q.z);
+    float l = v - c * 0.5;
+    float s = c / (1.0 - abs(2.0 * l - 1.0) + e);
+    return clamp(vec3(h, s, l), 0.0, 1.0);
+}
+
+vec3 hsl2rgb(vec3 hsl)
+{
+    vec3 h = vec3(hsl.x * 6.0);
+    vec3 p = abs(h - vec3(3.0, 2.0, 4.0));
+    vec3 q = 2.0 - p;
+
+    vec3 rgb = clamp(vec3(p.x - 1.0, q.yz), 0.0, 1.0);
+    float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
+    return (rgb - vec3(0.5)) * c + hsl.z;
+}
+
+void main()
+{
+    vec4 color = texture2D(texUnit, UV);
+    vec3 hsl = rgb2hsl(color.xyz);
+    vec3 rgb = pow(hsl2rgb(vec3(hsl.x, hsl.y * saturation, hsl.z * opacity)), vec3(gamma));
+    gl_FragColor = vec4(rgb, 1.0);
+}
diff --git a/core/res/res/raw/color_fade_vert.vert b/core/res/res/raw/color_fade_vert.vert
new file mode 100644
index 0000000..d17437f
--- /dev/null
+++ b/core/res/res/raw/color_fade_vert.vert
@@ -0,0 +1,13 @@
+uniform mat4 proj_matrix;
+uniform mat4 tex_matrix;
+uniform float scale;
+attribute vec2 position;
+attribute vec2 uv;
+varying vec2 UV;
+
+void main()
+{
+    vec4 transformed_uv = tex_matrix * vec4(uv.x, uv.y, 1.0, 1.0);
+    UV = transformed_uv.st / transformed_uv.q;
+    gl_Position = vec4(scale, scale, 1.0, 1.0) * (proj_matrix * vec4(position.x, position.y, 0.0, 1.0));
+}
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 110ddb1..250711e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1266,6 +1266,8 @@
   <java-symbol type="xml" name="default_zen_mode_config" />
   <java-symbol type="xml" name="tv_content_rating_systems" />
 
+  <java-symbol type="raw" name="color_fade_vert" />
+  <java-symbol type="raw" name="color_fade_frag" />
   <java-symbol type="raw" name="accessibility_gestures" />
   <java-symbol type="raw" name="incognito_mode_start_page" />
   <java-symbol type="raw" name="loaderror" />
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ColorFade.java
similarity index 65%
rename from services/core/java/com/android/server/display/ElectronBeam.java
rename to services/core/java/com/android/server/display/ColorFade.java
index 18e4049..920fdfb 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,11 +16,16 @@
 
 package com.android.server.display;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManagerInternal;
@@ -30,9 +35,8 @@
 import android.opengl.EGLContext;
 import android.opengl.EGLDisplay;
 import android.opengl.EGLSurface;
-import android.opengl.GLES10;
+import android.opengl.GLES20;
 import android.opengl.GLES11Ext;
-import android.os.Looper;
 import android.util.FloatMath;
 import android.util.Slog;
 import android.view.DisplayInfo;
@@ -41,10 +45,12 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
+import libcore.io.Streams;
+
 import com.android.server.LocalServices;
+import com.android.internal.R;
 
 /**
- * Bzzzoooop!  *crackle*
  * <p>
  * Animates a screen transition from on to off or off to on by applying
  * some GL transformations to a screenshot.
@@ -53,20 +59,14 @@
  * that belongs to the {@link DisplayPowerController}.
  * </p>
  */
-final class ElectronBeam {
-    private static final String TAG = "ElectronBeam";
+final class ColorFade {
+    private static final String TAG = "ColorFade";
 
     private static final boolean DEBUG = false;
 
     // The layer for the electron beam surface.
     // This is currently hardcoded to be one layer above the boot animation.
-    private static final int ELECTRON_BEAM_LAYER = 0x40000001;
-
-    // The relative proportion of the animation to spend performing
-    // the horizontal stretch effect.  The remainder is spent performing
-    // the vertical stretch effect.
-    private static final float HSTRETCH_DURATION = 0.5f;
-    private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
+    private static final int COLOR_FADE_LAYER = 0x40000001;
 
     // The number of frames to draw when preparing the animation so that it will
     // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
@@ -98,6 +98,11 @@
     private final int[] mTexNames = new int[1];
     private boolean mTexNamesGenerated;
     private final float mTexMatrix[] = new float[16];
+    private final float mProjMatrix[] = new float[16];
+    private final int[] mGLBuffers = new int[2];
+    private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
+    private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
+    private int mProgram;
 
     // Vertex and corresponding texture coordinates.
     // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
@@ -105,12 +110,12 @@
     private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
 
     /**
-     * Animates an electron beam warming up.
+     * Animates an color fade warming up.
      */
     public static final int MODE_WARM_UP = 0;
 
     /**
-     * Animates an electron beam shutting off.
+     * Animates an color fade shutting off.
      */
     public static final int MODE_COOL_DOWN = 1;
 
@@ -119,19 +124,19 @@
      */
     public static final int MODE_FADE = 2;
 
-    public ElectronBeam(int displayId) {
+    public ColorFade(int displayId) {
         mDisplayId = displayId;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
     /**
-     * Warms up the electron beam in preparation for turning on or off.
+     * Warms up the color fade in preparation for turning on or off.
      * This method prepares a GL context, and captures a screen shot.
      *
      * @param mode The desired mode for the upcoming animation.
-     * @return True if the electron beam is ready, false if it is uncontrollable.
+     * @return True if the color fade is ready, false if it is uncontrollable.
      */
-    public boolean prepare(int mode) {
+    public boolean prepare(Context context, int mode) {
         if (DEBUG) {
             Slog.d(TAG, "prepare: mode=" + mode);
         }
@@ -139,18 +144,33 @@
         mMode = mode;
 
         // Get the display size and layer stack.
-        // This is not expected to change while the electron beam surface is showing.
+        // This is not expected to change while the color fade surface is showing.
         DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
 
         // Prepare the surface for drawing.
-        if (!tryPrepare()) {
+        if (!(createSurface() && createEglContext() && createEglSurface() &&
+              captureScreenshotTextureAndSetViewport())) {
             dismiss();
             return false;
         }
 
+        // Init GL
+        if (!attachEglContext()) {
+            return false;
+        }
+        try {
+            if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
+                detachEglContext();
+                dismiss();
+                return false;
+            }
+        } finally {
+            detachEglContext();
+        }
+
         // Done.
         mPrepared = true;
 
@@ -169,24 +189,125 @@
         return true;
     }
 
-    private boolean tryPrepare() {
-        if (createSurface()) {
-            if (mMode == MODE_FADE) {
-                return true;
-            }
-            return createEglContext()
-                    && createEglSurface()
-                    && captureScreenshotTextureAndSetViewport();
+    private String readFile(Context context, int resourceId) {
+        try{
+            InputStream stream = context.getResources().openRawResource(resourceId);
+            return new String(Streams.readFully(new InputStreamReader(stream)));
         }
-        return false;
+        catch (IOException e) {
+            Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
+            throw new RuntimeException(e);
+        }
+    }
+
+    private int loadShader(Context context, int resourceId, int type) {
+        String source = readFile(context, resourceId);
+
+        int shader = GLES20.glCreateShader(type);
+
+        GLES20.glShaderSource(shader, source);
+        GLES20.glCompileShader(shader);
+
+        int[] compiled = new int[1];
+        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+        if (compiled[0] == 0) {
+            Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
+            Slog.e(TAG, GLES20.glGetShaderSource(shader));
+            Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
+            GLES20.glDeleteShader(shader);
+            shader = 0;
+        }
+
+        return shader;
+    }
+
+    private boolean initGLShaders(Context context) {
+        int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
+                GLES20.GL_VERTEX_SHADER);
+        int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
+                GLES20.GL_FRAGMENT_SHADER);
+        if (vshader == 0 || fshader == 0) return false;
+
+        mProgram = GLES20.glCreateProgram();
+
+        GLES20.glAttachShader(mProgram, vshader);
+        GLES20.glAttachShader(mProgram, fshader);
+
+        GLES20.glLinkProgram(mProgram);
+
+        mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
+        mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
+
+        mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
+        mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
+
+        mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
+        mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
+        mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
+        mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
+        mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
+
+        GLES20.glUseProgram(mProgram);
+        GLES20.glUniform1i(mTexUnitLoc, 0);
+        GLES20.glUseProgram(0);
+
+        return true;
+    }
+
+    private boolean initGLBuffers() {
+        //Fill vertices
+        setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
+
+        // Setup GL Textures
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+                GLES20.GL_NEAREST);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+                GLES20.GL_NEAREST);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+                GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+                GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+
+        // Setup GL Buffers
+        GLES20.glGenBuffers(2, mGLBuffers, 0);
+
+        // fill vertex buffer
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
+                            mVertexBuffer, GLES20.GL_STATIC_DRAW);
+
+        // fill tex buffer
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
+                            mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
+
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+        return true;
+    }
+
+    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
+        if (DEBUG) {
+            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
+        }
+        vtx.put(0, x);
+        vtx.put(1, y);
+        vtx.put(2, x);
+        vtx.put(3, y + h);
+        vtx.put(4, x + w);
+        vtx.put(5, y + h);
+        vtx.put(6, x + w);
+        vtx.put(7, y);
     }
 
     /**
-     * Dismisses the electron beam animation surface and cleans up.
+     * Dismisses the color fade animation surface and cleans up.
      *
-     * To prevent stray photons from leaking out after the electron beam has been
+     * To prevent stray photons from leaking out after the color fade has been
      * turned off, it is a good idea to defer dismissing the animation until the
-     * electron beam has been turned back on fully.
+     * color fade has been turned back on fully.
      */
     public void dismiss() {
         if (DEBUG) {
@@ -200,10 +321,10 @@
     }
 
     /**
-     * Draws an animation frame showing the electron beam activated at the
+     * Draws an animation frame showing the color fade activated at the
      * specified level.
      *
-     * @param level The electron beam level.
+     * @param level The color fade level.
      * @return True if successful.
      */
     public boolean draw(float level) {
@@ -224,15 +345,18 @@
         }
         try {
             // Clear frame to solid black.
-            GLES10.glClearColor(0f, 0f, 0f, 1f);
-            GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
+            GLES20.glClearColor(0f, 0f, 0f, 1f);
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
 
             // Draw the frame.
-            if (level < HSTRETCH_DURATION) {
-                drawHStretch(1.0f - (level / HSTRETCH_DURATION));
-            } else {
-                drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
-            }
+            float one_minus_level = 1 - level;
+            float cos = FloatMath.cos((float)Math.PI * one_minus_level);
+            float sign = cos < 0 ? -1 : 1;
+            float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
+            float saturation = FloatMath.pow(level, 4);
+            float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
+            float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+            drawFaded(opacity, 1.f / gamma, saturation, scale);
             if (checkGlErrors("drawFrame")) {
                 return false;
             }
@@ -244,139 +368,59 @@
         return showSurface(1.0f);
     }
 
-    /**
-     * Draws a frame where the content of the electron beam is collapsing inwards upon
-     * itself vertically with red / green / blue channels dispersing and eventually
-     * merging down to a single horizontal line.
-     *
-     * @param stretch The stretch factor.  0.0 is no collapse, 1.0 is full collapse.
-     */
-    private void drawVStretch(float stretch) {
-        // compute interpolation scale factors for each color channel
-        final float ar = scurve(stretch, 7.5f);
-        final float ag = scurve(stretch, 8.0f);
-        final float ab = scurve(stretch, 8.5f);
+    private void drawFaded(float opacity, float gamma, float saturation, float scale) {
         if (DEBUG) {
-            Slog.d(TAG, "drawVStretch: stretch=" + stretch
-                    + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
+            Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
+                        ", saturation=" + saturation + ", scale=" + scale);
         }
+        // Use shaders
+        GLES20.glUseProgram(mProgram);
 
-        // set blending
-        GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
-        GLES10.glEnable(GLES10.GL_BLEND);
+        // Set Uniforms
+        GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
+        GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
+        GLES20.glUniform1f(mOpacityLoc, opacity);
+        GLES20.glUniform1f(mGammaLoc, gamma);
+        GLES20.glUniform1f(mSaturationLoc, saturation);
+        GLES20.glUniform1f(mScaleLoc, scale);
 
-        // bind vertex buffer
-        GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
-        GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
+        // Use textures
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
 
-        // set-up texturing
-        GLES10.glDisable(GLES10.GL_TEXTURE_2D);
-        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
+        // draw the plane
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+        GLES20.glEnableVertexAttribArray(mVertexLoc);
+        GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
 
-        // bind texture and set blending for drawing planes
-        GLES10.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
-        GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
-                mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
-        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
-        GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
-        GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+        GLES20.glEnableVertexAttribArray(mTexCoordLoc);
+        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
 
-        // draw the red plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
-        GLES10.glColorMask(true, false, false, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // draw the green plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
-        GLES10.glColorMask(false, true, false, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // draw the blue plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
-        GLES10.glColorMask(false, false, true, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // clean up after drawing planes
-        GLES10.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
-        GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
-        GLES10.glColorMask(true, true, true, true);
-
-        // draw the white highlight (we use the last vertices)
-        if (mMode == MODE_COOL_DOWN) {
-            GLES10.glColor4f(ag, ag, ag, 1.0f);
-            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-        }
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
 
         // clean up
-        GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
-        GLES10.glDisable(GLES10.GL_BLEND);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
     }
 
-    /**
-     * Draws a frame where the electron beam has been stretched out into
-     * a thin white horizontal line that fades as it collapses inwards.
-     *
-     * @param stretch The stretch factor.  0.0 is maximum stretch / no fade,
-     * 1.0 is collapsed / maximum fade.
-     */
-    private void drawHStretch(float stretch) {
-        // compute interpolation scale factor
-        final float ag = scurve(stretch, 8.0f);
-        if (DEBUG) {
-            Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
-        }
-
-        if (stretch < 1.0f) {
-            // bind vertex buffer
-            GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
-            GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
-
-            // draw narrow fading white line
-            setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
-            GLES10.glColor4f(1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f);
-            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-            // clean up
-            GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
-        }
-    }
-
-    private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
-        final float w = dw + (dw * a);
-        final float h = dh - (dh * a);
-        final float x = (dw - w) * 0.5f;
-        final float y = (dh - h) * 0.5f;
-        setQuad(vtx, x, y, w, h);
-    }
-
-    private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
-        final float w = 2 * dw * (1.0f - a);
-        final float h = 1.0f;
-        final float x = (dw - w) * 0.5f;
-        final float y = (dh - h) * 0.5f;
-        setQuad(vtx, x, y, w, h);
-    }
-
-    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
-        if (DEBUG) {
-            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
-        }
-        vtx.put(0, x);
-        vtx.put(1, y);
-        vtx.put(2, x);
-        vtx.put(3, y + h);
-        vtx.put(4, x + w);
-        vtx.put(5, y + h);
-        vtx.put(6, x + w);
-        vtx.put(7, y);
+    private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
+        mProjMatrix[0] = 2f / (right - left);
+        mProjMatrix[1] = 0;
+        mProjMatrix[2] = 0;
+        mProjMatrix[3] = 0;
+        mProjMatrix[4] = 0;
+        mProjMatrix[5] = 2f / (top - bottom);
+        mProjMatrix[6] = 0;
+        mProjMatrix[7] = 0;
+        mProjMatrix[8] = 0;
+        mProjMatrix[9] = 0;
+        mProjMatrix[10] = -2f / (zfar - znear);
+        mProjMatrix[11] = 0;
+        mProjMatrix[12] = -(right + left) / (right - left);
+        mProjMatrix[13] = -(top + bottom) / (top - bottom);
+        mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
+        mProjMatrix[15] = 1f;
     }
 
     private boolean captureScreenshotTextureAndSetViewport() {
@@ -385,7 +429,7 @@
         }
         try {
             if (!mTexNamesGenerated) {
-                GLES10.glGenTextures(1, mTexNames, 0);
+                GLES20.glGenTextures(1, mTexNames, 0);
                 if (checkGlErrors("glGenTextures")) {
                     return false;
                 }
@@ -413,15 +457,8 @@
             mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
 
             // Set up our viewport.
-            GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
-            GLES10.glMatrixMode(GLES10.GL_PROJECTION);
-            GLES10.glLoadIdentity();
-            GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
-            GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
-            GLES10.glLoadIdentity();
-            GLES10.glMatrixMode(GLES10.GL_TEXTURE);
-            GLES10.glLoadIdentity();
-            GLES10.glLoadMatrixf(mTexMatrix, 0);
+            GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
+            ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
         } finally {
             detachEglContext();
         }
@@ -433,7 +470,7 @@
             mTexNamesGenerated = false;
             if (attachEglContext()) {
                 try {
-                    GLES10.glDeleteTextures(1, mTexNames, 0);
+                    GLES20.glDeleteTextures(1, mTexNames, 0);
                     checkGlErrors("glDeleteTextures");
                 } finally {
                     detachEglContext();
@@ -460,6 +497,8 @@
 
         if (mEglConfig == null) {
             int[] eglConfigAttribList = new int[] {
+                    EGL14.EGL_RENDERABLE_TYPE,
+                    EGL14.EGL_OPENGL_ES2_BIT,
                     EGL14.EGL_RED_SIZE, 8,
                     EGL14.EGL_GREEN_SIZE, 8,
                     EGL14.EGL_BLUE_SIZE, 8,
@@ -478,6 +517,7 @@
 
         if (mEglContext == null) {
             int[] eglContextAttribList = new int[] {
+                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                     EGL14.EGL_NONE
             };
             mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
@@ -490,16 +530,6 @@
         return true;
     }
 
-    /* not used because it is too expensive to create / destroy contexts all of the time
-    private void destroyEglContext() {
-        if (mEglContext != null) {
-            if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
-                logEglError("eglDestroyContext");
-            }
-            mEglContext = null;
-        }
-    }*/
-
     private boolean createSurface() {
         if (mSurfaceSession == null) {
             mSurfaceSession = new SurfaceSession();
@@ -516,7 +546,7 @@
                         flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
                     }
                     mSurfaceControl = new SurfaceControl(mSurfaceSession,
-                            "ElectronBeam", mDisplayWidth, mDisplayHeight,
+                            "ColorFade", mDisplayWidth, mDisplayHeight,
                             PixelFormat.OPAQUE, flags);
                 } catch (OutOfResourcesException ex) {
                     Slog.e(TAG, "Unable to create surface.", ex);
@@ -584,7 +614,7 @@
         if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
             SurfaceControl.openTransaction();
             try {
-                mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER);
+                mSurfaceControl.setLayer(COLOR_FADE_LAYER);
                 mSurfaceControl.setAlpha(alpha);
                 mSurfaceControl.show();
             } finally {
@@ -614,34 +644,6 @@
         }
     }
 
-    /**
-     * Interpolates a value in the range 0 .. 1 along a sigmoid curve
-     * yielding a result in the range 0 .. 1 scaled such that:
-     * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
-     */
-    private static float scurve(float value, float s) {
-        // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
-        // Here we take the input datum and shift it by 0.5 so that the
-        // domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
-        final float x = value - 0.5f;
-
-        // Next apply the sigmoid function to the scaled value
-        // which produces a value in the range 0 .. 1 so we subtract
-        // 0.5 to get a value in the range -0.5 .. 0.5 instead.
-        final float y = sigmoid(x, s) - 0.5f;
-
-        // To obtain the desired boundary conditions we need to scale
-        // the result so that it fills a range of -1 .. 1.
-        final float v = sigmoid(0.5f, s) - 0.5f;
-
-        // And finally remap the value back to a range of 0 .. 1.
-        return y / v * 0.5f + 0.5f;
-    }
-
-    private static float sigmoid(float x, float s) {
-        return 1.0f / (1.0f + FloatMath.exp(-x * s));
-    }
-
     private static FloatBuffer createNativeFloatBuffer(int size) {
         ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
         bb.order(ByteOrder.nativeOrder());
@@ -659,7 +661,7 @@
     private static boolean checkGlErrors(String func, boolean log) {
         boolean hadError = false;
         int error;
-        while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
+        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
             if (log) {
                 Slog.e(TAG, func + " failed: error " + error, new Throwable());
             }
@@ -670,7 +672,7 @@
 
     public void dump(PrintWriter pw) {
         pw.println();
-        pw.println("Electron Beam State:");
+        pw.println("Color Fade State:");
         pw.println("  mPrepared=" + mPrepared);
         pw.println("  mMode=" + mMode);
         pw.println("  mDisplayLayerStack=" + mDisplayLayerStack);
@@ -685,7 +687,7 @@
      * Updates the position and transformation of the matrix whenever the display
      * is rotated.  This is a little tricky because the display transaction
      * callback can be invoked on any thread, not necessarily the thread that
-     * owns the electron beam.
+     * owns the color fade.
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
         private final DisplayManagerInternal mDisplayManagerInternal;
@@ -725,7 +727,8 @@
                         mSurfaceControl.setMatrix(0, -1, 1, 0);
                         break;
                     case Surface.ROTATION_180:
-                        mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
+                        mSurfaceControl.setPosition(displayInfo.logicalWidth,
+                                displayInfo.logicalHeight);
                         mSurfaceControl.setMatrix(-1, 0, 0, -1);
                         break;
                     case Surface.ROTATION_270:
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d0e4b33..9a67321 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -64,7 +64,7 @@
  * blocker as long as the display is not ready.  So most of the work done here
  * does not need to worry about holding a suspend blocker unless it happens
  * independently of the display ready signal.
- *
+   *
  * For debugging, you can make the electron beam and brightness animations run
  * slower by changing the "animator duration scale" option in Development Settings.
  */
@@ -78,14 +78,14 @@
     // We might want to turn this off if we cannot get a guarantee that the screen
     // actually turns on and starts showing new content after the call to set the
     // screen state returns.  Playing the animation can also be somewhat slow.
-    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
+    private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
 
 
     // The minimum reduction in brightness when dimmed.
     private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
 
-    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
-    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
+    private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
+    private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 600;
 
     private static final int MSG_UPDATE_POWER_STATE = 1;
     private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
@@ -107,6 +107,8 @@
 
     private final Object mLock = new Object();
 
+    private final Context mContext;
+
     // Our handler.
     private final DisplayControllerHandler mHandler;
 
@@ -146,7 +148,7 @@
 
     // True if we should fade the screen while turning it off, false if we should play
     // a stylish electron beam animation instead.
-    private boolean mElectronBeamFadesConfig;
+    private boolean mColorFadeFadesConfig;
 
     // The pending power request.
     // Initially null until the first call to requestPowerState.
@@ -223,8 +225,8 @@
     private AutomaticBrightnessController mAutomaticBrightnessController;
 
     // Animators.
-    private ObjectAnimator mElectronBeamOnAnimator;
-    private ObjectAnimator mElectronBeamOffAnimator;
+    private ObjectAnimator mColorFadeOnAnimator;
+    private ObjectAnimator mColorFadeOffAnimator;
     private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
 
     /**
@@ -240,6 +242,7 @@
         mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
         mBlanker = blanker;
+        mContext = context;
 
         final Resources resources = context.getResources();
 
@@ -287,7 +290,7 @@
 
         mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
 
-        mElectronBeamFadesConfig = resources.getBoolean(
+        mColorFadeFadesConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_animateScreenLights);
 
         if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
@@ -378,17 +381,17 @@
         // In the future, we might manage multiple displays independently.
         mPowerState = new DisplayPowerState(mBlanker,
                 mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
-                new ElectronBeam(Display.DEFAULT_DISPLAY));
+                new ColorFade(Display.DEFAULT_DISPLAY));
 
-        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
-                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
-        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
-        mElectronBeamOnAnimator.addListener(mAnimatorListener);
+        mColorFadeOnAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
+        mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
+        mColorFadeOnAnimator.addListener(mAnimatorListener);
 
-        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
-                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
-        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
-        mElectronBeamOffAnimator.addListener(mAnimatorListener);
+        mColorFadeOffAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
+        mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
+        mColorFadeOffAnimator.addListener(mAnimatorListener);
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
@@ -600,34 +603,34 @@
             // Wait for previous off animation to complete beforehand.
             // It is relatively short but if we cancel it and switch to the
             // on animation immediately then the results are pretty ugly.
-            if (!mElectronBeamOffAnimator.isStarted()) {
+            if (!mColorFadeOffAnimator.isStarted()) {
                 // Turn the screen on.  The contents of the screen may not yet
                 // be visible if the electron beam has not been dismissed because
                 // its last frame of animation is solid black.
                 setScreenState(Display.STATE_ON);
                 if (mPowerRequest.blockScreenOn
-                        && mPowerState.getElectronBeamLevel() == 0.0f) {
+                        && mPowerState.getColorFadeLevel() == 0.0f) {
                     blockScreenOn();
                 } else {
                     unblockScreenOn();
-                    if (USE_ELECTRON_BEAM_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
+                    if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
                         // Perform screen on animation.
-                        if (!mElectronBeamOnAnimator.isStarted()) {
-                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
-                                mPowerState.dismissElectronBeam();
-                            } else if (mPowerState.prepareElectronBeam(
-                                    mElectronBeamFadesConfig ?
-                                            ElectronBeam.MODE_FADE :
-                                                    ElectronBeam.MODE_WARM_UP)) {
-                                mElectronBeamOnAnimator.start();
+                        if (!mColorFadeOnAnimator.isStarted()) {
+                            if (mPowerState.getColorFadeLevel() == 1.0f) {
+                                mPowerState.dismissColorFade();
+                            } else if (mPowerState.prepareColorFade(mContext,
+                                    mColorFadeFadesConfig ?
+                                            ColorFade.MODE_FADE :
+                                                    ColorFade.MODE_WARM_UP)) {
+                                mColorFadeOnAnimator.start();
                             } else {
-                                mElectronBeamOnAnimator.end();
+                                mColorFadeOnAnimator.end();
                             }
                         }
                     } else {
                         // Skip screen on animation.
-                        mPowerState.setElectronBeamLevel(1.0f);
-                        mPowerState.dismissElectronBeam();
+                        mPowerState.setColorFadeLevel(1.0f);
+                        mPowerState.dismissColorFade();
                     }
                 }
             }
@@ -640,8 +643,8 @@
                     || mPowerState.getScreenState() != Display.STATE_ON) {
                 // Set screen state and dismiss the black surface without fanfare.
                 setScreenState(state);
-                mPowerState.setElectronBeamLevel(1.0f);
-                mPowerState.dismissElectronBeam();
+                mPowerState.setColorFadeLevel(1.0f);
+                mPowerState.dismissColorFade();
             }
         } else if (state == Display.STATE_DOZE_SUSPEND) {
             // Want screen dozing and suspended.
@@ -652,27 +655,27 @@
                     || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
                 // Set screen state and dismiss the black surface without fanfare.
                 setScreenState(state);
-                mPowerState.setElectronBeamLevel(1.0f);
-                mPowerState.dismissElectronBeam();
+                mPowerState.setColorFadeLevel(1.0f);
+                mPowerState.dismissColorFade();
             }
         } else {
             // Want screen off.
             // Wait for previous on animation to complete beforehand.
             unblockScreenOn();
-            if (!mElectronBeamOnAnimator.isStarted()) {
+            if (!mColorFadeOnAnimator.isStarted()) {
                 if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
                     // Perform screen off animation.
-                    if (!mElectronBeamOffAnimator.isStarted()) {
-                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
+                    if (!mColorFadeOffAnimator.isStarted()) {
+                        if (mPowerState.getColorFadeLevel() == 0.0f) {
                             setScreenState(Display.STATE_OFF);
-                        } else if (mPowerState.prepareElectronBeam(
-                                mElectronBeamFadesConfig ?
-                                        ElectronBeam.MODE_FADE :
-                                                ElectronBeam.MODE_COOL_DOWN)
+                        } else if (mPowerState.prepareColorFade(mContext,
+                                mColorFadeFadesConfig ?
+                                        ColorFade.MODE_FADE :
+                                                ColorFade.MODE_COOL_DOWN)
                                 && mPowerState.getScreenState() != Display.STATE_OFF) {
-                            mElectronBeamOffAnimator.start();
+                            mColorFadeOffAnimator.start();
                         } else {
-                            mElectronBeamOffAnimator.end();
+                            mColorFadeOffAnimator.end();
                         }
                     }
                 } else {
@@ -687,8 +690,8 @@
         // which will be handled asynchronously.
         if (mustNotify
                 && !mScreenOnWasBlocked
-                && !mElectronBeamOnAnimator.isStarted()
-                && !mElectronBeamOffAnimator.isStarted()
+                && !mColorFadeOnAnimator.isStarted()
+                && !mColorFadeOffAnimator.isStarted()
                 && !mScreenBrightnessRampAnimator.isAnimating()
                 && mPowerState.waitUntilClean(mCleanListener)) {
             synchronized (mLock) {
@@ -936,13 +939,13 @@
         pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
                 mScreenBrightnessRampAnimator.isAnimating());
 
-        if (mElectronBeamOnAnimator != null) {
-            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
-                    mElectronBeamOnAnimator.isStarted());
+        if (mColorFadeOnAnimator != null) {
+            pw.println("  mColorFadeOnAnimator.isStarted()=" +
+                    mColorFadeOnAnimator.isStarted());
         }
-        if (mElectronBeamOffAnimator != null) {
-            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
-                    mElectronBeamOffAnimator.isStarted());
+        if (mColorFadeOffAnimator != null) {
+            pw.println("  mColorFadeOffAnimator.isStarted()=" +
+                    mColorFadeOffAnimator.isStarted());
         }
 
         if (mPowerState != null) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 4821e74..6522b89 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,6 +18,7 @@
 
 import com.android.server.lights.Light;
 
+import android.content.Context;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
@@ -56,7 +57,7 @@
     private final Choreographer mChoreographer;
     private final DisplayBlanker mBlanker;
     private final Light mBacklight;
-    private final ElectronBeam mElectronBeam;
+    private final ColorFade mColorFade;
     private final PhotonicModulator mPhotonicModulator;
 
     private int mScreenState;
@@ -64,19 +65,19 @@
     private boolean mScreenReady;
     private boolean mScreenUpdatePending;
 
-    private boolean mElectronBeamPrepared;
-    private float mElectronBeamLevel;
-    private boolean mElectronBeamReady;
-    private boolean mElectronBeamDrawPending;
+    private boolean mColorFadePrepared;
+    private float mColorFadeLevel;
+    private boolean mColorFadeReady;
+    private boolean mColorFadeDrawPending;
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
+    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
         mBlanker = blanker;
         mBacklight = backlight;
-        mElectronBeam = electronBeam;
+        mColorFade = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
 
         // At boot time, we know that the screen is on and the electron beam
@@ -89,21 +90,21 @@
         mScreenBrightness = PowerManager.BRIGHTNESS_ON;
         scheduleScreenUpdate();
 
-        mElectronBeamPrepared = false;
-        mElectronBeamLevel = 1.0f;
-        mElectronBeamReady = true;
+        mColorFadePrepared = false;
+        mColorFadeLevel = 1.0f;
+        mColorFadeReady = true;
     }
 
-    public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
+    public static final FloatProperty<DisplayPowerState> COLOR_FADE_LEVEL =
             new FloatProperty<DisplayPowerState>("electronBeamLevel") {
         @Override
         public void setValue(DisplayPowerState object, float value) {
-            object.setElectronBeamLevel(value);
+            object.setColorFadeLevel(value);
         }
 
         @Override
         public Float get(DisplayPowerState object) {
-            return object.getElectronBeamLevel();
+            return object.getColorFadeLevel();
         }
     };
 
@@ -176,26 +177,26 @@
      * @param mode The electron beam animation mode to prepare.
      * @return True if the electron beam was prepared.
      */
-    public boolean prepareElectronBeam(int mode) {
-        if (!mElectronBeam.prepare(mode)) {
-            mElectronBeamPrepared = false;
-            mElectronBeamReady = true;
+    public boolean prepareColorFade(Context context, int mode) {
+        if (!mColorFade.prepare(context, mode)) {
+            mColorFadePrepared = false;
+            mColorFadeReady = true;
             return false;
         }
 
-        mElectronBeamPrepared = true;
-        mElectronBeamReady = false;
-        scheduleElectronBeamDraw();
+        mColorFadePrepared = true;
+        mColorFadeReady = false;
+        scheduleColorFadeDraw();
         return true;
     }
 
     /**
      * Dismisses the electron beam surface.
      */
-    public void dismissElectronBeam() {
-        mElectronBeam.dismiss();
-        mElectronBeamPrepared = false;
-        mElectronBeamReady = true;
+    public void dismissColorFade() {
+        mColorFade.dismiss();
+        mColorFadePrepared = false;
+        mColorFadeReady = true;
     }
 
     /**
@@ -211,20 +212,20 @@
      *
      * @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
      */
-    public void setElectronBeamLevel(float level) {
-        if (mElectronBeamLevel != level) {
+    public void setColorFadeLevel(float level) {
+        if (mColorFadeLevel != level) {
             if (DEBUG) {
-                Slog.d(TAG, "setElectronBeamLevel: level=" + level);
+                Slog.d(TAG, "setColorFadeLevel: level=" + level);
             }
 
-            mElectronBeamLevel = level;
+            mColorFadeLevel = level;
             if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate(); // update backlight brightness
             }
-            if (mElectronBeamPrepared) {
-                mElectronBeamReady = false;
-                scheduleElectronBeamDraw();
+            if (mColorFadePrepared) {
+                mColorFadeReady = false;
+                scheduleColorFadeDraw();
             }
         }
     }
@@ -232,8 +233,8 @@
     /**
      * Gets the level of the electron beam steering current.
      */
-    public float getElectronBeamLevel() {
-        return mElectronBeamLevel;
+    public float getColorFadeLevel() {
+        return mColorFadeLevel;
     }
 
     /**
@@ -243,7 +244,7 @@
      * The listener always overrides any previously set listener.
      */
     public boolean waitUntilClean(Runnable listener) {
-        if (!mScreenReady || !mElectronBeamReady) {
+        if (!mScreenReady || !mColorFadeReady) {
             mCleanListener = listener;
             return false;
         } else {
@@ -259,13 +260,13 @@
         pw.println("  mScreenBrightness=" + mScreenBrightness);
         pw.println("  mScreenReady=" + mScreenReady);
         pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
-        pw.println("  mElectronBeamPrepared=" + mElectronBeamPrepared);
-        pw.println("  mElectronBeamLevel=" + mElectronBeamLevel);
-        pw.println("  mElectronBeamReady=" + mElectronBeamReady);
-        pw.println("  mElectronBeamDrawPending=" + mElectronBeamDrawPending);
+        pw.println("  mColorFadePrepared=" + mColorFadePrepared);
+        pw.println("  mColorFadeLevel=" + mColorFadeLevel);
+        pw.println("  mColorFadeReady=" + mColorFadeReady);
+        pw.println("  mColorFadeDrawPending=" + mColorFadeDrawPending);
 
         mPhotonicModulator.dump(pw);
-        mElectronBeam.dump(pw);
+        mColorFade.dump(pw);
     }
 
     private void scheduleScreenUpdate() {
@@ -280,17 +281,17 @@
         mHandler.post(mScreenUpdateRunnable);
     }
 
-    private void scheduleElectronBeamDraw() {
-        if (!mElectronBeamDrawPending) {
-            mElectronBeamDrawPending = true;
+    private void scheduleColorFadeDraw() {
+        if (!mColorFadeDrawPending) {
+            mColorFadeDrawPending = true;
             mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
-                    mElectronBeamDrawRunnable, null);
+                    mColorFadeDrawRunnable, null);
         }
     }
 
     private void invokeCleanListenerIfNeeded() {
         final Runnable listener = mCleanListener;
-        if (listener != null && mScreenReady && mElectronBeamReady) {
+        if (listener != null && mScreenReady && mColorFadeReady) {
             mCleanListener = null;
             listener.run();
         }
@@ -302,7 +303,7 @@
             mScreenUpdatePending = false;
 
             int brightness = mScreenState != Display.STATE_OFF
-                    && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+                    && mColorFadeLevel > 0f ? mScreenBrightness : 0;
             if (mPhotonicModulator.setState(mScreenState, brightness)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Screen ready");
@@ -317,16 +318,16 @@
         }
     };
 
-    private final Runnable mElectronBeamDrawRunnable = new Runnable() {
+    private final Runnable mColorFadeDrawRunnable = new Runnable() {
         @Override
         public void run() {
-            mElectronBeamDrawPending = false;
+            mColorFadeDrawPending = false;
 
-            if (mElectronBeamPrepared) {
-                mElectronBeam.draw(mElectronBeamLevel);
+            if (mColorFadePrepared) {
+                mColorFade.draw(mColorFadeLevel);
             }
 
-            mElectronBeamReady = true;
+            mColorFadeReady = true;
             invokeCleanListenerIfNeeded();
         }
     };