OSDN Git Service

f5ef8e858d6c97ff6e012b57a340a9b3639083b7
[mikumikustudio/libgdx-mikumikustudio.git] / backends / gdx-backend-android / src / com / badlogic / gdx / backends / android / AndroidLiveWallpaper.java
1 /*\r
2  * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)\r
3  * \r
4  * Modified by Elijah Cornell\r
5  * 2013.01 Modified by Jaroslaw Wisniewski <j.wisniewski@appsisle.com>\r
6  * \r
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the\r
8  * License. You may obtain a copy of the License at\r
9  * \r
10  * http://www.apache.org/licenses/LICENSE-2.0\r
11  * \r
12  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"\r
13  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language\r
14  * governing permissions and limitations under the License.\r
15  */\r
16 \r
17 \r
18 package com.badlogic.gdx.backends.android;\r
19 \r
20 import java.lang.reflect.Method;\r
21 import java.util.ArrayList;\r
22 import java.util.List;\r
23 \r
24 import android.app.Activity;\r
25 import android.content.Context;\r
26 import android.content.res.Configuration;\r
27 import android.opengl.GLSurfaceView;\r
28 import android.os.Build;\r
29 import android.os.Bundle;\r
30 import android.os.Debug;\r
31 import android.os.Handler;\r
32 import android.service.wallpaper.WallpaperService;\r
33 import android.service.wallpaper.WallpaperService.Engine;\r
34 import android.util.Log;\r
35 import android.view.View;\r
36 import android.view.WindowManager;\r
37 import android.widget.FrameLayout.LayoutParams;\r
38 \r
39 import com.badlogic.gdx.Application;\r
40 import com.badlogic.gdx.ApplicationListener;\r
41 import com.badlogic.gdx.Audio;\r
42 import com.badlogic.gdx.Files;\r
43 import com.badlogic.gdx.Gdx;\r
44 import com.badlogic.gdx.Graphics;\r
45 import com.badlogic.gdx.Input;\r
46 import com.badlogic.gdx.LifecycleListener;\r
47 import com.badlogic.gdx.Net;\r
48 import com.badlogic.gdx.Preferences;\r
49 import com.badlogic.gdx.Application.ApplicationType;\r
50 import com.badlogic.gdx.backends.android.surfaceview.FillResolutionStrategy;\r
51 import com.badlogic.gdx.backends.android.surfaceview.GLBaseSurfaceViewLW;\r
52 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20;\r
53 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20LW;\r
54 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewCupcake;\r
55 import com.badlogic.gdx.graphics.GL10;\r
56 import com.badlogic.gdx.graphics.GL11;\r
57 import com.badlogic.gdx.utils.Array;\r
58 import com.badlogic.gdx.utils.Clipboard;\r
59 import com.badlogic.gdx.utils.GdxNativesLoader;\r
60 \r
61 /**\r
62  * An implementation of the {@link Application} interface to be used with an\r
63  * AndroidLiveWallpaperService. Not directly constructable, instead the\r
64  * {@link AndroidLiveWallpaperService} will create this class internally.\r
65  * \r
66  * @author mzechner\r
67  */\r
68 public class AndroidLiveWallpaper implements Application {\r
69         static {\r
70                 GdxNativesLoader.load();\r
71         }\r
72         \r
73         protected AndroidLiveWallpaperService service;\r
74 \r
75         protected AndroidGraphicsLiveWallpaper graphics;\r
76         protected AndroidInput input;\r
77         protected AndroidAudio audio;\r
78         protected AndroidFiles files;\r
79         protected AndroidNet net;\r
80         protected ApplicationListener listener;\r
81         protected boolean firstResume = true;\r
82         protected final Array<Runnable> runnables = new Array<Runnable>();\r
83         protected final Array<Runnable> executedRunnables = new Array<Runnable>();\r
84         protected final Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>();\r
85         protected int logLevel = LOG_INFO;\r
86 \r
87         public AndroidLiveWallpaper(AndroidLiveWallpaperService service) {\r
88                 this.service = service;\r
89         }\r
90         \r
91         public void initialize(ApplicationListener listener, AndroidApplicationConfiguration config) {\r
92                 graphics = new AndroidGraphicsLiveWallpaper(this, config, config.resolutionStrategy==null?new FillResolutionStrategy():config.resolutionStrategy);\r
93                 \r
94                 // factory in use, but note: AndroidInputFactory causes exceptions when obfuscated: java.lang.RuntimeException: Couldn't construct AndroidInput, this should never happen, proguard deletes constructor used only by reflection\r
95                 input = AndroidInputFactory.newAndroidInput(this, this.getService(), graphics.view, config);\r
96                 //input = new AndroidInput(this, this.getService(), null, config);\r
97 \r
98                 audio = new AndroidAudio(this.getService(), config);\r
99                 \r
100                 // added initialization of android local storage: /data/data/<app package>/files/\r
101                 files = new AndroidFiles(this.getService().getAssets(), this.getService().getFilesDir().getAbsolutePath());\r
102                 \r
103                 this.listener = listener;\r
104                 \r
105                 Gdx.app = this;\r
106                 Gdx.input = input;\r
107                 Gdx.audio = audio;\r
108                 Gdx.files = files;\r
109                 Gdx.graphics = graphics;\r
110         }\r
111 \r
112         public void onPause() {\r
113                 if (AndroidLiveWallpaperService.DEBUG) Log.d(AndroidLiveWallpaperService.TAG, " > AndroidLiveWallpaper - onPause()");\r
114 \r
115                 // IMPORTANT!\r
116                 // jw: graphics.pause is never called, graphics.pause works on most devices but not on all.. \r
117                 // for example on Samsung Galaxy Tab (GT-P6800) on android 4.0.4 invoking graphics.pause causes "Fatal Signal 11" \r
118                 // near mEglHelper.swap() in GLSurfaceView while processing next onPause event.\r
119                 // See related issue: \r
120                 // http://code.google.com/p/libgdx/issues/detail?id=541\r
121                 // the problem with graphics.pause occurs while using OpenGL 2.0 and original GLSurfaceView while rotating device in lwp preview\r
122                 // in my opinion it is a bug of android not libgdx, even example Cubic live wallpaper from\r
123                 // Android SDK crashes on affected devices.......... and on some configurations of android emulator too.\r
124                 // \r
125                 // My wallpaper was rejected on Samsung Apps because of this issue, so I decided to disable graphics.pause.. \r
126                 // also I moved audio lifecycle methods from AndroidGraphicsLiveWallpaper into this class\r
127                 \r
128                 //graphics.pause();\r
129                 //if (AndroidLiveWallpaperService.DEBUG) Log.d(AndroidLiveWallpaperService.TAG, " > AndroidLiveWallpaper - onPause() application paused!");\r
130                 audio.pause();\r
131 \r
132                 input.unregisterSensorListeners();\r
133                 // erase pointer ids. this sucks donkeyballs...\r
134                 int[] realId = input.realId;\r
135                 for (int i = 0; i < realId.length; i++)\r
136                         realId[i] = -1;\r
137                 // erase touched state. this also sucks donkeyballs...\r
138                 boolean[] touched = input.touched;\r
139                 for (int i = 0; i < touched.length; i++)\r
140                         touched[i] = false;\r
141 \r
142                 if (graphics != null && graphics.view != null) {\r
143                         if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onPause();\r
144                         else if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onPause();\r
145                         else throw new RuntimeException("unimplemented");\r
146                 }\r
147                 \r
148                 if (AndroidLiveWallpaperService.DEBUG) Log.d(AndroidLiveWallpaperService.TAG, " > AndroidLiveWallpaper - onPause() done!");\r
149         }\r
150 \r
151         public void onResume() {\r
152                 Gdx.app = this;\r
153                 Gdx.input = input;\r
154                 Gdx.audio = audio;\r
155                 Gdx.files = files;\r
156                 Gdx.graphics = graphics;\r
157 \r
158                 input.registerSensorListeners();\r
159                 \r
160                 // FIXME restore conditional execution if lifecycle errors will occur when GLSurfaceView used. \r
161                 // GLSurfaceView is guaranteed to work with this condition on, but GLSurfaceViewCupcake requires it off,\r
162                 // so I disabled it.\r
163                 //if (!firstResume)     // mentioned condition\r
164                 if (graphics != null && graphics.view != null) {\r
165                         if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onResume();\r
166                         else if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onResume();\r
167                         else throw new RuntimeException("unimplemented");\r
168                 }\r
169                 \r
170                 if (!firstResume)\r
171                 {\r
172                         audio.resume();\r
173                         graphics.resume();\r
174                 }\r
175                 else\r
176                         firstResume = false;\r
177         }\r
178         \r
179         public void onDestroy() {\r
180 \r
181                 // it is too late to call graphics.destroy - it needs live gl GLThread and gl context, otherwise it will cause of deadlock\r
182                 //if (graphics != null) {\r
183                 //      graphics.clearManagedCaches();\r
184                 //      graphics.destroy();\r
185                 //}\r
186                 \r
187                 // so we do what we can..\r
188                 if (graphics != null)\r
189                 {\r
190                         // not necessary - already called in AndroidLiveWallpaperService.onDeepPauseApplication\r
191                         // app.graphics.clearManagedCaches();\r
192                         \r
193                         // 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)\r
194                         if (graphics.view != null && (graphics.view instanceof GLSurfaceView))\r
195                         {\r
196                                 GLSurfaceView glSurfaceView = (GLSurfaceView)graphics.view;\r
197                                 try {\r
198                                         Method method = null;\r
199                                         for (Method m : glSurfaceView.getClass().getMethods()) \r
200                                         {\r
201                                                 if (m.getName().equals("onDestroy"))    // implemented in AndroidGraphicsLiveWallpaper, redirects to onDetachedFromWindow - which stops GLThread by calling mGLThread.requestExitAndWait()\r
202                                                 {\r
203                                                         method = m;\r
204                                                         break;\r
205                                                 }\r
206                                         }\r
207                                         \r
208                                         if (method != null)\r
209                                         {\r
210                                                 method.invoke(glSurfaceView);\r
211                                                 if (AndroidLiveWallpaperService.DEBUG) Log.d(AndroidLiveWallpaperService.TAG, " > AndroidLiveWallpaper - onDestroy() stopped GLThread managed by GLSurfaceView");\r
212                                         }\r
213                                         else\r
214                                                 throw new Exception("method not found!");\r
215                                 } \r
216                                 catch (Throwable t)\r
217                                 {\r
218                                         // error while scheduling exit of GLThread, GLThread will remain live and wallpaper service wouldn't be able to shutdown completely\r
219                                         Log.e(AndroidLiveWallpaperService.TAG, "failed to destroy GLSurfaceView's thread! GLSurfaceView.onDetachedFromWindow impl changed since API lvl 16!");\r
220                                         t.printStackTrace();\r
221                                 }\r
222                         }\r
223                 }\r
224                 \r
225                 if (audio != null)\r
226                 {\r
227                         // dispose audio and free native resources, mandatory since graphics.pause is never called in live wallpaper\r
228                         audio.dispose();\r
229                 }\r
230         }\r
231 \r
232         public WindowManager getWindowManager() {\r
233                 return service.getWindowManager();\r
234         }\r
235         \r
236         public AndroidLiveWallpaperService getService() {\r
237                 return service;\r
238         }\r
239 \r
240         public ApplicationListener getListener() {\r
241                 return listener;\r
242         }\r
243 \r
244         @Override \r
245         public void postRunnable (Runnable runnable) {\r
246                 synchronized(runnables) {\r
247                         runnables.add(runnable);\r
248                 }\r
249         }\r
250         \r
251         @Override\r
252         public Audio getAudio () {\r
253                 return audio;\r
254         }\r
255 \r
256         @Override\r
257         public Files getFiles () {\r
258                 return files;\r
259         }\r
260 \r
261         @Override\r
262         public Graphics getGraphics () {\r
263                 return graphics;\r
264         }\r
265 \r
266         @Override\r
267         public Input getInput () {\r
268                 return input;\r
269         }\r
270         \r
271         @Override\r
272         public Net getNet () {\r
273                 return net;\r
274         }\r
275 \r
276         @Override\r
277         public ApplicationType getType () {\r
278                 return ApplicationType.Android;\r
279         }\r
280 \r
281         @Override\r
282         public int getVersion () {\r
283                 return Integer.parseInt(android.os.Build.VERSION.SDK);\r
284         }\r
285 \r
286         @Override\r
287         public long getJavaHeap () {\r
288                 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();\r
289         }\r
290 \r
291         @Override\r
292         public long getNativeHeap () {\r
293                 return Debug.getNativeHeapAllocatedSize();\r
294         }\r
295 \r
296         @Override\r
297         public Preferences getPreferences (String name) {\r
298                 return new AndroidPreferences(service.getSharedPreferences(name, Context.MODE_PRIVATE));\r
299         }\r
300 \r
301         AndroidClipboard clipboard;\r
302         \r
303         @Override\r
304         public Clipboard getClipboard() {\r
305                 if (clipboard == null) {\r
306                         clipboard = new AndroidClipboard(service);\r
307                 }\r
308                 return clipboard;\r
309         }\r
310         \r
311         @Override\r
312         public void debug (String tag, String message) {\r
313                 if (logLevel >= LOG_DEBUG) {\r
314                         Log.d(tag, message);\r
315                 }\r
316         }\r
317 \r
318         @Override\r
319         public void debug (String tag, String message, Throwable exception) {\r
320                 if (logLevel >= LOG_DEBUG) {\r
321                         Log.d(tag, message, exception);\r
322                 }\r
323         }\r
324 \r
325         @Override\r
326         public void log (String tag, String message) {\r
327                 if (logLevel >= LOG_INFO) Log.i(tag, message);\r
328         }\r
329 \r
330         @Override\r
331         public void log (String tag, String message, Exception exception) {\r
332                 if (logLevel >= LOG_INFO) Log.i(tag, message, exception);\r
333         }\r
334 \r
335         @Override\r
336         public void error (String tag, String message) {\r
337                 if (logLevel >= LOG_ERROR) Log.e(tag, message);\r
338         }\r
339 \r
340         @Override\r
341         public void error (String tag, String message, Throwable exception) {\r
342                 if (logLevel >= LOG_ERROR) Log.e(tag, message, exception);\r
343         }\r
344 \r
345         @Override\r
346         public void setLogLevel (int logLevel) {\r
347                 this.logLevel = logLevel;\r
348         }\r
349 \r
350         @Override\r
351         public void exit () {\r
352                 // no-op\r
353         }\r
354         \r
355         @Override\r
356         public void addLifecycleListener (LifecycleListener listener) {\r
357                 synchronized(lifecycleListeners) {\r
358                         lifecycleListeners.add(listener);\r
359                 }\r
360         }\r
361 \r
362         @Override\r
363         public void removeLifecycleListener (LifecycleListener listener) {\r
364                 synchronized(lifecycleListeners) {\r
365                         lifecycleListeners.removeValue(listener, true);\r
366                 }               \r
367         }\r
368 \r
369         @Override\r
370         public ApplicationListener getApplicationListener () {\r
371                 return listener;\r
372         }\r
373 }\r