blob: 0cb036837bc689176ff8dc1bf97338a1a38893b0 [file] [log] [blame]
/*
* Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)
*
* Modified by Elijah Cornell
* 2013.01 Modified by Jaroslaw Wisniewski <j.wisniewski@appsisle.com>
* 2014.04 Modified by davebaol
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.badlogic.gdx.backends.android;
import java.lang.reflect.Method;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.EGLConfigChooser;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.View;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20;
import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20API18;
import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewAPI18;
import com.badlogic.gdx.backends.android.surfaceview.ResolutionStrategy;
import com.badlogic.gdx.utils.GdxRuntimeException;
/** A subclass of {@link AndroidGraphics} specialized for live wallpaper applications.
*
* @author mzechner */
public final class AndroidGraphicsLiveWallpaper extends AndroidGraphics {
public AndroidGraphicsLiveWallpaper (AndroidLiveWallpaper lwp, AndroidApplicationConfiguration config,
ResolutionStrategy resolutionStrategy) {
super(lwp, config, resolutionStrategy, false);
}
// jw: I replaced GL..SurfaceViewLW classes with their original counterparts, if it will work
// on known devices, on opengl 1.0 and 2.0, and all possible SDK versions.. You can remove
// GL..SurfaceViewLW family of classes completely (there is no use for them).
// -> specific for live wallpapers
// jw: synchronized access to current wallpaper surface holder
SurfaceHolder getSurfaceHolder () {
synchronized (((AndroidLiveWallpaper)app).service.sync) {
return ((AndroidLiveWallpaper)app).service.getSurfaceHolder();
}
}
// <- specific for live wallpapers
// Grabbed from AndroidGraphics superclass and modified to override
// getHolder in created GLSurfaceView and GLSurfaceViewAPI18 instances
@Override
protected View createGLSurfaceView (AndroidApplicationBase application, final ResolutionStrategy resolutionStrategy) {
if (!checkGL20()) throw new GdxRuntimeException("Libgdx requires OpenGL ES 2.0");
EGLConfigChooser configChooser = getEglConfigChooser();
int sdkVersion = android.os.Build.VERSION.SDK_INT;
if (sdkVersion <= 10 && config.useGLSurfaceView20API18) {
GLSurfaceView20API18 view = new GLSurfaceView20API18(application.getContext(), resolutionStrategy) {
@Override
public SurfaceHolder getHolder () {
return getSurfaceHolder();
}
// This method is invoked via reflection by AndroidLiveWallpaper.onDestroy()
public void onDestroy () {
onDetachedFromWindow(); // calls GLSurfaceView.mGLThread.requestExitAndWait();
}
};
if (configChooser != null)
view.setEGLConfigChooser(configChooser);
else
view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
view.setRenderer(this);
return view;
}
else {
GLSurfaceView20 view = new GLSurfaceView20(application.getContext(), resolutionStrategy) {
@Override
public SurfaceHolder getHolder () {
return getSurfaceHolder();
}
// This method is invoked via reflection by AndroidLiveWallpaper.onDestroy()
public void onDestroy () {
onDetachedFromWindow(); // calls GLSurfaceView.mGLThread.requestExitAndWait();
}
};
if (configChooser != null)
view.setEGLConfigChooser(configChooser);
else
view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
view.setRenderer(this);
return view;
}
}
// kill the GLThread managed by GLSurfaceView (only for GLSurfaceView because GLSurffaceViewCupcake stops thread in
// onPause events - which is not as easy and safe for GLSurfaceView)
public void onDestroyGLSurfaceView () {
if (view != null) {
if (view instanceof GLSurfaceView || view instanceof GLSurfaceViewAPI18) {
try {
// onDestroy redirects to onDetachedFromWindow - which stops GLThread by calling mGLThread.requestExitAndWait()
view.getClass().getMethod("onDestroy").invoke(view);
if (AndroidLiveWallpaperService.DEBUG)
Log.d(AndroidLiveWallpaperService.TAG,
" > AndroidLiveWallpaper - onDestroy() stopped GLThread managed by GLSurfaceView");
} catch (Throwable t) {
// error while scheduling exit of GLThread, GLThread will remain live and wallpaper service
// wouldn't be able to shutdown completely
Log.e(AndroidLiveWallpaperService.TAG,
"failed to destroy GLSurfaceView's thread! GLSurfaceView.onDetachedFromWindow impl changed since API lvl 16!");
t.printStackTrace();
}
}
}
}
@Override
void resume () {
synchronized (synch) {
running = true;
resume = true;
// by jw: added synchronization, there was nothing before
while (resume) {
try {
requestRendering();
synch.wait();
} catch (InterruptedException ignored) {
Gdx.app.log("AndroidGraphics", "waiting for resume synchronization failed!");
}
}
}
}
@Override
public void onDrawFrame (javax.microedition.khronos.opengles.GL10 gl) {
long time = System.nanoTime();
deltaTime = (time - lastFrameTime) / 1000000000.0f;
lastFrameTime = time;
// After pause deltaTime can have somewhat huge value that destabilizes the mean, so let's cut it off
if (!resume) {
mean.addValue(deltaTime);
} else {
deltaTime = 0;
}
boolean lrunning = false;
boolean lpause = false;
boolean ldestroy = false;
boolean lresume = false;
synchronized (synch) {
lrunning = running;
lpause = pause;
ldestroy = destroy;
lresume = resume;
if (resume) {
resume = false;
// by jw: originally was not synchronized
synch.notifyAll();
}
if (pause) {
pause = false;
synch.notifyAll();
}
if (destroy) {
destroy = false;
synch.notifyAll();
}
}
if (lresume) {
// ((AndroidAudio)app.getAudio()).resume(); // jw: moved to AndroidLiveWallpaper.onResume
app.getApplicationListener().resume();
Gdx.app.log("AndroidGraphics", "resumed");
}
// HACK: added null check to handle set wallpaper from preview null
// error in renderer
// jw: this hack is not working always, renderer ends with error for some devices - because of uninitialized gl context
// jw: now it shouldn't be necessary - after wallpaper backend refactoring:)
if (lrunning) {
// jw: changed
synchronized (app.getRunnables()) {
app.getExecutedRunnables().clear();
app.getExecutedRunnables().addAll(app.getRunnables());
app.getRunnables().clear();
for (int i = 0; i < app.getExecutedRunnables().size; i++) {
try {
app.getExecutedRunnables().get(i).run();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
/*
* synchronized (app.runnables) { for (int i = 0; i < app.runnables.size; i++) { app.runnables.get(i).run(); }
* app.runnables.clear(); }
*/
app.getInput().processEvents();
frameId++;
app.getApplicationListener().render();
}
// jw: never called on lvp, why? see description in AndroidLiveWallpaper.onPause
if (lpause) {
app.getApplicationListener().pause();
// ((AndroidAudio)app.getAudio()).pause(); jw: moved to AndroidLiveWallpaper.onPause
Gdx.app.log("AndroidGraphics", "paused");
}
// jw: never called on lwp, why? see description in AndroidLiveWallpaper.onPause
if (ldestroy) {
app.getApplicationListener().dispose();
// ((AndroidAudio)app.getAudio()).dispose(); jw: moved to AndroidLiveWallpaper.onDestroy
Gdx.app.log("AndroidGraphics", "destroyed");
}
if (time - frameStart > 1000000000) {
fps = frames;
frames = 0;
frameStart = time;
}
frames++;
}
@Override
protected void logManagedCachesStatus() {
// to prevent creating too many string buffers in live wallpapers
if (AndroidLiveWallpaperService.DEBUG) {
super.logManagedCachesStatus();
}
}
}