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