1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 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.badlogic.gdx.backends.android; 18 19 import java.text.NumberFormat; 20 import java.text.ParseException; 21 22 import javax.microedition.khronos.egl.EGL10; 23 import javax.microedition.khronos.egl.EGLConfig; 24 import javax.microedition.khronos.egl.EGLContext; 25 import javax.microedition.khronos.egl.EGLDisplay; 26 import javax.microedition.khronos.opengles.GL10; 27 28 import android.opengl.GLSurfaceView; 29 import android.opengl.GLSurfaceView.EGLConfigChooser; 30 import android.opengl.GLSurfaceView.Renderer; 31 import android.util.DisplayMetrics; 32 import android.view.Display; 33 import android.view.View; 34 import android.view.WindowManager.LayoutParams; 35 36 import com.badlogic.gdx.Application; 37 import com.badlogic.gdx.Gdx; 38 import com.badlogic.gdx.Graphics; 39 import com.badlogic.gdx.LifecycleListener; 40 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20; 41 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20API18; 42 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewAPI18; 43 import com.badlogic.gdx.backends.android.surfaceview.GdxEglConfigChooser; 44 import com.badlogic.gdx.backends.android.surfaceview.ResolutionStrategy; 45 import com.badlogic.gdx.graphics.Cubemap; 46 import com.badlogic.gdx.graphics.Cursor; 47 import com.badlogic.gdx.graphics.Cursor.SystemCursor; 48 import com.badlogic.gdx.graphics.GL20; 49 import com.badlogic.gdx.graphics.GL30; 50 import com.badlogic.gdx.graphics.Mesh; 51 import com.badlogic.gdx.graphics.Pixmap; 52 import com.badlogic.gdx.graphics.Texture; 53 import com.badlogic.gdx.graphics.TextureArray; 54 import com.badlogic.gdx.graphics.glutils.FrameBuffer; 55 import com.badlogic.gdx.graphics.glutils.GLVersion; 56 import com.badlogic.gdx.graphics.glutils.ShaderProgram; 57 import com.badlogic.gdx.math.WindowedMean; 58 import com.badlogic.gdx.utils.Array; 59 import com.badlogic.gdx.utils.GdxRuntimeException; 60 import com.badlogic.gdx.utils.SnapshotArray; 61 62 /** An implementation of {@link Graphics} for Android. 63 * 64 * @author mzechner */ 65 public class AndroidGraphics implements Graphics, Renderer { 66 67 private static final String LOG_TAG = "AndroidGraphics"; 68 69 /** When {@link AndroidFragmentApplication#onPause()} or {@link AndroidApplication#onPause()} call 70 * {@link AndroidGraphics#pause()} they <b>MUST</b> enforce continuous rendering. If not, {@link #onDrawFrame(GL10)} will not 71 * be called in the GLThread while {@link #pause()} is sleeping in the Android UI Thread which will cause the 72 * {@link AndroidGraphics#pause} variable never be set to false. As a result, the {@link AndroidGraphics#pause()} method will 73 * kill the current process to avoid ANR */ 74 static volatile boolean enforceContinuousRendering = false; 75 76 final View view; 77 int width; 78 int height; 79 AndroidApplicationBase app; 80 GL20 gl20; 81 GL30 gl30; 82 EGLContext eglContext; 83 GLVersion glVersion; 84 String extensions; 85 86 protected long lastFrameTime = System.nanoTime(); 87 protected float deltaTime = 0; 88 protected long frameStart = System.nanoTime(); 89 protected long frameId = -1; 90 protected int frames = 0; 91 protected int fps; 92 protected WindowedMean mean = new WindowedMean(5); 93 94 volatile boolean created = false; 95 volatile boolean running = false; 96 volatile boolean pause = false; 97 volatile boolean resume = false; 98 volatile boolean destroy = false; 99 100 private float ppiX = 0; 101 private float ppiY = 0; 102 private float ppcX = 0; 103 private float ppcY = 0; 104 private float density = 1; 105 106 protected final AndroidApplicationConfiguration config; 107 private BufferFormat bufferFormat = new BufferFormat(5, 6, 5, 0, 16, 0, 0, false); 108 private boolean isContinuous = true; 109 110 public AndroidGraphics (AndroidApplicationBase application, AndroidApplicationConfiguration config, 111 ResolutionStrategy resolutionStrategy) { 112 this(application, config, resolutionStrategy, true); 113 } 114 115 public AndroidGraphics (AndroidApplicationBase application, AndroidApplicationConfiguration config, 116 ResolutionStrategy resolutionStrategy, boolean focusableView) { 117 this.config = config; 118 this.app = application; 119 view = createGLSurfaceView(application, resolutionStrategy); 120 preserveEGLContextOnPause(); 121 if (focusableView) { 122 view.setFocusable(true); 123 view.setFocusableInTouchMode(true); 124 } 125 } 126 127 protected void preserveEGLContextOnPause () { 128 int sdkVersion = android.os.Build.VERSION.SDK_INT; 129 if ((sdkVersion >= 11 && view instanceof GLSurfaceView20) || view instanceof GLSurfaceView20API18) { 130 try { 131 view.getClass().getMethod("setPreserveEGLContextOnPause", boolean.class).invoke(view, true); 132 } catch (Exception e) { 133 Gdx.app.log(LOG_TAG, "Method GLSurfaceView.setPreserveEGLContextOnPause not found"); 134 } 135 } 136 } 137 138 protected View createGLSurfaceView (AndroidApplicationBase application, final ResolutionStrategy resolutionStrategy) { 139 if (!checkGL20()) throw new GdxRuntimeException("Libgdx requires OpenGL ES 2.0"); 140 141 EGLConfigChooser configChooser = getEglConfigChooser(); 142 int sdkVersion = android.os.Build.VERSION.SDK_INT; 143 if (sdkVersion <= 10 && config.useGLSurfaceView20API18) { 144 GLSurfaceView20API18 view = new GLSurfaceView20API18(application.getContext(), resolutionStrategy); 145 if (configChooser != null) 146 view.setEGLConfigChooser(configChooser); 147 else 148 view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil); 149 view.setRenderer(this); 150 return view; 151 } else { 152 GLSurfaceView20 view = new GLSurfaceView20(application.getContext(), resolutionStrategy, config.useGL30 ? 3 : 2); 153 if (configChooser != null) 154 view.setEGLConfigChooser(configChooser); 155 else 156 view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil); 157 view.setRenderer(this); 158 return view; 159 } 160 } 161 162 public void onPauseGLSurfaceView () { 163 if (view != null) { 164 if (view instanceof GLSurfaceViewAPI18) ((GLSurfaceViewAPI18)view).onPause(); 165 if (view instanceof GLSurfaceView) ((GLSurfaceView)view).onPause(); 166 } 167 } 168 169 public void onResumeGLSurfaceView () { 170 if (view != null) { 171 if (view instanceof GLSurfaceViewAPI18) ((GLSurfaceViewAPI18)view).onResume(); 172 if (view instanceof GLSurfaceView) ((GLSurfaceView)view).onResume(); 173 } 174 } 175 176 protected EGLConfigChooser getEglConfigChooser () { 177 return new GdxEglConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil, config.numSamples); 178 } 179 180 private void updatePpi () { 181 DisplayMetrics metrics = new DisplayMetrics(); 182 app.getWindowManager().getDefaultDisplay().getMetrics(metrics); 183 184 ppiX = metrics.xdpi; 185 ppiY = metrics.ydpi; 186 ppcX = metrics.xdpi / 2.54f; 187 ppcY = metrics.ydpi / 2.54f; 188 density = metrics.density; 189 } 190 191 protected boolean checkGL20 () { 192 EGL10 egl = (EGL10)EGLContext.getEGL(); 193 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 194 195 int[] version = new int[2]; 196 egl.eglInitialize(display, version); 197 198 int EGL_OPENGL_ES2_BIT = 4; 199 int[] configAttribs = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, 200 EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; 201 202 EGLConfig[] configs = new EGLConfig[10]; 203 int[] num_config = new int[1]; 204 egl.eglChooseConfig(display, configAttribs, configs, 10, num_config); 205 egl.eglTerminate(display); 206 return num_config[0] > 0; 207 } 208 209 /** {@inheritDoc} */ 210 @Override 211 public GL20 getGL20 () { 212 return gl20; 213 } 214 215 /** {@inheritDoc} */ 216 @Override 217 public int getHeight () { 218 return height; 219 } 220 221 /** {@inheritDoc} */ 222 @Override 223 public int getWidth () { 224 return width; 225 } 226 227 @Override 228 public int getBackBufferWidth () { 229 return width; 230 } 231 232 @Override 233 public int getBackBufferHeight () { 234 return height; 235 } 236 237 /** This instantiates the GL10, GL11 and GL20 instances. Includes the check for certain devices that pretend to support GL11 but 238 * fuck up vertex buffer objects. This includes the pixelflinger which segfaults when buffers are deleted as well as the 239 * Motorola CLIQ and the Samsung Behold II. 240 * 241 * @param gl */ 242 private void setupGL (javax.microedition.khronos.opengles.GL10 gl) { 243 String versionString = gl.glGetString(GL10.GL_VERSION); 244 String vendorString = gl.glGetString(GL10.GL_VENDOR); 245 String rendererString = gl.glGetString(GL10.GL_RENDERER); 246 glVersion = new GLVersion(Application.ApplicationType.Android, versionString, vendorString, rendererString); 247 if (config.useGL30 && glVersion.getMajorVersion() > 2) { 248 if (gl30 != null) return; 249 gl20 = gl30 = new AndroidGL30(); 250 251 Gdx.gl = gl30; 252 Gdx.gl20 = gl30; 253 Gdx.gl30 = gl30; 254 } else { 255 if (gl20 != null) return; 256 gl20 = new AndroidGL20(); 257 258 Gdx.gl = gl20; 259 Gdx.gl20 = gl20; 260 } 261 262 Gdx.app.log(LOG_TAG, "OGL renderer: " + gl.glGetString(GL10.GL_RENDERER)); 263 Gdx.app.log(LOG_TAG, "OGL vendor: " + gl.glGetString(GL10.GL_VENDOR)); 264 Gdx.app.log(LOG_TAG, "OGL version: " + gl.glGetString(GL10.GL_VERSION)); 265 Gdx.app.log(LOG_TAG, "OGL extensions: " + gl.glGetString(GL10.GL_EXTENSIONS)); 266 } 267 268 @Override 269 public void onSurfaceChanged (javax.microedition.khronos.opengles.GL10 gl, int width, int height) { 270 this.width = width; 271 this.height = height; 272 updatePpi(); 273 gl.glViewport(0, 0, this.width, this.height); 274 if (created == false) { 275 app.getApplicationListener().create(); 276 created = true; 277 synchronized (this) { 278 running = true; 279 } 280 } 281 app.getApplicationListener().resize(width, height); 282 } 283 284 @Override 285 public void onSurfaceCreated (javax.microedition.khronos.opengles.GL10 gl, EGLConfig config) { 286 eglContext = ((EGL10)EGLContext.getEGL()).eglGetCurrentContext(); 287 setupGL(gl); 288 logConfig(config); 289 updatePpi(); 290 291 Mesh.invalidateAllMeshes(app); 292 Texture.invalidateAllTextures(app); 293 Cubemap.invalidateAllCubemaps(app); 294 TextureArray.invalidateAllTextureArrays(app); 295 ShaderProgram.invalidateAllShaderPrograms(app); 296 FrameBuffer.invalidateAllFrameBuffers(app); 297 298 logManagedCachesStatus(); 299 300 Display display = app.getWindowManager().getDefaultDisplay(); 301 this.width = display.getWidth(); 302 this.height = display.getHeight(); 303 this.mean = new WindowedMean(5); 304 this.lastFrameTime = System.nanoTime(); 305 306 gl.glViewport(0, 0, this.width, this.height); 307 } 308 309 private void logConfig (EGLConfig config) { 310 EGL10 egl = (EGL10)EGLContext.getEGL(); 311 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 312 int r = getAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); 313 int g = getAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); 314 int b = getAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); 315 int a = getAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); 316 int d = getAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); 317 int s = getAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); 318 int samples = Math.max(getAttrib(egl, display, config, EGL10.EGL_SAMPLES, 0), 319 getAttrib(egl, display, config, GdxEglConfigChooser.EGL_COVERAGE_SAMPLES_NV, 0)); 320 boolean coverageSample = getAttrib(egl, display, config, GdxEglConfigChooser.EGL_COVERAGE_SAMPLES_NV, 0) != 0; 321 322 Gdx.app.log(LOG_TAG, "framebuffer: (" + r + ", " + g + ", " + b + ", " + a + ")"); 323 Gdx.app.log(LOG_TAG, "depthbuffer: (" + d + ")"); 324 Gdx.app.log(LOG_TAG, "stencilbuffer: (" + s + ")"); 325 Gdx.app.log(LOG_TAG, "samples: (" + samples + ")"); 326 Gdx.app.log(LOG_TAG, "coverage sampling: (" + coverageSample + ")"); 327 328 bufferFormat = new BufferFormat(r, g, b, a, d, s, samples, coverageSample); 329 } 330 331 int[] value = new int[1]; 332 333 private int getAttrib (EGL10 egl, EGLDisplay display, EGLConfig config, int attrib, int defValue) { 334 if (egl.eglGetConfigAttrib(display, config, attrib, value)) { 335 return value[0]; 336 } 337 return defValue; 338 } 339 340 Object synch = new Object(); 341 342 void resume () { 343 synchronized (synch) { 344 running = true; 345 resume = true; 346 } 347 } 348 349 void pause () { 350 synchronized (synch) { 351 if (!running) return; 352 running = false; 353 pause = true; 354 while (pause) { 355 try { 356 // TODO: fix deadlock race condition with quick resume/pause. 357 // Temporary workaround: 358 // Android ANR time is 5 seconds, so wait up to 4 seconds before assuming 359 // deadlock and killing process. This can easily be triggered by opening the 360 // Recent Apps list and then double-tapping the Recent Apps button with 361 // ~500ms between taps. 362 synch.wait(4000); 363 if (pause) { 364 // pause will never go false if onDrawFrame is never called by the GLThread 365 // when entering this method, we MUST enforce continuous rendering 366 Gdx.app.error(LOG_TAG, "waiting for pause synchronization took too long; assuming deadlock and killing"); 367 android.os.Process.killProcess(android.os.Process.myPid()); 368 } 369 } catch (InterruptedException ignored) { 370 Gdx.app.log(LOG_TAG, "waiting for pause synchronization failed!"); 371 } 372 } 373 } 374 } 375 376 void destroy () { 377 synchronized (synch) { 378 running = false; 379 destroy = true; 380 381 while (destroy) { 382 try { 383 synch.wait(); 384 } catch (InterruptedException ex) { 385 Gdx.app.log(LOG_TAG, "waiting for destroy synchronization failed!"); 386 } 387 } 388 } 389 } 390 391 @Override 392 public void onDrawFrame (javax.microedition.khronos.opengles.GL10 gl) { 393 long time = System.nanoTime(); 394 deltaTime = (time - lastFrameTime) / 1000000000.0f; 395 lastFrameTime = time; 396 397 // After pause deltaTime can have somewhat huge value that destabilizes the mean, so let's cut it off 398 if (!resume) { 399 mean.addValue(deltaTime); 400 } else { 401 deltaTime = 0; 402 } 403 404 boolean lrunning = false; 405 boolean lpause = false; 406 boolean ldestroy = false; 407 boolean lresume = false; 408 409 synchronized (synch) { 410 lrunning = running; 411 lpause = pause; 412 ldestroy = destroy; 413 lresume = resume; 414 415 if (resume) { 416 resume = false; 417 } 418 419 if (pause) { 420 pause = false; 421 synch.notifyAll(); 422 } 423 424 if (destroy) { 425 destroy = false; 426 synch.notifyAll(); 427 } 428 } 429 430 if (lresume) { 431 SnapshotArray<LifecycleListener> lifecycleListeners = app.getLifecycleListeners(); 432 synchronized (lifecycleListeners) { 433 LifecycleListener[] listeners = lifecycleListeners.begin(); 434 for (int i = 0, n = lifecycleListeners.size; i < n; ++i) { 435 listeners[i].resume(); 436 } 437 lifecycleListeners.end(); 438 } 439 app.getApplicationListener().resume(); 440 Gdx.app.log(LOG_TAG, "resumed"); 441 } 442 443 if (lrunning) { 444 synchronized (app.getRunnables()) { 445 app.getExecutedRunnables().clear(); 446 app.getExecutedRunnables().addAll(app.getRunnables()); 447 app.getRunnables().clear(); 448 } 449 450 for (int i = 0; i < app.getExecutedRunnables().size; i++) { 451 try { 452 app.getExecutedRunnables().get(i).run(); 453 } catch (Throwable t) { 454 t.printStackTrace(); 455 } 456 } 457 app.getInput().processEvents(); 458 frameId++; 459 app.getApplicationListener().render(); 460 } 461 462 if (lpause) { 463 SnapshotArray<LifecycleListener> lifecycleListeners = app.getLifecycleListeners(); 464 synchronized (lifecycleListeners) { 465 LifecycleListener[] listeners = lifecycleListeners.begin(); 466 for (int i = 0, n = lifecycleListeners.size; i < n; ++i) { 467 listeners[i].pause(); 468 } 469 } 470 app.getApplicationListener().pause(); 471 Gdx.app.log(LOG_TAG, "paused"); 472 } 473 474 if (ldestroy) { 475 SnapshotArray<LifecycleListener> lifecycleListeners = app.getLifecycleListeners(); 476 synchronized (lifecycleListeners) { 477 LifecycleListener[] listeners = lifecycleListeners.begin(); 478 for (int i = 0, n = lifecycleListeners.size; i < n; ++i) { 479 listeners[i].dispose(); 480 } 481 } 482 app.getApplicationListener().dispose(); 483 Gdx.app.log(LOG_TAG, "destroyed"); 484 } 485 486 if (time - frameStart > 1000000000) { 487 fps = frames; 488 frames = 0; 489 frameStart = time; 490 } 491 frames++; 492 } 493 494 @Override 495 public long getFrameId () { 496 return frameId; 497 } 498 499 /** {@inheritDoc} */ 500 @Override 501 public float getDeltaTime () { 502 return mean.getMean() == 0 ? deltaTime : mean.getMean(); 503 } 504 505 @Override 506 public float getRawDeltaTime () { 507 return deltaTime; 508 } 509 510 /** {@inheritDoc} */ 511 @Override 512 public GraphicsType getType () { 513 return GraphicsType.AndroidGL; 514 } 515 516 /** {@inheritDoc} */ 517 @Override 518 public GLVersion getGLVersion () { 519 return glVersion; 520 } 521 522 /** {@inheritDoc} */ 523 @Override 524 public int getFramesPerSecond () { 525 return fps; 526 } 527 528 public void clearManagedCaches () { 529 Mesh.clearAllMeshes(app); 530 Texture.clearAllTextures(app); 531 Cubemap.clearAllCubemaps(app); 532 TextureArray.clearAllTextureArrays(app); 533 ShaderProgram.clearAllShaderPrograms(app); 534 FrameBuffer.clearAllFrameBuffers(app); 535 536 logManagedCachesStatus(); 537 } 538 539 protected void logManagedCachesStatus () { 540 Gdx.app.log(LOG_TAG, Mesh.getManagedStatus()); 541 Gdx.app.log(LOG_TAG, Texture.getManagedStatus()); 542 Gdx.app.log(LOG_TAG, Cubemap.getManagedStatus()); 543 Gdx.app.log(LOG_TAG, ShaderProgram.getManagedStatus()); 544 Gdx.app.log(LOG_TAG, FrameBuffer.getManagedStatus()); 545 } 546 547 public View getView () { 548 return view; 549 } 550 551 @Override 552 public float getPpiX () { 553 return ppiX; 554 } 555 556 @Override 557 public float getPpiY () { 558 return ppiY; 559 } 560 561 @Override 562 public float getPpcX () { 563 return ppcX; 564 } 565 566 @Override 567 public float getPpcY () { 568 return ppcY; 569 } 570 571 @Override 572 public float getDensity () { 573 return density; 574 } 575 576 @Override 577 public boolean supportsDisplayModeChange () { 578 return false; 579 } 580 581 @Override 582 public boolean setFullscreenMode (DisplayMode displayMode) { 583 return false; 584 } 585 586 @Override 587 public Monitor getPrimaryMonitor () { 588 return new AndroidMonitor(0, 0, "Primary Monitor"); 589 } 590 591 @Override 592 public Monitor getMonitor () { 593 return getPrimaryMonitor(); 594 } 595 596 @Override 597 public Monitor[] getMonitors () { 598 return new Monitor[] { getPrimaryMonitor() }; 599 } 600 601 @Override 602 public DisplayMode[] getDisplayModes (Monitor monitor) { 603 return getDisplayModes(); 604 } 605 606 @Override 607 public DisplayMode getDisplayMode (Monitor monitor) { 608 return getDisplayMode(); 609 } 610 611 @Override 612 public DisplayMode[] getDisplayModes () { 613 return new DisplayMode[] {getDisplayMode()}; 614 } 615 616 @Override 617 public boolean setWindowedMode (int width, int height) { 618 return false; 619 } 620 621 @Override 622 public void setTitle (String title) { 623 624 } 625 626 @Override 627 public void setUndecorated (boolean undecorated) { 628 final int mask = (undecorated) ? 1 : 0; 629 app.getApplicationWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, mask); 630 } 631 632 @Override 633 public void setResizable (boolean resizable) { 634 635 } 636 637 @Override 638 public DisplayMode getDisplayMode () { 639 DisplayMetrics metrics = new DisplayMetrics(); 640 app.getWindowManager().getDefaultDisplay().getMetrics(metrics); 641 return new AndroidDisplayMode(metrics.widthPixels, metrics.heightPixels, 0, 0); 642 } 643 644 @Override 645 public BufferFormat getBufferFormat () { 646 return bufferFormat; 647 } 648 649 @Override 650 public void setVSync (boolean vsync) { 651 } 652 653 @Override 654 public boolean supportsExtension (String extension) { 655 if (extensions == null) extensions = Gdx.gl.glGetString(GL10.GL_EXTENSIONS); 656 return extensions.contains(extension); 657 } 658 659 @Override 660 public void setContinuousRendering (boolean isContinuous) { 661 if (view != null) { 662 // ignore setContinuousRendering(false) while pausing 663 this.isContinuous = enforceContinuousRendering || isContinuous; 664 int renderMode = this.isContinuous ? GLSurfaceView.RENDERMODE_CONTINUOUSLY : GLSurfaceView.RENDERMODE_WHEN_DIRTY; 665 if (view instanceof GLSurfaceViewAPI18) ((GLSurfaceViewAPI18)view).setRenderMode(renderMode); 666 if (view instanceof GLSurfaceView) ((GLSurfaceView)view).setRenderMode(renderMode); 667 mean.clear(); 668 } 669 } 670 671 @Override 672 public boolean isContinuousRendering () { 673 return isContinuous; 674 } 675 676 @Override 677 public void requestRendering () { 678 if (view != null) { 679 if (view instanceof GLSurfaceViewAPI18) ((GLSurfaceViewAPI18)view).requestRender(); 680 if (view instanceof GLSurfaceView) ((GLSurfaceView)view).requestRender(); 681 } 682 } 683 684 @Override 685 public boolean isFullscreen () { 686 return true; 687 } 688 689 @Override 690 public boolean isGL30Available () { 691 return gl30 != null; 692 } 693 694 @Override 695 public GL30 getGL30 () { 696 return gl30; 697 } 698 699 @Override 700 public Cursor newCursor (Pixmap pixmap, int xHotspot, int yHotspot) { 701 return null; 702 } 703 704 @Override 705 public void setCursor (Cursor cursor) { 706 } 707 708 @Override 709 public void setSystemCursor (SystemCursor systemCursor) { 710 } 711 712 private class AndroidDisplayMode extends DisplayMode { 713 protected AndroidDisplayMode (int width, int height, int refreshRate, int bitsPerPixel) { 714 super(width, height, refreshRate, bitsPerPixel); 715 } 716 } 717 718 private class AndroidMonitor extends Monitor { 719 public AndroidMonitor (int virtualX, int virtualY, String name) { 720 super(virtualX, virtualY, name); 721 } 722 } 723 } 724