2 * Copyright (c) 2011 Ben Gruver
5 * You may use this code at your option under the following BSD license
6 * or Apache 2.0 license terms
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * [The "Apache 2.0 license"]
32 * Licensed under the Apache License, Version 2.0 (the "License");
33 * you may not use this file except in compliance with the License.
34 * You may obtain a copy of the License at
36 * http://www.apache.org/licenses/LICENSE-2.0
38 * Unless required by applicable law or agreed to in writing, software
39 * distributed under the License is distributed on an "AS IS" BASIS,
40 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41 * See the License for the specific language governing permissions and
42 * limitations under the License.
45 package net.rbgrn.android.glwallpaperservice;
47 import android.opengl.GLSurfaceView;
48 import android.service.wallpaper.WallpaperService;
49 import android.view.SurfaceHolder;
51 import java.lang.reflect.InvocationTargetException;
52 import java.lang.reflect.Method;
53 import java.util.ArrayList;
54 import java.util.List;
56 public abstract class GLWallpaperService extends WallpaperService {
57 public interface Renderer extends GLSurfaceView.Renderer {
60 public class GLEngine extends WallpaperService.Engine {
61 public final static int RENDERMODE_WHEN_DIRTY = 0;
62 public final static int RENDERMODE_CONTINUOUSLY = 1;
64 private Object lock = new Object();
65 private GLSurfaceView mGLSurfaceView = null;
67 private int debugFlags;
68 private int renderMode;
71 * If we don't have a GLSurfaceView yet, then we queue up any operations that are requested, until the
72 * GLSurfaceView is created.
74 * Initially, we created the glSurfaceView in the GLEngine constructor, and things seemed to work. However,
75 * it turns out a few devices aren't set up to handle the surface related events at this point, and crash.
77 * This is a work around so that we can delay the creation of the GLSurfaceView until the surface is actually
78 * created, so that the underlying code should be in a state to be able to handle the surface related events
79 * that get fired when GLSurfaceView is created.
81 private List<Runnable> pendingOperations = new ArrayList<Runnable>();
86 public void setGLWrapper(final GLSurfaceView.GLWrapper glWrapper) {
88 if (mGLSurfaceView != null) {
89 mGLSurfaceView.setGLWrapper(glWrapper);
91 pendingOperations.add(new Runnable() {
93 setGLWrapper(glWrapper);
100 public void setDebugFlags(final int debugFlags) {
101 synchronized (lock) {
102 if (mGLSurfaceView != null) {
103 mGLSurfaceView.setDebugFlags(debugFlags);
105 this.debugFlags = debugFlags;
106 pendingOperations.add(new Runnable() {
108 setDebugFlags(debugFlags);
115 public int getDebugFlags() {
116 synchronized (lock) {
117 if (mGLSurfaceView != null) {
118 return mGLSurfaceView.getDebugFlags();
125 public void setRenderer(final GLSurfaceView.Renderer renderer) {
126 synchronized (lock) {
127 if (mGLSurfaceView != null) {
128 mGLSurfaceView.setRenderer(renderer);
130 mGLSurfaceView.onPause();
133 pendingOperations.add(new Runnable() {
135 setRenderer(renderer);
142 public void queueEvent(final Runnable r) {
143 synchronized (lock) {
144 if (mGLSurfaceView != null) {
145 mGLSurfaceView.queueEvent(r);
147 pendingOperations.add(new Runnable() {
156 public void setEGLContextFactory(final GLSurfaceView.EGLContextFactory factory) {
157 synchronized (lock) {
158 if (mGLSurfaceView != null) {
159 mGLSurfaceView.setEGLContextFactory(factory);
161 pendingOperations.add(new Runnable() {
163 setEGLContextFactory(factory);
170 public void setEGLWindowSurfaceFactory(final GLSurfaceView.EGLWindowSurfaceFactory factory) {
171 synchronized (lock) {
172 if (mGLSurfaceView != null) {
173 mGLSurfaceView.setEGLWindowSurfaceFactory(factory);
175 pendingOperations.add(new Runnable() {
177 setEGLWindowSurfaceFactory(factory);
184 public void setEGLConfigChooser(final GLSurfaceView.EGLConfigChooser configChooser) {
185 synchronized (lock) {
186 if (mGLSurfaceView != null) {
187 mGLSurfaceView.setEGLConfigChooser(configChooser);
189 pendingOperations.add(new Runnable() {
191 setEGLConfigChooser(configChooser);
198 public void setEGLConfigChooser(final boolean needDepth) {
199 synchronized (lock) {
200 if (mGLSurfaceView != null) {
201 mGLSurfaceView.setEGLConfigChooser(needDepth);
203 pendingOperations.add(new Runnable() {
205 setEGLConfigChooser(needDepth);
212 public void setEGLConfigChooser(final int redSize, final int greenSize, final int blueSize,
213 final int alphaSize, final int depthSize, final int stencilSize) {
214 synchronized (lock) {
215 if (mGLSurfaceView != null) {
216 mGLSurfaceView.setEGLConfigChooser(redSize, greenSize, blueSize,
217 alphaSize, depthSize, stencilSize);
219 pendingOperations.add(new Runnable() {
221 setEGLConfigChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize);
228 public void setEGLContextClientVersion(final int version) {
229 synchronized (lock) {
230 Method method = null;
233 //the setEGLContextClientVersion method is first available in api level 8, but we would
234 //like to support compiling against api level 7
235 method = GLSurfaceView.class.getMethod("setEGLContextClientVersion", int.class);
236 } catch (NoSuchMethodException ex) {
240 if (mGLSurfaceView != null) {
242 method.invoke(mGLSurfaceView, version);
243 } catch (IllegalAccessException ex) {
245 } catch (InvocationTargetException ex) {
249 pendingOperations.add(new Runnable() {
251 setEGLContextClientVersion(version);
258 public void setRenderMode(final int renderMode) {
259 synchronized (lock) {
260 if (mGLSurfaceView != null) {
261 mGLSurfaceView.setRenderMode(renderMode);
263 this.renderMode = renderMode;
264 pendingOperations.add(new Runnable() {
266 setRenderMode(renderMode);
273 public int getRenderMode() {
274 synchronized (lock) {
275 if (mGLSurfaceView != null) {
276 return mGLSurfaceView.getRenderMode();
283 public void requestRender() {
284 if (mGLSurfaceView != null) {
285 mGLSurfaceView.requestRender();
290 public void onVisibilityChanged(final boolean visible) {
291 super.onVisibilityChanged(visible);
293 synchronized (lock) {
294 if (mGLSurfaceView != null) {
296 mGLSurfaceView.onResume();
298 mGLSurfaceView.onPause();
301 pendingOperations.add(new Runnable() {
304 mGLSurfaceView.onResume();
306 mGLSurfaceView.onPause();
315 public void onSurfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
316 synchronized (lock) {
317 if (mGLSurfaceView != null) {
318 mGLSurfaceView.surfaceChanged(holder, format, width, height);
320 pendingOperations.add(new Runnable() {
322 onSurfaceChanged(holder, format, width, height);
330 public void onSurfaceCreated(SurfaceHolder holder) {
331 synchronized (lock) {
332 if (mGLSurfaceView == null) {
333 mGLSurfaceView = new GLSurfaceView(GLWallpaperService.this) {
335 public SurfaceHolder getHolder() {
336 return GLEngine.this.getSurfaceHolder();
339 for (Runnable pendingOperation: pendingOperations) {
340 pendingOperation.run();
342 pendingOperations.clear();
344 mGLSurfaceView.surfaceCreated(holder);
349 public void onSurfaceDestroyed(SurfaceHolder holder) {
350 synchronized (lock) {
351 if (mGLSurfaceView != null) {
352 mGLSurfaceView.surfaceDestroyed(holder);