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 = null; 405 mBackground = mWallpaperManager.getBitmap(); 406 } catch (RuntimeException e) { 407 exception = e; 408 } catch (OutOfMemoryError e) { 409 exception = e; 410 } 411 412 if (exception != null) { 413 mBackground = null; 414 // Note that if we do fail at this, and the default wallpaper can't 415 // be loaded, we will go into a cycle. Don't do a build where the 416 // default wallpaper can't be loaded. 417 Log.w(TAG, "Unable to load wallpaper!", exception); 418 try { 419 mWallpaperManager.clear(); 420 } catch (IOException ex) { 421 // now we're really screwed. 422 Log.w(TAG, "Unable reset to default wallpaper!", ex); 423 } 424 } 425 } 426 427 private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) { 428 Canvas c = sh.lockCanvas(); 429 if (c != null) { 430 try { 431 if (DEBUG) { 432 Log.d(TAG, "Redrawing: x=" + x + ", y=" + y); 433 } 434 435 c.translate(x, y); 436 if (w < 0 || h < 0) { 437 c.save(Canvas.CLIP_SAVE_FLAG); 438 c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(), 439 Op.DIFFERENCE); 440 c.drawColor(0xff000000); 441 c.restore(); 442 } 443 if (mBackground != null) { 444 c.drawBitmap(mBackground, 0, 0, null); 445 } 446 } finally { 447 sh.unlockCanvasAndPost(c); 448 } 449 } 450 } 451 452 private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) { 453 if (!initGL(sh)) return false; 454 455 final float right = left + mBackground.getWidth(); 456 final float bottom = top + mBackground.getHeight(); 457 458 final Rect frame = sh.getSurfaceFrame(); 459 final Matrix4f ortho = new Matrix4f(); 460 ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f); 461 462 final FloatBuffer triangleVertices = createMesh(left, top, right, bottom); 463 464 final int texture = loadTexture(mBackground); 465 final int program = buildProgram(sSimpleVS, sSimpleFS); 466 467 final int attribPosition = glGetAttribLocation(program, "position"); 468 final int attribTexCoords = glGetAttribLocation(program, "texCoords"); 469 final int uniformTexture = glGetUniformLocation(program, "texture"); 470 final int uniformProjection = glGetUniformLocation(program, "projection"); 471 472 checkGlError(); 473 474 glViewport(0, 0, frame.width(), frame.height()); 475 glBindTexture(GL_TEXTURE_2D, texture); 476 477 glUseProgram(program); 478 glEnableVertexAttribArray(attribPosition); 479 glEnableVertexAttribArray(attribTexCoords); 480 glUniform1i(uniformTexture, 0); 481 glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0); 482 483 checkGlError(); 484 485 if (w < 0 || h < 0) { 486 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 487 glClear(GL_COLOR_BUFFER_BIT); 488 } 489 490 // drawQuad 491 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 492 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 493 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 494 495 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 496 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 497 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 498 499 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 500 501 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 502 throw new RuntimeException("Cannot swap buffers"); 503 } 504 checkEglError(); 505 506 finishGL(); 507 508 return true; 509 } 510 511 private FloatBuffer createMesh(int left, int top, float right, float bottom) { 512 final float[] verticesData = { 513 // X, Y, Z, U, V 514 left, bottom, 0.0f, 0.0f, 1.0f, 515 right, bottom, 0.0f, 1.0f, 1.0f, 516 left, top, 0.0f, 0.0f, 0.0f, 517 right, top, 0.0f, 1.0f, 0.0f, 518 }; 519 520 final int bytes = verticesData.length * FLOAT_SIZE_BYTES; 521 final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order( 522 ByteOrder.nativeOrder()).asFloatBuffer(); 523 triangleVertices.put(verticesData).position(0); 524 return triangleVertices; 525 } 526 527 private int loadTexture(Bitmap bitmap) { 528 int[] textures = new int[1]; 529 530 glActiveTexture(GL_TEXTURE0); 531 glGenTextures(1, textures, 0); 532 checkGlError(); 533 534 int texture = textures[0]; 535 glBindTexture(GL_TEXTURE_2D, texture); 536 checkGlError(); 537 538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 539 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 540 541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 543 544 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 545 checkGlError(); 546 547 return texture; 548 } 549 550 private int buildProgram(String vertex, String fragment) { 551 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 552 if (vertexShader == 0) return 0; 553 554 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 555 if (fragmentShader == 0) return 0; 556 557 int program = glCreateProgram(); 558 glAttachShader(program, vertexShader); 559 checkGlError(); 560 561 glAttachShader(program, fragmentShader); 562 checkGlError(); 563 564 glLinkProgram(program); 565 checkGlError(); 566 567 int[] status = new int[1]; 568 glGetProgramiv(program, GL_LINK_STATUS, status, 0); 569 if (status[0] != GL_TRUE) { 570 String error = glGetProgramInfoLog(program); 571 Log.d(GL_LOG_TAG, "Error while linking program:\n" + error); 572 glDeleteShader(vertexShader); 573 glDeleteShader(fragmentShader); 574 glDeleteProgram(program); 575 return 0; 576 } 577 578 return program; 579 } 580 581 private int buildShader(String source, int type) { 582 int shader = glCreateShader(type); 583 584 glShaderSource(shader, source); 585 checkGlError(); 586 587 glCompileShader(shader); 588 checkGlError(); 589 590 int[] status = new int[1]; 591 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 592 if (status[0] != GL_TRUE) { 593 String error = glGetShaderInfoLog(shader); 594 Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error); 595 glDeleteShader(shader); 596 return 0; 597 } 598 599 return shader; 600 } 601 602 private void checkEglError() { 603 int error = mEgl.eglGetError(); 604 if (error != EGL_SUCCESS) { 605 Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error)); 606 } 607 } 608 609 private void checkGlError() { 610 int error = glGetError(); 611 if (error != GL_NO_ERROR) { 612 Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable()); 613 } 614 } 615 616 private void finishGL() { 617 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 618 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 619 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 620 } 621 622 private boolean initGL(SurfaceHolder surfaceHolder) { 623 mEgl = (EGL10) EGLContext.getEGL(); 624 625 mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 626 if (mEglDisplay == EGL_NO_DISPLAY) { 627 throw new RuntimeException("eglGetDisplay failed " + 628 GLUtils.getEGLErrorString(mEgl.eglGetError())); 629 } 630 631 int[] version = new int[2]; 632 if (!mEgl.eglInitialize(mEglDisplay, version)) { 633 throw new RuntimeException("eglInitialize failed " + 634 GLUtils.getEGLErrorString(mEgl.eglGetError())); 635 } 636 637 mEglConfig = chooseEglConfig(); 638 if (mEglConfig == null) { 639 throw new RuntimeException("eglConfig not initialized"); 640 } 641 642 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 643 644 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null); 645 646 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 647 int error = mEgl.eglGetError(); 648 if (error == EGL_BAD_NATIVE_WINDOW) { 649 Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 650 return false; 651 } 652 throw new RuntimeException("createWindowSurface failed " + 653 GLUtils.getEGLErrorString(error)); 654 } 655 656 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 657 throw new RuntimeException("eglMakeCurrent failed " + 658 GLUtils.getEGLErrorString(mEgl.eglGetError())); 659 } 660 661 mGL = mEglContext.getGL(); 662 663 return true; 664 } 665 666 667 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 668 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 669 return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); 670 } 671 672 private EGLConfig chooseEglConfig() { 673 int[] configsCount = new int[1]; 674 EGLConfig[] configs = new EGLConfig[1]; 675 int[] configSpec = getConfig(); 676 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 677 throw new IllegalArgumentException("eglChooseConfig failed " + 678 GLUtils.getEGLErrorString(mEgl.eglGetError())); 679 } else if (configsCount[0] > 0) { 680 return configs[0]; 681 } 682 return null; 683 } 684 685 private int[] getConfig() { 686 return new int[] { 687 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 688 EGL_RED_SIZE, 8, 689 EGL_GREEN_SIZE, 8, 690 EGL_BLUE_SIZE, 8, 691 EGL_ALPHA_SIZE, 0, 692 EGL_DEPTH_SIZE, 0, 693 EGL_STENCIL_SIZE, 0, 694 EGL_CONFIG_CAVEAT, EGL_NONE, 695 EGL_NONE 696 }; 697 } 698 } 699} 700