1 /* 2 * Copyright (C) 2014 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 17 package com.android.server.display; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.io.InputStreamReader; 22 import java.io.PrintWriter; 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 import java.nio.FloatBuffer; 26 27 import android.content.Context; 28 import android.content.res.Resources; 29 import android.graphics.PixelFormat; 30 import android.graphics.SurfaceTexture; 31 import android.hardware.display.DisplayManagerInternal; 32 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; 33 import android.opengl.EGL14; 34 import android.opengl.EGLConfig; 35 import android.opengl.EGLContext; 36 import android.opengl.EGLDisplay; 37 import android.opengl.EGLSurface; 38 import android.opengl.GLES20; 39 import android.opengl.GLES11Ext; 40 import android.util.FloatMath; 41 import android.util.Slog; 42 import android.view.DisplayInfo; 43 import android.view.Surface.OutOfResourcesException; 44 import android.view.Surface; 45 import android.view.SurfaceControl; 46 import android.view.SurfaceSession; 47 48 import libcore.io.Streams; 49 50 import com.android.server.LocalServices; 51 import com.android.internal.R; 52 53 /** 54 * <p> 55 * Animates a screen transition from on to off or off to on by applying 56 * some GL transformations to a screenshot. 57 * </p><p> 58 * This component must only be created or accessed by the {@link Looper} thread 59 * that belongs to the {@link DisplayPowerController}. 60 * </p> 61 */ 62 final class ColorFade { 63 private static final String TAG = "ColorFade"; 64 65 private static final boolean DEBUG = false; 66 67 // The layer for the electron beam surface. 68 // This is currently hardcoded to be one layer above the boot animation. 69 private static final int COLOR_FADE_LAYER = 0x40000001; 70 71 // The number of frames to draw when preparing the animation so that it will 72 // be ready to run smoothly. We use 3 frames because we are triple-buffered. 73 // See code for details. 74 private static final int DEJANK_FRAMES = 3; 75 76 private final int mDisplayId; 77 78 // Set to true when the animation context has been fully prepared. 79 private boolean mPrepared; 80 private int mMode; 81 82 private final DisplayManagerInternal mDisplayManagerInternal; 83 private int mDisplayLayerStack; // layer stack associated with primary display 84 private int mDisplayWidth; // real width, not rotated 85 private int mDisplayHeight; // real height, not rotated 86 private SurfaceSession mSurfaceSession; 87 private SurfaceControl mSurfaceControl; 88 private Surface mSurface; 89 private NaturalSurfaceLayout mSurfaceLayout; 90 private EGLDisplay mEglDisplay; 91 private EGLConfig mEglConfig; 92 private EGLContext mEglContext; 93 private EGLSurface mEglSurface; 94 private boolean mSurfaceVisible; 95 private float mSurfaceAlpha; 96 97 // Texture names. We only use one texture, which contains the screenshot. 98 private final int[] mTexNames = new int[1]; 99 private boolean mTexNamesGenerated; 100 private final float mTexMatrix[] = new float[16]; 101 private final float mProjMatrix[] = new float[16]; 102 private final int[] mGLBuffers = new int[2]; 103 private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc; 104 private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc; 105 private int mProgram; 106 107 // Vertex and corresponding texture coordinates. 108 // We have 4 2D vertices, so 8 elements. The vertices form a quad. 109 private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8); 110 private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8); 111 112 /** 113 * Animates an color fade warming up. 114 */ 115 public static final int MODE_WARM_UP = 0; 116 117 /** 118 * Animates an color fade shutting off. 119 */ 120 public static final int MODE_COOL_DOWN = 1; 121 122 /** 123 * Animates a simple dim layer to fade the contents of the screen in or out progressively. 124 */ 125 public static final int MODE_FADE = 2; 126 127 public ColorFade(int displayId) { 128 mDisplayId = displayId; 129 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); 130 } 131 132 /** 133 * Warms up the color fade in preparation for turning on or off. 134 * This method prepares a GL context, and captures a screen shot. 135 * 136 * @param mode The desired mode for the upcoming animation. 137 * @return True if the color fade is ready, false if it is uncontrollable. 138 */ 139 public boolean prepare(Context context, int mode) { 140 if (DEBUG) { 141 Slog.d(TAG, "prepare: mode=" + mode); 142 } 143 144 mMode = mode; 145 146 // Get the display size and layer stack. 147 // This is not expected to change while the color fade surface is showing. 148 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); 149 mDisplayLayerStack = displayInfo.layerStack; 150 mDisplayWidth = displayInfo.getNaturalWidth(); 151 mDisplayHeight = displayInfo.getNaturalHeight(); 152 153 // Prepare the surface for drawing. 154 if (!(createSurface() && createEglContext() && createEglSurface() && 155 captureScreenshotTextureAndSetViewport())) { 156 dismiss(); 157 return false; 158 } 159 160 // Init GL 161 if (!attachEglContext()) { 162 return false; 163 } 164 try { 165 if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) { 166 detachEglContext(); 167 dismiss(); 168 return false; 169 } 170 } finally { 171 detachEglContext(); 172 } 173 174 // Done. 175 mPrepared = true; 176 177 // Dejanking optimization. 178 // Some GL drivers can introduce a lot of lag in the first few frames as they 179 // initialize their state and allocate graphics buffers for rendering. 180 // Work around this problem by rendering the first frame of the animation a few 181 // times. The rest of the animation should run smoothly thereafter. 182 // The frames we draw here aren't visible because we are essentially just 183 // painting the screenshot as-is. 184 if (mode == MODE_COOL_DOWN) { 185 for (int i = 0; i < DEJANK_FRAMES; i++) { 186 draw(1.0f); 187 } 188 } 189 return true; 190 } 191 192 private String readFile(Context context, int resourceId) { 193 try{ 194 InputStream stream = context.getResources().openRawResource(resourceId); 195 return new String(Streams.readFully(new InputStreamReader(stream))); 196 } 197 catch (IOException e) { 198 Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId)); 199 throw new RuntimeException(e); 200 } 201 } 202 203 private int loadShader(Context context, int resourceId, int type) { 204 String source = readFile(context, resourceId); 205 206 int shader = GLES20.glCreateShader(type); 207 208 GLES20.glShaderSource(shader, source); 209 GLES20.glCompileShader(shader); 210 211 int[] compiled = new int[1]; 212 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 213 if (compiled[0] == 0) { 214 Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":"); 215 Slog.e(TAG, GLES20.glGetShaderSource(shader)); 216 Slog.e(TAG, GLES20.glGetShaderInfoLog(shader)); 217 GLES20.glDeleteShader(shader); 218 shader = 0; 219 } 220 221 return shader; 222 } 223 224 private boolean initGLShaders(Context context) { 225 int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert, 226 GLES20.GL_VERTEX_SHADER); 227 int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag, 228 GLES20.GL_FRAGMENT_SHADER); 229 GLES20.glReleaseShaderCompiler(); 230 if (vshader == 0 || fshader == 0) return false; 231 232 mProgram = GLES20.glCreateProgram(); 233 234 GLES20.glAttachShader(mProgram, vshader); 235 GLES20.glAttachShader(mProgram, fshader); 236 GLES20.glDeleteShader(vshader); 237 GLES20.glDeleteShader(fshader); 238 239 GLES20.glLinkProgram(mProgram); 240 241 mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position"); 242 mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv"); 243 244 mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix"); 245 mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix"); 246 247 mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity"); 248 mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma"); 249 mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation"); 250 mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale"); 251 mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit"); 252 253 GLES20.glUseProgram(mProgram); 254 GLES20.glUniform1i(mTexUnitLoc, 0); 255 GLES20.glUseProgram(0); 256 257 return true; 258 } 259 260 private void destroyGLShaders() { 261 GLES20.glDeleteProgram(mProgram); 262 checkGlErrors("glDeleteProgram"); 263 } 264 265 private boolean initGLBuffers() { 266 //Fill vertices 267 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight); 268 269 // Setup GL Textures 270 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]); 271 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, 272 GLES20.GL_NEAREST); 273 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, 274 GLES20.GL_NEAREST); 275 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, 276 GLES20.GL_CLAMP_TO_EDGE); 277 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, 278 GLES20.GL_CLAMP_TO_EDGE); 279 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 280 281 // Setup GL Buffers 282 GLES20.glGenBuffers(2, mGLBuffers, 0); 283 284 // fill vertex buffer 285 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]); 286 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4, 287 mVertexBuffer, GLES20.GL_STATIC_DRAW); 288 289 // fill tex buffer 290 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]); 291 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4, 292 mTexCoordBuffer, GLES20.GL_STATIC_DRAW); 293 294 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 295 296 return true; 297 } 298 299 private void destroyGLBuffers() { 300 GLES20.glDeleteBuffers(2, mGLBuffers, 0); 301 checkGlErrors("glDeleteBuffers"); 302 } 303 304 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) { 305 if (DEBUG) { 306 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h); 307 } 308 vtx.put(0, x); 309 vtx.put(1, y); 310 vtx.put(2, x); 311 vtx.put(3, y + h); 312 vtx.put(4, x + w); 313 vtx.put(5, y + h); 314 vtx.put(6, x + w); 315 vtx.put(7, y); 316 } 317 318 /** 319 * Dismisses the color fade animation surface and cleans up. 320 * 321 * To prevent stray photons from leaking out after the color fade has been 322 * turned off, it is a good idea to defer dismissing the animation until the 323 * color fade has been turned back on fully. 324 */ 325 public void dismiss() { 326 if (DEBUG) { 327 Slog.d(TAG, "dismiss"); 328 } 329 330 if (mPrepared) { 331 attachEglContext(); 332 try { 333 destroyScreenshotTexture(); 334 destroyGLShaders(); 335 destroyGLBuffers(); 336 destroyEglSurface(); 337 } finally { 338 detachEglContext(); 339 } 340 destroySurface(); 341 GLES20.glFlush(); 342 mPrepared = false; 343 } 344 } 345 346 /** 347 * Draws an animation frame showing the color fade activated at the 348 * specified level. 349 * 350 * @param level The color fade level. 351 * @return True if successful. 352 */ 353 public boolean draw(float level) { 354 if (DEBUG) { 355 Slog.d(TAG, "drawFrame: level=" + level); 356 } 357 358 if (!mPrepared) { 359 return false; 360 } 361 362 if (mMode == MODE_FADE) { 363 return showSurface(1.0f - level); 364 } 365 366 if (!attachEglContext()) { 367 return false; 368 } 369 try { 370 // Clear frame to solid black. 371 GLES20.glClearColor(0f, 0f, 0f, 1f); 372 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 373 374 // Draw the frame. 375 float one_minus_level = 1 - level; 376 float cos = FloatMath.cos((float)Math.PI * one_minus_level); 377 float sign = cos < 0 ? -1 : 1; 378 float opacity = -FloatMath.pow(one_minus_level, 2) + 1; 379 float saturation = FloatMath.pow(level, 4); 380 float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f; 381 float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f; 382 drawFaded(opacity, 1.f / gamma, saturation, scale); 383 if (checkGlErrors("drawFrame")) { 384 return false; 385 } 386 387 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); 388 } finally { 389 detachEglContext(); 390 } 391 return showSurface(1.0f); 392 } 393 394 private void drawFaded(float opacity, float gamma, float saturation, float scale) { 395 if (DEBUG) { 396 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma + 397 ", saturation=" + saturation + ", scale=" + scale); 398 } 399 // Use shaders 400 GLES20.glUseProgram(mProgram); 401 402 // Set Uniforms 403 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0); 404 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0); 405 GLES20.glUniform1f(mOpacityLoc, opacity); 406 GLES20.glUniform1f(mGammaLoc, gamma); 407 GLES20.glUniform1f(mSaturationLoc, saturation); 408 GLES20.glUniform1f(mScaleLoc, scale); 409 410 // Use textures 411 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 412 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]); 413 414 // draw the plane 415 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]); 416 GLES20.glEnableVertexAttribArray(mVertexLoc); 417 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0); 418 419 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]); 420 GLES20.glEnableVertexAttribArray(mTexCoordLoc); 421 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0); 422 423 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4); 424 425 // clean up 426 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 427 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 428 } 429 430 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) { 431 mProjMatrix[0] = 2f / (right - left); 432 mProjMatrix[1] = 0; 433 mProjMatrix[2] = 0; 434 mProjMatrix[3] = 0; 435 mProjMatrix[4] = 0; 436 mProjMatrix[5] = 2f / (top - bottom); 437 mProjMatrix[6] = 0; 438 mProjMatrix[7] = 0; 439 mProjMatrix[8] = 0; 440 mProjMatrix[9] = 0; 441 mProjMatrix[10] = -2f / (zfar - znear); 442 mProjMatrix[11] = 0; 443 mProjMatrix[12] = -(right + left) / (right - left); 444 mProjMatrix[13] = -(top + bottom) / (top - bottom); 445 mProjMatrix[14] = -(zfar + znear) / (zfar - znear); 446 mProjMatrix[15] = 1f; 447 } 448 449 private boolean captureScreenshotTextureAndSetViewport() { 450 if (!attachEglContext()) { 451 return false; 452 } 453 try { 454 if (!mTexNamesGenerated) { 455 GLES20.glGenTextures(1, mTexNames, 0); 456 if (checkGlErrors("glGenTextures")) { 457 return false; 458 } 459 mTexNamesGenerated = true; 460 } 461 462 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]); 463 final Surface s = new Surface(st); 464 try { 465 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( 466 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s); 467 st.updateTexImage(); 468 st.getTransformMatrix(mTexMatrix); 469 } finally { 470 s.release(); 471 st.release(); 472 } 473 474 // Set up texture coordinates for a quad. 475 // We might need to change this if the texture ends up being 476 // a different size from the display for some reason. 477 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f); 478 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f); 479 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f); 480 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f); 481 482 // Set up our viewport. 483 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight); 484 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1); 485 } finally { 486 detachEglContext(); 487 } 488 return true; 489 } 490 491 private void destroyScreenshotTexture() { 492 if (mTexNamesGenerated) { 493 mTexNamesGenerated = false; 494 GLES20.glDeleteTextures(1, mTexNames, 0); 495 checkGlErrors("glDeleteTextures"); 496 } 497 } 498 499 private boolean createEglContext() { 500 if (mEglDisplay == null) { 501 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 502 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) { 503 logEglError("eglGetDisplay"); 504 return false; 505 } 506 507 int[] version = new int[2]; 508 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { 509 mEglDisplay = null; 510 logEglError("eglInitialize"); 511 return false; 512 } 513 } 514 515 if (mEglConfig == null) { 516 int[] eglConfigAttribList = new int[] { 517 EGL14.EGL_RENDERABLE_TYPE, 518 EGL14.EGL_OPENGL_ES2_BIT, 519 EGL14.EGL_RED_SIZE, 8, 520 EGL14.EGL_GREEN_SIZE, 8, 521 EGL14.EGL_BLUE_SIZE, 8, 522 EGL14.EGL_ALPHA_SIZE, 8, 523 EGL14.EGL_NONE 524 }; 525 int[] numEglConfigs = new int[1]; 526 EGLConfig[] eglConfigs = new EGLConfig[1]; 527 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0, 528 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { 529 logEglError("eglChooseConfig"); 530 return false; 531 } 532 mEglConfig = eglConfigs[0]; 533 } 534 535 if (mEglContext == null) { 536 int[] eglContextAttribList = new int[] { 537 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 538 EGL14.EGL_NONE 539 }; 540 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, 541 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0); 542 if (mEglContext == null) { 543 logEglError("eglCreateContext"); 544 return false; 545 } 546 } 547 return true; 548 } 549 550 private boolean createSurface() { 551 if (mSurfaceSession == null) { 552 mSurfaceSession = new SurfaceSession(); 553 } 554 555 SurfaceControl.openTransaction(); 556 try { 557 if (mSurfaceControl == null) { 558 try { 559 int flags; 560 if (mMode == MODE_FADE) { 561 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN; 562 } else { 563 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN; 564 } 565 mSurfaceControl = new SurfaceControl(mSurfaceSession, 566 "ColorFade", mDisplayWidth, mDisplayHeight, 567 PixelFormat.OPAQUE, flags); 568 } catch (OutOfResourcesException ex) { 569 Slog.e(TAG, "Unable to create surface.", ex); 570 return false; 571 } 572 } 573 574 mSurfaceControl.setLayerStack(mDisplayLayerStack); 575 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight); 576 mSurface = new Surface(); 577 mSurface.copyFrom(mSurfaceControl); 578 579 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, 580 mDisplayId, mSurfaceControl); 581 mSurfaceLayout.onDisplayTransaction(); 582 } finally { 583 SurfaceControl.closeTransaction(); 584 } 585 return true; 586 } 587 588 private boolean createEglSurface() { 589 if (mEglSurface == null) { 590 int[] eglSurfaceAttribList = new int[] { 591 EGL14.EGL_NONE 592 }; 593 // turn our SurfaceControl into a Surface 594 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, 595 eglSurfaceAttribList, 0); 596 if (mEglSurface == null) { 597 logEglError("eglCreateWindowSurface"); 598 return false; 599 } 600 } 601 return true; 602 } 603 604 private void destroyEglSurface() { 605 if (mEglSurface != null) { 606 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) { 607 logEglError("eglDestroySurface"); 608 } 609 mEglSurface = null; 610 } 611 } 612 613 private void destroySurface() { 614 if (mSurfaceControl != null) { 615 mSurfaceLayout.dispose(); 616 mSurfaceLayout = null; 617 SurfaceControl.openTransaction(); 618 try { 619 mSurfaceControl.destroy(); 620 mSurface.release(); 621 } finally { 622 SurfaceControl.closeTransaction(); 623 } 624 mSurfaceControl = null; 625 mSurfaceVisible = false; 626 mSurfaceAlpha = 0f; 627 } 628 } 629 630 private boolean showSurface(float alpha) { 631 if (!mSurfaceVisible || mSurfaceAlpha != alpha) { 632 SurfaceControl.openTransaction(); 633 try { 634 mSurfaceControl.setLayer(COLOR_FADE_LAYER); 635 mSurfaceControl.setAlpha(alpha); 636 mSurfaceControl.show(); 637 } finally { 638 SurfaceControl.closeTransaction(); 639 } 640 mSurfaceVisible = true; 641 mSurfaceAlpha = alpha; 642 } 643 return true; 644 } 645 646 private boolean attachEglContext() { 647 if (mEglSurface == null) { 648 return false; 649 } 650 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 651 logEglError("eglMakeCurrent"); 652 return false; 653 } 654 return true; 655 } 656 657 private void detachEglContext() { 658 if (mEglDisplay != null) { 659 EGL14.eglMakeCurrent(mEglDisplay, 660 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); 661 } 662 } 663 664 private static FloatBuffer createNativeFloatBuffer(int size) { 665 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4); 666 bb.order(ByteOrder.nativeOrder()); 667 return bb.asFloatBuffer(); 668 } 669 670 private static void logEglError(String func) { 671 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable()); 672 } 673 674 private static boolean checkGlErrors(String func) { 675 return checkGlErrors(func, true); 676 } 677 678 private static boolean checkGlErrors(String func, boolean log) { 679 boolean hadError = false; 680 int error; 681 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 682 if (log) { 683 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 684 } 685 hadError = true; 686 } 687 return hadError; 688 } 689 690 public void dump(PrintWriter pw) { 691 pw.println(); 692 pw.println("Color Fade State:"); 693 pw.println(" mPrepared=" + mPrepared); 694 pw.println(" mMode=" + mMode); 695 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack); 696 pw.println(" mDisplayWidth=" + mDisplayWidth); 697 pw.println(" mDisplayHeight=" + mDisplayHeight); 698 pw.println(" mSurfaceVisible=" + mSurfaceVisible); 699 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha); 700 } 701 702 /** 703 * Keeps a surface aligned with the natural orientation of the device. 704 * Updates the position and transformation of the matrix whenever the display 705 * is rotated. This is a little tricky because the display transaction 706 * callback can be invoked on any thread, not necessarily the thread that 707 * owns the color fade. 708 */ 709 private static final class NaturalSurfaceLayout implements DisplayTransactionListener { 710 private final DisplayManagerInternal mDisplayManagerInternal; 711 private final int mDisplayId; 712 private SurfaceControl mSurfaceControl; 713 714 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal, 715 int displayId, SurfaceControl surfaceControl) { 716 mDisplayManagerInternal = displayManagerInternal; 717 mDisplayId = displayId; 718 mSurfaceControl = surfaceControl; 719 mDisplayManagerInternal.registerDisplayTransactionListener(this); 720 } 721 722 public void dispose() { 723 synchronized (this) { 724 mSurfaceControl = null; 725 } 726 mDisplayManagerInternal.unregisterDisplayTransactionListener(this); 727 } 728 729 @Override 730 public void onDisplayTransaction() { 731 synchronized (this) { 732 if (mSurfaceControl == null) { 733 return; 734 } 735 736 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); 737 switch (displayInfo.rotation) { 738 case Surface.ROTATION_0: 739 mSurfaceControl.setPosition(0, 0); 740 mSurfaceControl.setMatrix(1, 0, 0, 1); 741 break; 742 case Surface.ROTATION_90: 743 mSurfaceControl.setPosition(0, displayInfo.logicalHeight); 744 mSurfaceControl.setMatrix(0, -1, 1, 0); 745 break; 746 case Surface.ROTATION_180: 747 mSurfaceControl.setPosition(displayInfo.logicalWidth, 748 displayInfo.logicalHeight); 749 mSurfaceControl.setMatrix(-1, 0, 0, -1); 750 break; 751 case Surface.ROTATION_270: 752 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0); 753 mSurfaceControl.setMatrix(0, 1, -1, 0); 754 break; 755 } 756 } 757 } 758 } 759 } 760