• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)
3  *
4  * Modified by Elijah Cornell
5  * 2013.01 Modified by Jaroslaw Wisniewski <j.wisniewski@appsisle.com>
6  * 2014.04 Modified by davebaol
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
9  * License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
14  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  */
17 
18 package com.badlogic.gdx.backends.android;
19 
20 import java.lang.reflect.Method;
21 
22 import android.opengl.GLSurfaceView;
23 import android.opengl.GLSurfaceView.EGLConfigChooser;
24 import android.util.Log;
25 import android.view.SurfaceHolder;
26 import android.view.View;
27 
28 import com.badlogic.gdx.Gdx;
29 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20;
30 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20API18;
31 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewAPI18;
32 import com.badlogic.gdx.backends.android.surfaceview.ResolutionStrategy;
33 import com.badlogic.gdx.utils.GdxRuntimeException;
34 
35 /** A subclass of {@link AndroidGraphics} specialized for live wallpaper applications.
36  *
37  * @author mzechner */
38 public final class AndroidGraphicsLiveWallpaper extends AndroidGraphics {
39 
AndroidGraphicsLiveWallpaper(AndroidLiveWallpaper lwp, AndroidApplicationConfiguration config, ResolutionStrategy resolutionStrategy)40 	public AndroidGraphicsLiveWallpaper (AndroidLiveWallpaper lwp, AndroidApplicationConfiguration config,
41 		ResolutionStrategy resolutionStrategy) {
42 		super(lwp, config, resolutionStrategy, false);
43 	}
44 
45 	// jw: I replaced GL..SurfaceViewLW classes with their original counterparts, if it will work
46 	// on known devices, on opengl 1.0 and 2.0, and all possible SDK versions.. You can remove
47 	// GL..SurfaceViewLW family of classes completely (there is no use for them).
48 
49 	// -> specific for live wallpapers
50 	// jw: synchronized access to current wallpaper surface holder
getSurfaceHolder()51 	SurfaceHolder getSurfaceHolder () {
52 		synchronized (((AndroidLiveWallpaper)app).service.sync) {
53 			return ((AndroidLiveWallpaper)app).service.getSurfaceHolder();
54 		}
55 	}
56 
57 	// <- specific for live wallpapers
58 
59 	// Grabbed from AndroidGraphics superclass and modified to override
60 	// getHolder in created GLSurfaceView and GLSurfaceViewAPI18 instances
61 	@Override
createGLSurfaceView(AndroidApplicationBase application, final ResolutionStrategy resolutionStrategy)62 	protected View createGLSurfaceView (AndroidApplicationBase application, final ResolutionStrategy resolutionStrategy) {
63 		if (!checkGL20()) throw new GdxRuntimeException("Libgdx requires OpenGL ES 2.0");
64 
65 		EGLConfigChooser configChooser = getEglConfigChooser();
66 		int sdkVersion = android.os.Build.VERSION.SDK_INT;
67 		if (sdkVersion <= 10 && config.useGLSurfaceView20API18) {
68 			GLSurfaceView20API18 view = new GLSurfaceView20API18(application.getContext(), resolutionStrategy) {
69 				@Override
70 				public SurfaceHolder getHolder () {
71 					return getSurfaceHolder();
72 				}
73 
74 				// This method is invoked via reflection by AndroidLiveWallpaper.onDestroy()
75 				public void onDestroy () {
76 					onDetachedFromWindow(); // calls GLSurfaceView.mGLThread.requestExitAndWait();
77 				}
78 			};
79 			if (configChooser != null)
80 				view.setEGLConfigChooser(configChooser);
81 			else
82 				view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
83 			view.setRenderer(this);
84 			return view;
85 		}
86 		else {
87 			GLSurfaceView20 view = new GLSurfaceView20(application.getContext(), resolutionStrategy) {
88 				@Override
89 				public SurfaceHolder getHolder () {
90 					return getSurfaceHolder();
91 				}
92 
93 				// This method is invoked via reflection by AndroidLiveWallpaper.onDestroy()
94 				public void onDestroy () {
95 					onDetachedFromWindow(); // calls GLSurfaceView.mGLThread.requestExitAndWait();
96 				}
97 			};
98 
99 			if (configChooser != null)
100 				view.setEGLConfigChooser(configChooser);
101 			else
102 				view.setEGLConfigChooser(config.r, config.g, config.b, config.a, config.depth, config.stencil);
103 			view.setRenderer(this);
104 			return view;
105 		}
106 	}
107 
108 	// kill the GLThread managed by GLSurfaceView (only for GLSurfaceView because GLSurffaceViewCupcake stops thread in
109 	// onPause events - which is not as easy and safe for GLSurfaceView)
onDestroyGLSurfaceView()110 	public void onDestroyGLSurfaceView () {
111 		if (view != null) {
112 			if (view instanceof GLSurfaceView || view instanceof GLSurfaceViewAPI18) {
113 				try {
114 					// onDestroy redirects to onDetachedFromWindow - which stops GLThread by calling mGLThread.requestExitAndWait()
115 					view.getClass().getMethod("onDestroy").invoke(view);
116 					if (AndroidLiveWallpaperService.DEBUG)
117 						Log.d(AndroidLiveWallpaperService.TAG,
118 							" > AndroidLiveWallpaper - onDestroy() stopped GLThread managed by GLSurfaceView");
119 				} catch (Throwable t) {
120 					// error while scheduling exit of GLThread, GLThread will remain live and wallpaper service
121 					// wouldn't be able to shutdown completely
122 					Log.e(AndroidLiveWallpaperService.TAG,
123 						"failed to destroy GLSurfaceView's thread! GLSurfaceView.onDetachedFromWindow impl changed since API lvl 16!");
124 					t.printStackTrace();
125 				}
126 			}
127 		}
128 	}
129 
130 	@Override
resume()131 	void resume () {
132 		synchronized (synch) {
133 			running = true;
134 			resume = true;
135 
136 			// by jw: added synchronization, there was nothing before
137 			while (resume) {
138 				try {
139 					requestRendering();
140 					synch.wait();
141 				} catch (InterruptedException ignored) {
142 					Gdx.app.log("AndroidGraphics", "waiting for resume synchronization failed!");
143 				}
144 			}
145 		}
146 	}
147 
148 	@Override
onDrawFrame(javax.microedition.khronos.opengles.GL10 gl)149 	public void onDrawFrame (javax.microedition.khronos.opengles.GL10 gl) {
150 		long time = System.nanoTime();
151 		deltaTime = (time - lastFrameTime) / 1000000000.0f;
152 		lastFrameTime = time;
153 
154 		// After pause deltaTime can have somewhat huge value that destabilizes the mean, so let's cut it off
155 		if (!resume) {
156 			mean.addValue(deltaTime);
157 		} else {
158 			deltaTime = 0;
159 		}
160 
161 		boolean lrunning = false;
162 		boolean lpause = false;
163 		boolean ldestroy = false;
164 		boolean lresume = false;
165 
166 		synchronized (synch) {
167 			lrunning = running;
168 			lpause = pause;
169 			ldestroy = destroy;
170 			lresume = resume;
171 
172 			if (resume) {
173 				resume = false;
174 				// by jw: originally was not synchronized
175 				synch.notifyAll();
176 			}
177 
178 			if (pause) {
179 				pause = false;
180 				synch.notifyAll();
181 			}
182 
183 			if (destroy) {
184 				destroy = false;
185 				synch.notifyAll();
186 			}
187 		}
188 
189 		if (lresume) {
190 			// ((AndroidAudio)app.getAudio()).resume(); // jw: moved to AndroidLiveWallpaper.onResume
191 			app.getApplicationListener().resume();
192 			Gdx.app.log("AndroidGraphics", "resumed");
193 		}
194 
195 		// HACK: added null check to handle set wallpaper from preview null
196 		// error in renderer
197 		// jw: this hack is not working always, renderer ends with error for some devices - because of uninitialized gl context
198 		// jw: now it shouldn't be necessary - after wallpaper backend refactoring:)
199 		if (lrunning) {
200 
201 			// jw: changed
202 			synchronized (app.getRunnables()) {
203 				app.getExecutedRunnables().clear();
204 				app.getExecutedRunnables().addAll(app.getRunnables());
205 				app.getRunnables().clear();
206 
207 				for (int i = 0; i < app.getExecutedRunnables().size; i++) {
208 					try {
209 						app.getExecutedRunnables().get(i).run();
210 					} catch (Throwable t) {
211 						t.printStackTrace();
212 					}
213 				}
214 			}
215 			/*
216 			 * synchronized (app.runnables) { for (int i = 0; i < app.runnables.size; i++) { app.runnables.get(i).run(); }
217 			 * app.runnables.clear(); }
218 			 */
219 
220 			app.getInput().processEvents();
221 			frameId++;
222 			app.getApplicationListener().render();
223 		}
224 
225 		// jw: never called on lvp, why? see description in AndroidLiveWallpaper.onPause
226 		if (lpause) {
227 			app.getApplicationListener().pause();
228 			// ((AndroidAudio)app.getAudio()).pause(); jw: moved to AndroidLiveWallpaper.onPause
229 			Gdx.app.log("AndroidGraphics", "paused");
230 		}
231 
232 		// jw: never called on lwp, why? see description in AndroidLiveWallpaper.onPause
233 		if (ldestroy) {
234 			app.getApplicationListener().dispose();
235 			// ((AndroidAudio)app.getAudio()).dispose(); jw: moved to AndroidLiveWallpaper.onDestroy
236 			Gdx.app.log("AndroidGraphics", "destroyed");
237 		}
238 
239 		if (time - frameStart > 1000000000) {
240 			fps = frames;
241 			frames = 0;
242 			frameStart = time;
243 		}
244 		frames++;
245 	}
246 
247 	@Override
logManagedCachesStatus()248 	protected void logManagedCachesStatus() {
249 		// to prevent creating too many string buffers in live wallpapers
250 		if (AndroidLiveWallpaperService.DEBUG) {
251 			super.logManagedCachesStatus();
252 		}
253 	}
254 }
255