All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.backends.iosmoe.IOSApplication Maven / Gradle / Ivy

There is a newer version: 1.9.11
Show newest version
/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * 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.iosmoe;

import java.io.File;

import org.moe.natj.general.Pointer;
import org.moe.natj.objc.ann.Selector;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.ApplicationLogger;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.backends.iosmoe.objectal.OALAudioSession;
import com.badlogic.gdx.backends.iosmoe.objectal.OALSimpleAudio;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Clipboard;

import apple.NSObject;
import apple.coregraphics.struct.CGPoint;
import apple.coregraphics.struct.CGRect;
import apple.coregraphics.struct.CGSize;
import apple.foundation.NSDictionary;
import apple.foundation.NSMutableDictionary;
import apple.foundation.NSThread;
import apple.uikit.UIApplication;
import apple.uikit.UIDevice;
import apple.uikit.UIPasteboard;
import apple.uikit.UIScreen;
import apple.uikit.UIViewController;
import apple.uikit.UIWindow;
import apple.uikit.enums.UIInterfaceOrientation;
import apple.uikit.enums.UIUserInterfaceIdiom;
import apple.uikit.protocol.UIApplicationDelegate;

public class IOSApplication implements Application {

	public static abstract class Delegate extends NSObject implements UIApplicationDelegate {

		private IOSApplication app;

		protected Delegate (Pointer peer) {
			super(peer);
		}

		@Selector("alloc")
		public static native Delegate alloc ();

		protected abstract IOSApplication createApplication ();

		@Override
		public boolean applicationDidFinishLaunchingWithOptions (UIApplication application, NSDictionary launchOptions) {
			this.app = createApplication();
			return app.didFinishLaunching(application, launchOptions);
		}

		@Override
		public void applicationDidBecomeActive (UIApplication application) {
			app.didBecomeActive(application);
		}

		@Override
		public void applicationWillEnterForeground (UIApplication application) {
			app.willEnterForeground(application);
		}

		@Override
		public void applicationWillResignActive (UIApplication application) {
			app.willResignActive(application);
		}

		@Override
		public void applicationWillTerminate (UIApplication application) {
			app.willTerminate(application);
		}

		@Override
		public UIWindow window () {
			return app.getUIWindow();
		}
	}

	UIApplication uiApp;
	UIWindow uiWindow;
	ApplicationListener listener;
	IOSViewControllerListener viewControllerListener;
	IOSApplicationConfiguration config;
	IOSGraphics graphics;
	IOSAudio audio;
	IOSFiles files;
	IOSInput input;
	IOSNet net;
	int logLevel = Application.LOG_DEBUG;
	ApplicationLogger applicationLogger;

	/** The display scale factor (1.0f for normal; 2.0f to use retina coordinates/dimensions). */
	float displayScaleFactor;

	protected CGRect lastScreenBounds = null;

	Array runnables = new Array();
	Array executedRunnables = new Array();
	Array lifecycleListeners = new Array();

	public IOSApplication (ApplicationListener listener, IOSApplicationConfiguration config) {
		this.listener = listener;
		this.config = config;
	}

	final boolean didFinishLaunching (UIApplication uiApp, NSDictionary launchOptions) {
		this.uiApp = uiApp;

		init();

		this.uiWindow = UIWindow.alloc().initWithFrame(UIScreen.mainScreen().bounds());
		this.uiWindow.setRootViewController(this.graphics.viewController);
		this.uiWindow.makeKeyAndVisible();
		Gdx.app.debug("IOSApplication", "created");
		return true;
	}

	protected void init () {
		setApplicationLogger(new IOSApplicationLogger());
		Gdx.app = this;

		// enable or disable screen dimming
		UIApplication.sharedApplication().setIdleTimerDisabled(config.preventScreenDimming);

		Gdx.app.debug("IOSApplication", "iOS version: " + UIDevice.currentDevice().systemVersion());
		// fix the scale factor if we have a retina device (NOTE: iOS screen sizes are in "points" not pixels by default!)

		float scale = (float)(getIosVersion() >= 8 ? UIScreen.mainScreen().nativeScale() : UIScreen.mainScreen().nativeScale());
		if (scale >= 2.0f) {
			Gdx.app.debug("IOSApplication", "scale: " + scale);
			if (UIDevice.currentDevice().userInterfaceIdiom() == UIUserInterfaceIdiom.Pad) {
				// it's an iPad!
				displayScaleFactor = config.displayScaleLargeScreenIfRetina * scale;
			} else {
				// it's an iPod or iPhone
				displayScaleFactor = config.displayScaleSmallScreenIfRetina * scale;
			}
		} else {
			// no retina screen: no scaling!
			if (UIDevice.currentDevice().userInterfaceIdiom() == UIUserInterfaceIdiom.Pad) {
				// it's an iPad!
				displayScaleFactor = config.displayScaleLargeScreenIfNonRetina;
			} else {
				// it's an iPod or iPhone
				displayScaleFactor = config.displayScaleSmallScreenIfNonRetina;
			}
		}

		// setup libgdx
		this.input = createInput();
		this.graphics = createGraphics(scale);
		Gdx.gl = Gdx.gl20 = graphics.gl20;
		Gdx.gl30 = graphics.gl30;
		this.files = new IOSFiles();
		this.audio = new IOSAudio(config);
		this.net = new IOSNet(this);

		Gdx.files = this.files;
		Gdx.graphics = this.graphics;
		Gdx.audio = this.audio;
		Gdx.input = this.input;
		Gdx.net = this.net;

		this.input.setupPeripherals();
	}

	protected IOSGraphics createGraphics (float scale) {
		return IOSGraphics.alloc().init(scale, this, config, input, config.useGL30);
	}

	protected IOSInput createInput() {
		return new IOSInput(this);
	}

	private int getIosVersion () {
		String systemVersion = UIDevice.currentDevice().systemVersion();
		int version = Integer.parseInt(systemVersion.split("\\.")[0]);
		return version;
	}

	/** Return the UI view controller of IOSApplication
	 * @return the view controller of IOSApplication */
	public UIViewController getUIViewController () {
		return graphics.viewController;
	}

	/** Return the UI Window of IOSApplication
	 * @return the window */
	public UIWindow getUIWindow () {
		return uiWindow;
	}

	/** GL View spans whole screen, that is, even under the status bar. iOS can also rotate the screen, which is not handled
	 * consistently over iOS versions. This method returns, in pixels, rectangle in which libGDX draws.
	 *
	 * @return dimensions of space we draw to, adjusted for device orientation */
	protected CGRect getBounds () {
		final CGRect screenBounds = getOriginalBounds();
		final long statusBarOrientation = getStatusBarOrientation();

		double screenWidth = screenBounds.size().width();
		double screenHeight = screenBounds.size().height();

		// Make sure that the orientation is consistent with ratios. Should be, but may not be on older iOS versions
		if (statusBarOrientation == UIInterfaceOrientation.LandscapeLeft
			|| statusBarOrientation == UIInterfaceOrientation.LandscapeRight) {
			if (screenHeight > screenWidth) {
				debug("IOSApplication", "Switching reported width and height (w=" + screenWidth + " h=" + screenHeight + ")");
				double tmp = screenHeight;
				// noinspection SuspiciousNameCombination
				screenHeight = screenWidth;
				screenWidth = tmp;
			}
		}

		// update width/height depending on display scaling selected
		screenWidth *= displayScaleFactor;
		screenHeight *= displayScaleFactor;

		double statusBarHeight = getStatusBarHeight(screenHeight);

		debug("IOSApplication", "Total computed bounds are w=" + screenWidth + " h=" + screenHeight);

		return lastScreenBounds = new CGRect(new CGPoint(0, statusBarHeight), new CGSize(screenWidth, screenHeight));
	}

	protected CGRect getCachedBounds () {
		if (lastScreenBounds == null)
			return getBounds();
		else
			return lastScreenBounds;
	}

	final void didBecomeActive (UIApplication uiApp) {
		Gdx.app.debug("IOSApplication", "resumed");
		// workaround for ObjectAL crash problem
		// see: https://groups.google.com/forum/?fromgroups=#!topic/objectal-for-iphone/ubRWltp_i1Q
		OALAudioSession audioSession = OALAudioSession.sharedInstance();
		if (audioSession != null) {
			audioSession.forceEndInterruption();
		}
		if (config.allowIpod) {
			OALSimpleAudio audio = OALSimpleAudio.sharedInstance();
			if (audio != null) {
				audio.setUseHardwareIfAvailable(false);
			}
		}
		graphics.makeCurrent();
		graphics.resume();
	}

	final void willEnterForeground (UIApplication uiApp) {
		// workaround for ObjectAL crash problem
		// see: https://groups.google.com/forum/?fromgroups=#!topic/objectal-for-iphone/ubRWltp_i1Q
		OALAudioSession audioSession = OALAudioSession.sharedInstance();
		if (audioSession != null) {
			audioSession.forceEndInterruption();
		}
	}

	final void willResignActive (UIApplication uiApp) {
		Gdx.app.debug("IOSApplication", "paused");
		graphics.makeCurrent();
		graphics.pause();
		Gdx.gl.glFinish();
	}

	final void willTerminate (UIApplication uiApp) {
		Gdx.app.debug("IOSApplication", "disposed");
		graphics.makeCurrent();
		Array listeners = lifecycleListeners;
		synchronized (listeners) {
			for (LifecycleListener listener : listeners) {
				listener.pause();
			}
		}
		listener.dispose();
		Gdx.gl.glFinish();
	}

	@Override
	public ApplicationListener getApplicationListener () {
		return listener;
	}

	@Override
	public Graphics getGraphics () {
		return graphics;
	}

	@Override
	public Audio getAudio () {
		return audio;
	}

	@Override
	public Input getInput () {
		return input;
	}

	@Override
	public Files getFiles () {
		return files;
	}

	@Override
	public Net getNet () {
		return net;
	}

	@Override
	public void debug (String tag, String message) {
		if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message);
	}

	@Override
	public void debug (String tag, String message, Throwable exception) {
		if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message, exception);
	}

	@Override
	public void log (String tag, String message) {
		if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message);
	}

	@Override
	public void log (String tag, String message, Throwable exception) {
		if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message, exception);
	}

	@Override
	public void error (String tag, String message) {
		if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message);
	}

	@Override
	public void error (String tag, String message, Throwable exception) {
		if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message, exception);
	}

	@Override
	public void setLogLevel (int logLevel) {
		this.logLevel = logLevel;
	}

	@Override
	public int getLogLevel () {
		return logLevel;
	}

	@Override
	public void setApplicationLogger (ApplicationLogger applicationLogger) {
		this.applicationLogger = applicationLogger;
	}

	@Override
	public ApplicationLogger getApplicationLogger () {
		return applicationLogger;
	}

	@Override
	public ApplicationType getType () {
		return ApplicationType.iOS;
	}

	@Override
	public int getVersion () {
		return Integer.parseInt(UIDevice.currentDevice().systemVersion().split("\\.")[0]);
	}

	@Override
	public long getJavaHeap () {
		return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
	}

	@Override
	public long getNativeHeap () {
		return getJavaHeap();
	}

	@Override
	public Preferences getPreferences (String name) {
		File libraryPath = new File(System.getenv("HOME"), "Library");
		File finalPath = new File(libraryPath, name + ".plist");
		String path = libraryPath + "/" + name + ".plist";

		NSMutableDictionary nsDictionary = NSMutableDictionary.dictionaryWithContentsOfFile(path);

		// if it fails to get an existing dictionary, create a new one.
		if (nsDictionary == null) {
			nsDictionary = (NSMutableDictionary)NSMutableDictionary.alloc().init();
			nsDictionary.writeToFileAtomically(path, false);
		}
		return new IOSPreferences(nsDictionary, finalPath.getAbsolutePath());
	}

	@Override
	public void postRunnable (Runnable runnable) {
		synchronized (runnables) {
			runnables.add(runnable);
			Gdx.graphics.requestRendering();
		}
	}

	public void processRunnables () {
		synchronized (runnables) {
			executedRunnables.clear();
			executedRunnables.addAll(runnables);
			runnables.clear();
		}
		for (int i = 0; i < executedRunnables.size; i++) {
			try {
				executedRunnables.get(i).run();
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	@Override
	public void exit () {
		NSThread.exit();
	}

	@Override
	public Clipboard getClipboard () {
		return new Clipboard() {
			@Override
			public void setContents (String content) {
				UIPasteboard.generalPasteboard().setString(content);
			}

			@Override
			public String getContents () {
				return UIPasteboard.generalPasteboard().string();
			}
		};
	}

	@Override
	public void addLifecycleListener (LifecycleListener listener) {
		synchronized (lifecycleListeners) {
			lifecycleListeners.add(listener);
		}
	}

	@Override
	public void removeLifecycleListener (LifecycleListener listener) {
		synchronized (lifecycleListeners) {
			lifecycleListeners.removeValue(listener, true);
		}
	}

	/** Add a listener to handle events from the libgdx root view controller
	 * @param listener The {#link IOSViewControllerListener} to add */
	public void addViewControllerListener (IOSViewControllerListener listener) {
		viewControllerListener = listener;
	}

	protected CGRect getOriginalBounds () {
		return UIScreen.mainScreen().bounds();
	}

	protected double getStatusBarHeight (double screenHeight) {
		final CGRect statusBarFrame = uiApp.statusBarFrame();
		double statusBarHeight = Math.min(statusBarFrame.size().width(), statusBarFrame.size().height());
		if (statusBarHeight != 0.0) {
			debug("IOSApplication", "Status bar is visible (height = " + statusBarHeight + ")");
			statusBarHeight *= displayScaleFactor;
			screenHeight -= statusBarHeight;
		} else {
			debug("IOSApplication", "Status bar is not visible");
		}

		return statusBarHeight;
	}

	protected long getStatusBarOrientation () {
		return uiApp.statusBarOrientation();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy