1 /*******************************************************************************
2 * Copyright 2011 See AUTHORS file.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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 ******************************************************************************/
17 package com.badlogic.gdx.backends.android;
19 import java.lang.reflect.Method;
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.os.Bundle;
25 import android.os.Debug;
26 import android.os.Handler;
27 import android.os.PowerManager;
28 import android.os.PowerManager.WakeLock;
29 import android.service.dreams.DreamService;
30 import android.util.Log;
31 import android.view.Gravity;
32 import android.view.View;
33 import android.widget.FrameLayout;
35 import com.badlogic.gdx.Application;
36 import com.badlogic.gdx.ApplicationListener;
37 import com.badlogic.gdx.Audio;
38 import com.badlogic.gdx.Files;
39 import com.badlogic.gdx.Gdx;
40 import com.badlogic.gdx.Graphics;
41 import com.badlogic.gdx.Input;
42 import com.badlogic.gdx.LifecycleListener;
43 import com.badlogic.gdx.Net;
44 import com.badlogic.gdx.Preferences;
45 import com.badlogic.gdx.backends.android.surfaceview.FillResolutionStrategy;
46 import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewCupcake;
47 import com.badlogic.gdx.graphics.GL10;
48 import com.badlogic.gdx.graphics.GL11;
49 import com.badlogic.gdx.utils.Array;
50 import com.badlogic.gdx.utils.Clipboard;
51 import com.badlogic.gdx.utils.GdxNativesLoader;
53 /** An implementation of the {@link Application} interface for Android. Create an {@link Activity} that derives from this class. In
54 * the Activity#onCreate(Bundle) method call the {@link #initialize(ApplicationListener, boolean)} method specifying the
55 * configuration for the GLSurfaceView.
58 public class AndroidDaydream extends DreamService implements Application {
60 GdxNativesLoader.load();
63 protected AndroidGraphicsDaydream graphics;
64 protected AndroidInput input;
65 protected AndroidAudio audio;
66 protected AndroidFiles files;
67 protected AndroidNet net;
68 protected ApplicationListener listener;
69 protected Handler handler;
70 protected boolean firstResume = true;
71 protected final Array<Runnable> runnables = new Array<Runnable>();
72 protected final Array<Runnable> executedRunnables = new Array<Runnable>();
73 protected final Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>();
74 protected WakeLock wakeLock = null;
75 protected int logLevel = LOG_INFO;
77 /** This method has to be called in the Activity#onCreate(Bundle) method. It sets up all the things necessary to get input,
78 * render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 context
79 * which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be used when
80 * OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the {@link Graphics#isGL20Available()}
81 * method. Uses a default {@link AndroidApplicationConfiguration}.
83 * @param listener the {@link ApplicationListener} implementing the program logic
84 * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. */
85 public void initialize (ApplicationListener listener, boolean useGL2IfAvailable) {
86 AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
87 config.useGL20 = useGL2IfAvailable;
88 initialize(listener, config);
91 /** This method has to be called in the Activity#onCreate(Bundle) method. It sets up all the things necessary to get input,
92 * render via OpenGL and so on. If config.useGL20 is set the AndroidApplication will try to create an OpenGL ES 2.0 context
93 * which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be used when
94 * OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the {@link Graphics#isGL20Available()}
95 * method. You can configure other aspects of the application with the rest of the fields in the
96 * {@link AndroidApplicationConfiguration} instance.
98 * @param listener the {@link ApplicationListener} implementing the program logic
99 * @param config the {@link AndroidApplicationConfiguration}, defining various settings of the application (use accelerometer,
101 public void initialize (ApplicationListener listener, AndroidApplicationConfiguration config) {
102 graphics = new AndroidGraphicsDaydream(this, config, config.resolutionStrategy == null ? new FillResolutionStrategy()
103 : config.resolutionStrategy);
104 input = AndroidInputFactory.newAndroidInput(this, this, graphics.view, config);
105 audio = new AndroidAudio(this, config);
106 files = new AndroidFiles(this.getAssets(), this.getFilesDir().getAbsolutePath());
107 net = new AndroidNet(null);
108 this.listener = listener;
109 this.handler = new Handler();
112 Gdx.input = this.getInput();
113 Gdx.audio = this.getAudio();
114 Gdx.files = this.getFiles();
115 Gdx.graphics = this.getGraphics();
116 Gdx.net = this.getNet();
120 setContentView(graphics.getView(), createLayoutParams());
121 createWakeLock(config);
122 hideStatusBar(config);
125 protected FrameLayout.LayoutParams createLayoutParams () {
126 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
127 android.view.ViewGroup.LayoutParams.FILL_PARENT);
128 layoutParams.gravity = Gravity.CENTER;
132 protected void createWakeLock (AndroidApplicationConfiguration config) {
133 if (config.useWakelock) {
134 PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
135 wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "libgdx wakelock");
139 protected void hideStatusBar (AndroidApplicationConfiguration config) {
140 if (!config.hideStatusBar || getVersion() < 11) return;
142 View rootView = getWindow().getDecorView();
145 Method m = View.class.getMethod("setSystemUiVisibility", int.class);
146 m.invoke(rootView, 0x0);
147 m.invoke(rootView, 0x1);
148 } catch (Exception e) {
149 log("AndroidApplication", "Can't hide status bar", e);
153 /** This method has to be called in the Activity#onCreate(Bundle) method. It sets up all the things necessary to get input,
154 * render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 context
155 * which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be used when
156 * OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the {@link Graphics#isGL20Available()}
157 * method. Uses a default {@link AndroidApplicationConfiguration}.
159 * Note: you have to add the returned view to your layout!
161 * @param listener the {@link ApplicationListener} implementing the program logic
162 * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available.
163 * @return the GLSurfaceView of the application */
164 public View initializeForView (ApplicationListener listener, boolean useGL2IfAvailable) {
165 AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
166 config.useGL20 = useGL2IfAvailable;
167 return initializeForView(listener, config);
170 /** This method has to be called in the Activity#onCreate(Bundle) method. It sets up all the things necessary to get input,
171 * render via OpenGL and so on. If config.useGL20 is set the AndroidApplication will try to create an OpenGL ES 2.0 context
172 * which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be used when
173 * OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the {@link Graphics#isGL20Available()}
174 * method. You can configure other aspects of the application with the rest of the fields in the
175 * {@link AndroidApplicationConfiguration} instance.
177 * Note: you have to add the returned view to your layout!
179 * @param listener the {@link ApplicationListener} implementing the program logic
180 * @param config the {@link AndroidApplicationConfiguration}, defining various settings of the application (use accelerometer,
182 * @return the GLSurfaceView of the application */
183 public View initializeForView (ApplicationListener listener, AndroidApplicationConfiguration config) {
184 graphics = new AndroidGraphicsDaydream(this, config, config.resolutionStrategy == null ? new FillResolutionStrategy()
185 : config.resolutionStrategy);
186 input = AndroidInputFactory.newAndroidInput(this, this, graphics.view, config);
187 audio = new AndroidAudio(this, config);
188 files = new AndroidFiles(this.getAssets(), this.getFilesDir().getAbsolutePath());
189 net = new AndroidNet(null);
190 this.listener = listener;
191 this.handler = new Handler();
194 Gdx.input = this.getInput();
195 Gdx.audio = this.getAudio();
196 Gdx.files = this.getFiles();
197 Gdx.graphics = this.getGraphics();
198 Gdx.net = this.getNet();
200 createWakeLock(config);
201 hideStatusBar(config);
202 return graphics.getView();
206 public void onDreamingStopped () {
207 if (wakeLock != null) wakeLock.release();
208 boolean isContinuous = graphics.isContinuousRendering();
209 graphics.setContinuousRendering(true);
212 input.unregisterSensorListeners();
213 // erase pointer ids. this sucks donkeyballs...
214 int[] realId = input.realId;
215 for (int i = 0; i < realId.length; i++)
217 // erase touched state. this also sucks donkeyballs...
218 boolean[] touched = input.touched;
219 for (int i = 0; i < touched.length; i++)
222 graphics.clearManagedCaches();
224 graphics.setContinuousRendering(isContinuous);
226 if (graphics != null && graphics.view != null) {
227 if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onPause();
228 if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onPause();
231 super.onDreamingStopped();
235 public void onDreamingStarted () {
236 if (wakeLock != null) wakeLock.acquire();
238 Gdx.input = this.getInput();
239 Gdx.audio = this.getAudio();
240 Gdx.files = this.getFiles();
241 Gdx.graphics = this.getGraphics();
242 Gdx.net = this.getNet();
244 ((AndroidInput)getInput()).registerSensorListeners();
246 if (graphics != null && graphics.view != null) {
247 if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onResume();
248 if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onResume();
255 super.onDreamingStarted();
259 public void onDetachedFromWindow () {
260 super.onDetachedFromWindow();
264 public ApplicationListener getApplicationListener () {
269 public Audio getAudio () {
274 public Files getFiles () {
279 public Graphics getGraphics () {
284 public Input getInput () {
289 public Net getNet () {
294 public ApplicationType getType () {
295 return ApplicationType.Android;
299 public int getVersion () {
300 return Integer.parseInt(android.os.Build.VERSION.SDK);
304 public long getJavaHeap () {
305 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
309 public long getNativeHeap () {
310 return Debug.getNativeHeapAllocatedSize();
314 public Preferences getPreferences (String name) {
315 return new AndroidPreferences(getSharedPreferences(name, Context.MODE_PRIVATE));
318 AndroidClipboard clipboard;
321 public Clipboard getClipboard () {
322 if (clipboard == null) {
323 clipboard = new AndroidClipboard(this);
329 public void postRunnable (Runnable runnable) {
330 synchronized (runnables) {
331 runnables.add(runnable);
332 Gdx.graphics.requestRendering();
337 public void onConfigurationChanged (Configuration config) {
338 super.onConfigurationChanged(config);
339 boolean keyboardAvailable = false;
340 if (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) keyboardAvailable = true;
341 input.keyboardAvailable = keyboardAvailable;
345 public void exit () {
346 handler.post(new Runnable() {
349 AndroidDaydream.this.finish();
355 public void debug (String tag, String message) {
356 if (logLevel >= LOG_DEBUG) {
362 public void debug (String tag, String message, Throwable exception) {
363 if (logLevel >= LOG_DEBUG) {
364 Log.d(tag, message, exception);
369 public void log (String tag, String message) {
370 if (logLevel >= LOG_INFO) Log.i(tag, message);
374 public void log (String tag, String message, Exception exception) {
375 if (logLevel >= LOG_INFO) Log.i(tag, message, exception);
379 public void error (String tag, String message) {
380 if (logLevel >= LOG_ERROR) Log.e(tag, message);
384 public void error (String tag, String message, Throwable exception) {
385 if (logLevel >= LOG_ERROR) Log.e(tag, message, exception);
389 public void setLogLevel (int logLevel) {
390 this.logLevel = logLevel;
394 public int getLogLevel() {
399 public void addLifecycleListener (LifecycleListener listener) {
400 synchronized (lifecycleListeners) {
401 lifecycleListeners.add(listener);
406 public void removeLifecycleListener (LifecycleListener listener) {
407 synchronized (lifecycleListeners) {
408 lifecycleListeners.removeValue(listener, true);