ImageWallpaper.java revision 5f0d976b37b919b74509b6f22e4ad3fa56422f6c
1/* 2 * Copyright (C) 2009 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.systemui; 18 19import android.app.ActivityManager; 20import android.app.WallpaperManager; 21import android.content.BroadcastReceiver; 22import android.content.ComponentCallbacks2; 23import android.content.Context; 24import android.content.Intent; 25import android.graphics.Bitmap; 26import android.graphics.Canvas; 27import android.graphics.Rect; 28import android.graphics.Region.Op; 29import android.opengl.GLUtils; 30import android.os.SystemProperties; 31import android.renderscript.Matrix4f; 32import android.service.wallpaper.WallpaperService; 33import android.util.Log; 34import android.view.Display; 35import android.view.MotionEvent; 36import android.view.SurfaceHolder; 37import android.view.WindowManager; 38 39import javax.microedition.khronos.egl.EGL10; 40import javax.microedition.khronos.egl.EGLConfig; 41import javax.microedition.khronos.egl.EGLContext; 42import javax.microedition.khronos.egl.EGLDisplay; 43import javax.microedition.khronos.egl.EGLSurface; 44import javax.microedition.khronos.opengles.GL; 45import java.io.IOException; 46import java.nio.ByteBuffer; 47import java.nio.ByteOrder; 48import java.nio.FloatBuffer; 49 50import static android.opengl.GLES20.*; 51import static javax.microedition.khronos.egl.EGL10.*; 52 53/** 54 * Default built-in wallpaper that simply shows a static image. 55 */ 56@SuppressWarnings({"UnusedDeclaration"}) 57public class ImageWallpaper extends WallpaperService { 58 private static final String TAG = "ImageWallpaper"; 59 private static final String GL_LOG_TAG = "ImageWallpaperGL"; 60 private static final boolean DEBUG = false; 61 private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu"; 62 63 static final boolean FIXED_SIZED_SURFACE = true; 64 static final boolean USE_OPENGL = true; 65 66 WallpaperManager mWallpaperManager; 67 68 DrawableEngine mEngine; 69 70 boolean mIsHwAccelerated; 71 72 @Override 73 public void onCreate() { 74 super.onCreate(); 75 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE); 76 77 //noinspection PointlessBooleanExpression,ConstantConditions 78 if (FIXED_SIZED_SURFACE && USE_OPENGL) { 79 if (!isEmulator()) { 80 mIsHwAccelerated = ActivityManager.isHighEndGfx(); 81 } 82 } 83 } 84 85 @Override 86 public void onTrimMemory(int level) { 87 if (mEngine != null) { 88 mEngine.trimMemory(level); 89 } 90 } 91 92 private static boolean isEmulator() { 93 return "1".equals(SystemProperties.get(PROPERTY_KERNEL_QEMU, "0")); 94 } 95 96 public Engine onCreateEngine() { 97 mEngine = new DrawableEngine(); 98 return mEngine; 99 } 100 101 class DrawableEngine extends Engine { 102 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 103 static final int EGL_OPENGL_ES2_BIT = 4; 104 105 private final Object mLock = new Object[0]; 106 107 // TODO: Not currently used, keeping around until we know we don't need it 108 @SuppressWarnings({"UnusedDeclaration"}) 109 private WallpaperObserver mReceiver; 110 111 Bitmap mBackground; 112 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; 113 int mLastRotation = -1; 114 float mXOffset; 115 float mYOffset; 116 117 boolean mVisible = true; 118 boolean mRedrawNeeded; 119 boolean mOffsetsChanged; 120 int mLastXTranslation; 121 int mLastYTranslation; 122 123 private EGL10 mEgl; 124 private EGLDisplay mEglDisplay; 125 private EGLConfig mEglConfig; 126 private EGLContext mEglContext; 127 private EGLSurface mEglSurface; 128 private GL mGL; 129 130 private static final String sSimpleVS = 131 "attribute vec4 position;\n" + 132 "attribute vec2 texCoords;\n" + 133 "varying vec2 outTexCoords;\n" + 134 "uniform mat4 projection;\n" + 135 "\nvoid main(void) {\n" + 136 " outTexCoords = texCoords;\n" + 137 " gl_Position = projection * position;\n" + 138 "}\n\n"; 139 private static final String sSimpleFS = 140 "precision mediump float;\n\n" + 141 "varying vec2 outTexCoords;\n" + 142 "uniform sampler2D texture;\n" + 143 "\nvoid main(void) {\n" + 144 " gl_FragColor = texture2D(texture, outTexCoords);\n" + 145 "}\n\n"; 146 147 private static final int FLOAT_SIZE_BYTES = 4; 148 private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 149 private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 150 private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 151 152 class WallpaperObserver extends BroadcastReceiver { 153 public void onReceive(Context context, Intent intent) { 154 if (DEBUG) { 155 Log.d(TAG, "onReceive"); 156 } 157 158 synchronized (mLock) { 159 mLastSurfaceWidth = mLastSurfaceHeight = -1; 160 mBackground = null; 161 mRedrawNeeded = true; 162 drawFrameLocked(); 163 } 164 } 165 } 166 167 public DrawableEngine() { 168 super(); 169 setFixedSizeAllowed(true); 170 } 171 172 public void trimMemory(int level) { 173 if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW && 174 mBackground != null && mIsHwAccelerated) { 175 if (DEBUG) { 176 Log.d(TAG, "trimMemory"); 177 } 178 mBackground.recycle(); 179 mBackground = null; 180 mWallpaperManager.forgetLoadedWallpaper(); 181 } 182 } 183 184 @Override 185 public void onCreate(SurfaceHolder surfaceHolder) { 186 if (DEBUG) { 187 Log.d(TAG, "onCreate"); 188 } 189 190 super.onCreate(surfaceHolder); 191 192 // TODO: Don't need this currently because the wallpaper service 193 // will restart the image wallpaper whenever the image changes. 194 //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 195 //mReceiver = new WallpaperObserver(); 196 //registerReceiver(mReceiver, filter, null, mHandler); 197 198 updateSurfaceSize(surfaceHolder); 199 200 setOffsetNotificationsEnabled(false); 201 } 202 203 @Override 204 public void onDestroy() { 205 super.onDestroy(); 206 if (mReceiver != null) { 207 unregisterReceiver(mReceiver); 208 } 209 } 210 211 @Override 212 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 213 super.onDesiredSizeChanged(desiredWidth, desiredHeight); 214 SurfaceHolder surfaceHolder = getSurfaceHolder(); 215 if (surfaceHolder != null) { 216 updateSurfaceSize(surfaceHolder); 217 } 218 } 219 220 void updateSurfaceSize(SurfaceHolder surfaceHolder) { 221 if (FIXED_SIZED_SURFACE) { 222 // Used a fixed size surface, because we are special. We can do 223 // this because we know the current design of window animations doesn't 224 // cause this to break. 225 surfaceHolder.setFixedSize(getDesiredMinimumWidth(), getDesiredMinimumHeight()); 226 } else { 227 surfaceHolder.setSizeFromLayout(); 228 } 229 } 230 231 @Override 232 public void onVisibilityChanged(boolean visible) { 233 if (DEBUG) { 234 Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible); 235 } 236 237 synchronized (mLock) { 238 if (mVisible != visible) { 239 if (DEBUG) { 240 Log.d(TAG, "Visibility changed to visible=" + visible); 241 } 242 mVisible = visible; 243 drawFrameLocked(); 244 } 245 } 246 } 247 248 @Override 249 public void onTouchEvent(MotionEvent event) { 250 super.onTouchEvent(event); 251 } 252 253 @Override 254 public void onOffsetsChanged(float xOffset, float yOffset, 255 float xOffsetStep, float yOffsetStep, 256 int xPixels, int yPixels) { 257 if (DEBUG) { 258 Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset 259 + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep 260 + ", xPixels=" + xPixels + ", yPixels=" + yPixels); 261 } 262 263 synchronized (mLock) { 264 if (mXOffset != xOffset || mYOffset != yOffset) { 265 if (DEBUG) { 266 Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ")."); 267 } 268 mXOffset = xOffset; 269 mYOffset = yOffset; 270 mOffsetsChanged = true; 271 } 272 drawFrameLocked(); 273 } 274 } 275 276 @Override 277 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 278 if (DEBUG) { 279 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height); 280 } 281 282 super.onSurfaceChanged(holder, format, width, height); 283 284 synchronized (mLock) { 285 drawFrameLocked(); 286 } 287 } 288 289 @Override 290 public void onSurfaceDestroyed(SurfaceHolder holder) { 291 super.onSurfaceDestroyed(holder); 292 mLastSurfaceWidth = mLastSurfaceHeight = -1; 293 } 294 295 @Override 296 public void onSurfaceCreated(SurfaceHolder holder) { 297 super.onSurfaceCreated(holder); 298 mLastSurfaceWidth = mLastSurfaceHeight = -1; 299 } 300 301 @Override 302 public void onSurfaceRedrawNeeded(SurfaceHolder holder) { 303 if (DEBUG) { 304 Log.d(TAG, "onSurfaceRedrawNeeded"); 305 } 306 super.onSurfaceRedrawNeeded(holder); 307 308 synchronized (mLock) { 309 drawFrameLocked(); 310 } 311 } 312 313 void drawFrameLocked() { 314 SurfaceHolder sh = getSurfaceHolder(); 315 final Rect frame = sh.getSurfaceFrame(); 316 final int dw = frame.width(); 317 final int dh = frame.height(); 318 int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)). 319 getDefaultDisplay().getRotation(); 320 boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight; 321 322 boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation; 323 if (!redrawNeeded && !mOffsetsChanged) { 324 if (DEBUG) { 325 Log.d(TAG, "Suppressed drawFrame since redraw is not needed " 326 + "and offsets have not changed."); 327 } 328 return; 329 } 330 mLastRotation = newRotation; 331 332 // Load bitmap if it is not yet loaded or if it was loaded at a different size 333 if (mBackground == null || surfaceDimensionsChanged) { 334 if (DEBUG) { 335 Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " + 336 mBackground + ", " + 337 ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " + 338 ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " + 339 dw + ", " + dh); 340 } 341 updateWallpaperLocked(); 342 if (mBackground == null) { 343 if (DEBUG) { 344 Log.d(TAG, "Unable to load bitmap"); 345 } 346 return; 347 } 348 if (DEBUG) { 349 if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) { 350 Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " + 351 dw + ", " + dh + ", " + mBackground.getWidth() + ", " + 352 mBackground.getHeight()); 353 } 354 } 355 } 356 357 final int availw = dw - mBackground.getWidth(); 358 final int availh = dh - mBackground.getHeight(); 359 int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2); 360 int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2); 361 362 mOffsetsChanged = false; 363 mRedrawNeeded = false; 364 if (surfaceDimensionsChanged) { 365 mLastSurfaceWidth = dw; 366 mLastSurfaceHeight = dh; 367 } 368 mLastXTranslation = xPixels; 369 mLastYTranslation = yPixels; 370 if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) { 371 if (DEBUG) { 372 Log.d(TAG, "Suppressed drawFrame since the image has not " 373 + "actually moved an integral number of pixels."); 374 } 375 return; 376 } 377 378 if (DEBUG) { 379 Log.d(TAG, "Redrawing wallpaper"); 380 } 381 if (mIsHwAccelerated) { 382 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) { 383 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 384 } 385 } else { 386 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 387 if (FIXED_SIZED_SURFACE) { 388 // If the surface is fixed-size, we should only need to 389 // draw it once and then we'll let the window manager 390 // position it appropriately. As such, we no longer needed 391 // the loaded bitmap. Yay! 392 // hw-accelerated path retains bitmap for faster rotation 393 mBackground = null; 394 mWallpaperManager.forgetLoadedWallpaper(); 395 } 396 } 397 398 } 399 400 private void updateWallpaperLocked() { 401 Throwable exception = null; 402 try { 403 mWallpaperManager.forgetLoadedWallpaper(); // force reload 404 mBackground = mWallpaperManager.getBitmap(); 405 } catch (RuntimeException e) { 406 exception = e; 407 } catch (OutOfMemoryError e) { 408 exception = e; 409 } 410 411 if (exception != null) { 412 mBackground = null; 413 // Note that if we do fail at this, and the default wallpaper can't 414 // be loaded, we will go into a cycle. Don't do a build where the 415 // default wallpaper can't be loaded. 416 Log.w(TAG, "Unable to load wallpaper!", exception); 417 try { 418 mWallpaperManager.clear(); 419 } catch (IOException ex) { 420 // now we're really screwed. 421 Log.w(TAG, "Unable reset to default wallpaper!", ex); 422 } 423 } 424 } 425 426 private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) { 427 Canvas c = sh.lockCanvas(); 428 if (c != null) { 429 try { 430 if (DEBUG) { 431 Log.d(TAG, "Redrawing: x=" + x + ", y=" + y); 432 } 433 434 c.translate(x, y); 435 if (w < 0 || h < 0) { 436 c.save(Canvas.CLIP_SAVE_FLAG); 437 c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(), 438 Op.DIFFERENCE); 439 c.drawColor(0xff000000); 440 c.restore(); 441 } 442 if (mBackground != null) { 443 c.drawBitmap(mBackground, 0, 0, null); 444 } 445 } finally { 446 sh.unlockCanvasAndPost(c); 447 } 448 } 449 } 450 451 private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) { 452 if (!initGL(sh)) return false; 453 454 final float right = left + mBackground.getWidth(); 455 final float bottom = top + mBackground.getHeight(); 456 457 final Rect frame = sh.getSurfaceFrame(); 458 final Matrix4f ortho = new Matrix4f(); 459 ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f); 460 461 final FloatBuffer triangleVertices = createMesh(left, top, right, bottom); 462 463 final int texture = loadTexture(mBackground); 464 final int program = buildProgram(sSimpleVS, sSimpleFS); 465 466 final int attribPosition = glGetAttribLocation(program, "position"); 467 final int attribTexCoords = glGetAttribLocation(program, "texCoords"); 468 final int uniformTexture = glGetUniformLocation(program, "texture"); 469 final int uniformProjection = glGetUniformLocation(program, "projection"); 470 471 checkGlError(); 472 473 glViewport(0, 0, frame.width(), frame.height()); 474 glBindTexture(GL_TEXTURE_2D, texture); 475 476 glUseProgram(program); 477 glEnableVertexAttribArray(attribPosition); 478 glEnableVertexAttribArray(attribTexCoords); 479 glUniform1i(uniformTexture, 0); 480 glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0); 481 482 checkGlError(); 483 484 if (w < 0 || h < 0) { 485 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 486 glClear(GL_COLOR_BUFFER_BIT); 487 } 488 489 // drawQuad 490 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 491 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 492 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 493 494 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 495 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 496 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 497 498 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 499 500 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 501 throw new RuntimeException("Cannot swap buffers"); 502 } 503 checkEglError(); 504 505 finishGL(); 506 507 return true; 508 } 509 510 private FloatBuffer createMesh(int left, int top, float right, float bottom) { 511 final float[] verticesData = { 512 // X, Y, Z, U, V 513 left, bottom, 0.0f, 0.0f, 1.0f, 514 right, bottom, 0.0f, 1.0f, 1.0f, 515 left, top, 0.0f, 0.0f, 0.0f, 516 right, top, 0.0f, 1.0f, 0.0f, 517 }; 518 519 final int bytes = verticesData.length * FLOAT_SIZE_BYTES; 520 final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order( 521 ByteOrder.nativeOrder()).asFloatBuffer(); 522 triangleVertices.put(verticesData).position(0); 523 return triangleVertices; 524 } 525 526 private int loadTexture(Bitmap bitmap) { 527 int[] textures = new int[1]; 528 529 glActiveTexture(GL_TEXTURE0); 530 glGenTextures(1, textures, 0); 531 checkGlError(); 532 533 int texture = textures[0]; 534 glBindTexture(GL_TEXTURE_2D, texture); 535 checkGlError(); 536 537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 539 540 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 542 543 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 544 checkGlError(); 545 546 return texture; 547 } 548 549 private int buildProgram(String vertex, String fragment) { 550 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 551 if (vertexShader == 0) return 0; 552 553 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 554 if (fragmentShader == 0) return 0; 555 556 int program = glCreateProgram(); 557 glAttachShader(program, vertexShader); 558 checkGlError(); 559 560 glAttachShader(program, fragmentShader); 561 checkGlError(); 562 563 glLinkProgram(program); 564 checkGlError(); 565 566 int[] status = new int[1]; 567 glGetProgramiv(program, GL_LINK_STATUS, status, 0); 568 if (status[0] != GL_TRUE) { 569 String error = glGetProgramInfoLog(program); 570 Log.d(GL_LOG_TAG, "Error while linking program:\n" + error); 571 glDeleteShader(vertexShader); 572 glDeleteShader(fragmentShader); 573 glDeleteProgram(program); 574 return 0; 575 } 576 577 return program; 578 } 579 580 private int buildShader(String source, int type) { 581 int shader = glCreateShader(type); 582 583 glShaderSource(shader, source); 584 checkGlError(); 585 586 glCompileShader(shader); 587 checkGlError(); 588 589 int[] status = new int[1]; 590 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 591 if (status[0] != GL_TRUE) { 592 String error = glGetShaderInfoLog(shader); 593 Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error); 594 glDeleteShader(shader); 595 return 0; 596 } 597 598 return shader; 599 } 600 601 private void checkEglError() { 602 int error = mEgl.eglGetError(); 603 if (error != EGL_SUCCESS) { 604 Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error)); 605 } 606 } 607 608 private void checkGlError() { 609 int error = glGetError(); 610 if (error != GL_NO_ERROR) { 611 Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable()); 612 } 613 } 614 615 private void finishGL() { 616 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 617 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 618 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 619 } 620 621 private boolean initGL(SurfaceHolder surfaceHolder) { 622 mEgl = (EGL10) EGLContext.getEGL(); 623 624 mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 625 if (mEglDisplay == EGL_NO_DISPLAY) { 626 throw new RuntimeException("eglGetDisplay failed " + 627 GLUtils.getEGLErrorString(mEgl.eglGetError())); 628 } 629 630 int[] version = new int[2]; 631 if (!mEgl.eglInitialize(mEglDisplay, version)) { 632 throw new RuntimeException("eglInitialize failed " + 633 GLUtils.getEGLErrorString(mEgl.eglGetError())); 634 } 635 636 mEglConfig = chooseEglConfig(); 637 if (mEglConfig == null) { 638 throw new RuntimeException("eglConfig not initialized"); 639 } 640 641 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 642 643 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null); 644 645 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 646 int error = mEgl.eglGetError(); 647 if (error == EGL_BAD_NATIVE_WINDOW) { 648 Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 649 return false; 650 } 651 throw new RuntimeException("createWindowSurface failed " + 652 GLUtils.getEGLErrorString(error)); 653 } 654 655 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 656 throw new RuntimeException("eglMakeCurrent failed " + 657 GLUtils.getEGLErrorString(mEgl.eglGetError())); 658 } 659 660 mGL = mEglContext.getGL(); 661 662 return true; 663 } 664 665 666 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 667 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 668 return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); 669 } 670 671 private EGLConfig chooseEglConfig() { 672 int[] configsCount = new int[1]; 673 EGLConfig[] configs = new EGLConfig[1]; 674 int[] configSpec = getConfig(); 675 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 676 throw new IllegalArgumentException("eglChooseConfig failed " + 677 GLUtils.getEGLErrorString(mEgl.eglGetError())); 678 } else if (configsCount[0] > 0) { 679 return configs[0]; 680 } 681 return null; 682 } 683 684 private int[] getConfig() { 685 return new int[] { 686 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 687 EGL_RED_SIZE, 8, 688 EGL_GREEN_SIZE, 8, 689 EGL_BLUE_SIZE, 8, 690 EGL_ALPHA_SIZE, 0, 691 EGL_DEPTH_SIZE, 0, 692 EGL_STENCIL_SIZE, 0, 693 EGL_CONFIG_CAVEAT, EGL_NONE, 694 EGL_NONE 695 }; 696 } 697 } 698} 699