ColorFade.java revision 0839adb25c6d1a9f4e06fc5a098ffd03c67dbe99
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.content.res.Resources; 29import android.graphics.PixelFormat; 30import android.graphics.SurfaceTexture; 31import android.hardware.display.DisplayManagerInternal; 32import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; 33import android.opengl.EGL14; 34import android.opengl.EGLConfig; 35import android.opengl.EGLContext; 36import android.opengl.EGLDisplay; 37import android.opengl.EGLSurface; 38import android.opengl.GLES20; 39import android.opengl.GLES11Ext; 40import android.util.FloatMath; 41import android.util.Slog; 42import android.view.DisplayInfo; 43import android.view.Surface.OutOfResourcesException; 44import android.view.Surface; 45import android.view.SurfaceControl; 46import android.view.SurfaceSession; 47 48import libcore.io.Streams; 49 50import com.android.server.LocalServices; 51import 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 */ 62final 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 if (vshader == 0 || fshader == 0) return false; 230 231 mProgram = GLES20.glCreateProgram(); 232 233 GLES20.glAttachShader(mProgram, vshader); 234 GLES20.glAttachShader(mProgram, 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 boolean initGLBuffers() { 258 //Fill vertices 259 setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight); 260 261 // Setup GL Textures 262 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]); 263 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, 264 GLES20.GL_NEAREST); 265 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, 266 GLES20.GL_NEAREST); 267 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, 268 GLES20.GL_CLAMP_TO_EDGE); 269 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, 270 GLES20.GL_CLAMP_TO_EDGE); 271 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 272 273 // Setup GL Buffers 274 GLES20.glGenBuffers(2, mGLBuffers, 0); 275 276 // fill vertex buffer 277 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]); 278 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4, 279 mVertexBuffer, GLES20.GL_STATIC_DRAW); 280 281 // fill tex buffer 282 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]); 283 GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4, 284 mTexCoordBuffer, GLES20.GL_STATIC_DRAW); 285 286 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 287 288 return true; 289 } 290 291 private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) { 292 if (DEBUG) { 293 Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h); 294 } 295 vtx.put(0, x); 296 vtx.put(1, y); 297 vtx.put(2, x); 298 vtx.put(3, y + h); 299 vtx.put(4, x + w); 300 vtx.put(5, y + h); 301 vtx.put(6, x + w); 302 vtx.put(7, y); 303 } 304 305 /** 306 * Dismisses the color fade animation surface and cleans up. 307 * 308 * To prevent stray photons from leaking out after the color fade has been 309 * turned off, it is a good idea to defer dismissing the animation until the 310 * color fade has been turned back on fully. 311 */ 312 public void dismiss() { 313 if (DEBUG) { 314 Slog.d(TAG, "dismiss"); 315 } 316 317 destroyScreenshotTexture(); 318 destroyEglSurface(); 319 destroySurface(); 320 mPrepared = false; 321 } 322 323 /** 324 * Draws an animation frame showing the color fade activated at the 325 * specified level. 326 * 327 * @param level The color fade level. 328 * @return True if successful. 329 */ 330 public boolean draw(float level) { 331 if (DEBUG) { 332 Slog.d(TAG, "drawFrame: level=" + level); 333 } 334 335 if (!mPrepared) { 336 return false; 337 } 338 339 if (mMode == MODE_FADE) { 340 return showSurface(1.0f - level); 341 } 342 343 if (!attachEglContext()) { 344 return false; 345 } 346 try { 347 // Clear frame to solid black. 348 GLES20.glClearColor(0f, 0f, 0f, 1f); 349 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 350 351 // Draw the frame. 352 float one_minus_level = 1 - level; 353 float cos = FloatMath.cos((float)Math.PI * one_minus_level); 354 float sign = cos < 0 ? -1 : 1; 355 float opacity = -FloatMath.pow(one_minus_level, 2) + 1; 356 float saturation = FloatMath.pow(level, 4); 357 float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f; 358 float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f; 359 drawFaded(opacity, 1.f / gamma, saturation, scale); 360 if (checkGlErrors("drawFrame")) { 361 return false; 362 } 363 364 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); 365 } finally { 366 detachEglContext(); 367 } 368 return showSurface(1.0f); 369 } 370 371 private void drawFaded(float opacity, float gamma, float saturation, float scale) { 372 if (DEBUG) { 373 Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma + 374 ", saturation=" + saturation + ", scale=" + scale); 375 } 376 // Use shaders 377 GLES20.glUseProgram(mProgram); 378 379 // Set Uniforms 380 GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0); 381 GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0); 382 GLES20.glUniform1f(mOpacityLoc, opacity); 383 GLES20.glUniform1f(mGammaLoc, gamma); 384 GLES20.glUniform1f(mSaturationLoc, saturation); 385 GLES20.glUniform1f(mScaleLoc, scale); 386 387 // Use textures 388 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 389 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]); 390 391 // draw the plane 392 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]); 393 GLES20.glEnableVertexAttribArray(mVertexLoc); 394 GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0); 395 396 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]); 397 GLES20.glEnableVertexAttribArray(mTexCoordLoc); 398 GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0); 399 400 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4); 401 402 // clean up 403 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 404 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 405 } 406 407 private void ortho(float left, float right, float bottom, float top, float znear, float zfar) { 408 mProjMatrix[0] = 2f / (right - left); 409 mProjMatrix[1] = 0; 410 mProjMatrix[2] = 0; 411 mProjMatrix[3] = 0; 412 mProjMatrix[4] = 0; 413 mProjMatrix[5] = 2f / (top - bottom); 414 mProjMatrix[6] = 0; 415 mProjMatrix[7] = 0; 416 mProjMatrix[8] = 0; 417 mProjMatrix[9] = 0; 418 mProjMatrix[10] = -2f / (zfar - znear); 419 mProjMatrix[11] = 0; 420 mProjMatrix[12] = -(right + left) / (right - left); 421 mProjMatrix[13] = -(top + bottom) / (top - bottom); 422 mProjMatrix[14] = -(zfar + znear) / (zfar - znear); 423 mProjMatrix[15] = 1f; 424 } 425 426 private boolean captureScreenshotTextureAndSetViewport() { 427 if (!attachEglContext()) { 428 return false; 429 } 430 try { 431 if (!mTexNamesGenerated) { 432 GLES20.glGenTextures(1, mTexNames, 0); 433 if (checkGlErrors("glGenTextures")) { 434 return false; 435 } 436 mTexNamesGenerated = true; 437 } 438 439 final SurfaceTexture st = new SurfaceTexture(mTexNames[0]); 440 final Surface s = new Surface(st); 441 try { 442 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( 443 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s); 444 } finally { 445 s.release(); 446 } 447 448 st.updateTexImage(); 449 st.getTransformMatrix(mTexMatrix); 450 451 // Set up texture coordinates for a quad. 452 // We might need to change this if the texture ends up being 453 // a different size from the display for some reason. 454 mTexCoordBuffer.put(0, 0f); mTexCoordBuffer.put(1, 0f); 455 mTexCoordBuffer.put(2, 0f); mTexCoordBuffer.put(3, 1f); 456 mTexCoordBuffer.put(4, 1f); mTexCoordBuffer.put(5, 1f); 457 mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f); 458 459 // Set up our viewport. 460 GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight); 461 ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1); 462 } finally { 463 detachEglContext(); 464 } 465 return true; 466 } 467 468 private void destroyScreenshotTexture() { 469 if (mTexNamesGenerated) { 470 mTexNamesGenerated = false; 471 if (attachEglContext()) { 472 try { 473 GLES20.glDeleteTextures(1, mTexNames, 0); 474 checkGlErrors("glDeleteTextures"); 475 } finally { 476 detachEglContext(); 477 } 478 } 479 } 480 } 481 482 private boolean createEglContext() { 483 if (mEglDisplay == null) { 484 mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 485 if (mEglDisplay == EGL14.EGL_NO_DISPLAY) { 486 logEglError("eglGetDisplay"); 487 return false; 488 } 489 490 int[] version = new int[2]; 491 if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { 492 mEglDisplay = null; 493 logEglError("eglInitialize"); 494 return false; 495 } 496 } 497 498 if (mEglConfig == null) { 499 int[] eglConfigAttribList = new int[] { 500 EGL14.EGL_RENDERABLE_TYPE, 501 EGL14.EGL_OPENGL_ES2_BIT, 502 EGL14.EGL_RED_SIZE, 8, 503 EGL14.EGL_GREEN_SIZE, 8, 504 EGL14.EGL_BLUE_SIZE, 8, 505 EGL14.EGL_ALPHA_SIZE, 8, 506 EGL14.EGL_NONE 507 }; 508 int[] numEglConfigs = new int[1]; 509 EGLConfig[] eglConfigs = new EGLConfig[1]; 510 if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0, 511 eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { 512 logEglError("eglChooseConfig"); 513 return false; 514 } 515 mEglConfig = eglConfigs[0]; 516 } 517 518 if (mEglContext == null) { 519 int[] eglContextAttribList = new int[] { 520 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 521 EGL14.EGL_NONE 522 }; 523 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, 524 EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0); 525 if (mEglContext == null) { 526 logEglError("eglCreateContext"); 527 return false; 528 } 529 } 530 return true; 531 } 532 533 private boolean createSurface() { 534 if (mSurfaceSession == null) { 535 mSurfaceSession = new SurfaceSession(); 536 } 537 538 SurfaceControl.openTransaction(); 539 try { 540 if (mSurfaceControl == null) { 541 try { 542 int flags; 543 if (mMode == MODE_FADE) { 544 flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN; 545 } else { 546 flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN; 547 } 548 mSurfaceControl = new SurfaceControl(mSurfaceSession, 549 "ColorFade", mDisplayWidth, mDisplayHeight, 550 PixelFormat.OPAQUE, flags); 551 } catch (OutOfResourcesException ex) { 552 Slog.e(TAG, "Unable to create surface.", ex); 553 return false; 554 } 555 } 556 557 mSurfaceControl.setLayerStack(mDisplayLayerStack); 558 mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight); 559 mSurface = new Surface(); 560 mSurface.copyFrom(mSurfaceControl); 561 562 mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, 563 mDisplayId, mSurfaceControl); 564 mSurfaceLayout.onDisplayTransaction(); 565 } finally { 566 SurfaceControl.closeTransaction(); 567 } 568 return true; 569 } 570 571 private boolean createEglSurface() { 572 if (mEglSurface == null) { 573 int[] eglSurfaceAttribList = new int[] { 574 EGL14.EGL_NONE 575 }; 576 // turn our SurfaceControl into a Surface 577 mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, 578 eglSurfaceAttribList, 0); 579 if (mEglSurface == null) { 580 logEglError("eglCreateWindowSurface"); 581 return false; 582 } 583 } 584 return true; 585 } 586 587 private void destroyEglSurface() { 588 if (mEglSurface != null) { 589 if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) { 590 logEglError("eglDestroySurface"); 591 } 592 mEglSurface = null; 593 } 594 } 595 596 private void destroySurface() { 597 if (mSurfaceControl != null) { 598 mSurfaceLayout.dispose(); 599 mSurfaceLayout = null; 600 SurfaceControl.openTransaction(); 601 try { 602 mSurfaceControl.destroy(); 603 mSurface.release(); 604 } finally { 605 SurfaceControl.closeTransaction(); 606 } 607 mSurfaceControl = null; 608 mSurfaceVisible = false; 609 mSurfaceAlpha = 0f; 610 } 611 } 612 613 private boolean showSurface(float alpha) { 614 if (!mSurfaceVisible || mSurfaceAlpha != alpha) { 615 SurfaceControl.openTransaction(); 616 try { 617 mSurfaceControl.setLayer(COLOR_FADE_LAYER); 618 mSurfaceControl.setAlpha(alpha); 619 mSurfaceControl.show(); 620 } finally { 621 SurfaceControl.closeTransaction(); 622 } 623 mSurfaceVisible = true; 624 mSurfaceAlpha = alpha; 625 } 626 return true; 627 } 628 629 private boolean attachEglContext() { 630 if (mEglSurface == null) { 631 return false; 632 } 633 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 634 logEglError("eglMakeCurrent"); 635 return false; 636 } 637 return true; 638 } 639 640 private void detachEglContext() { 641 if (mEglDisplay != null) { 642 EGL14.eglMakeCurrent(mEglDisplay, 643 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); 644 } 645 } 646 647 private static FloatBuffer createNativeFloatBuffer(int size) { 648 ByteBuffer bb = ByteBuffer.allocateDirect(size * 4); 649 bb.order(ByteOrder.nativeOrder()); 650 return bb.asFloatBuffer(); 651 } 652 653 private static void logEglError(String func) { 654 Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable()); 655 } 656 657 private static boolean checkGlErrors(String func) { 658 return checkGlErrors(func, true); 659 } 660 661 private static boolean checkGlErrors(String func, boolean log) { 662 boolean hadError = false; 663 int error; 664 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 665 if (log) { 666 Slog.e(TAG, func + " failed: error " + error, new Throwable()); 667 } 668 hadError = true; 669 } 670 return hadError; 671 } 672 673 public void dump(PrintWriter pw) { 674 pw.println(); 675 pw.println("Color Fade State:"); 676 pw.println(" mPrepared=" + mPrepared); 677 pw.println(" mMode=" + mMode); 678 pw.println(" mDisplayLayerStack=" + mDisplayLayerStack); 679 pw.println(" mDisplayWidth=" + mDisplayWidth); 680 pw.println(" mDisplayHeight=" + mDisplayHeight); 681 pw.println(" mSurfaceVisible=" + mSurfaceVisible); 682 pw.println(" mSurfaceAlpha=" + mSurfaceAlpha); 683 } 684 685 /** 686 * Keeps a surface aligned with the natural orientation of the device. 687 * Updates the position and transformation of the matrix whenever the display 688 * is rotated. This is a little tricky because the display transaction 689 * callback can be invoked on any thread, not necessarily the thread that 690 * owns the color fade. 691 */ 692 private static final class NaturalSurfaceLayout implements DisplayTransactionListener { 693 private final DisplayManagerInternal mDisplayManagerInternal; 694 private final int mDisplayId; 695 private SurfaceControl mSurfaceControl; 696 697 public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal, 698 int displayId, SurfaceControl surfaceControl) { 699 mDisplayManagerInternal = displayManagerInternal; 700 mDisplayId = displayId; 701 mSurfaceControl = surfaceControl; 702 mDisplayManagerInternal.registerDisplayTransactionListener(this); 703 } 704 705 public void dispose() { 706 synchronized (this) { 707 mSurfaceControl = null; 708 } 709 mDisplayManagerInternal.unregisterDisplayTransactionListener(this); 710 } 711 712 @Override 713 public void onDisplayTransaction() { 714 synchronized (this) { 715 if (mSurfaceControl == null) { 716 return; 717 } 718 719 DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); 720 switch (displayInfo.rotation) { 721 case Surface.ROTATION_0: 722 mSurfaceControl.setPosition(0, 0); 723 mSurfaceControl.setMatrix(1, 0, 0, 1); 724 break; 725 case Surface.ROTATION_90: 726 mSurfaceControl.setPosition(0, displayInfo.logicalHeight); 727 mSurfaceControl.setMatrix(0, -1, 1, 0); 728 break; 729 case Surface.ROTATION_180: 730 mSurfaceControl.setPosition(displayInfo.logicalWidth, 731 displayInfo.logicalHeight); 732 mSurfaceControl.setMatrix(-1, 0, 0, -1); 733 break; 734 case Surface.ROTATION_270: 735 mSurfaceControl.setPosition(displayInfo.logicalWidth, 0); 736 mSurfaceControl.setMatrix(0, 1, -1, 0); 737 break; 738 } 739 } 740 } 741 } 742} 743