You're breathtaking!

This commit is contained in:
Wojtek Figat
2020-12-07 23:40:54 +01:00
commit 6fb9eee74c
5143 changed files with 1153594 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
defaultConfig {
applicationId "${PackageName}"
minSdkVersion 24
targetSdkVersion 24
versionCode 1
versionName "${ProjectVersion}"
ndk {
abiFilter "${PackageAbi}"
}
}
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = ['jniLibs']
assets.srcDirs = ['assets']
}
}
buildTypes {
release {
debuggable true
minifyEnabled false
}
}
packagingOptions {
doNotStrip '**.so'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="${PackageName}"
android:versionName="${ProjectVersion}">${AndroidPermissions}
<application android:label="@string/app_name"${AndroidAttributes}
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:icon="@mipmap/icon"
android:extractNativeLibs="true"
android:hasCode="true">
<activity android:name="com.flaxengine.GameActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="fullSensor">
<meta-data android:name="android.app.lib_name" android:value="FlaxGame" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,288 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
package com.flaxengine;
import android.app.NativeActivity;
import android.app.PendingIntent;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Bundle;
import android.os.Build;
import android.os.Vibrator;
import android.view.View;
import android.view.Display;
import android.view.KeyEvent;
import android.util.Log;
import android.util.DisplayMetrics;
import android.net.Uri;
import android.net.NetworkInfo;
import android.net.ConnectivityManager;
import android.media.AudioManager;
import android.provider.Settings;
import android.graphics.Point;
import android.annotation.TargetApi;
import java.util.concurrent.Semaphore;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class GameActivity extends NativeActivity {
static {
try {
// Load native libraries
System.loadLibrary("FlaxGame");
} catch (UnsatisfiedLinkError error) {
Log.e("Flax", error.getMessage());
}
}
static GameActivity _activity;
String _appPackageName;
final Semaphore _semaphore = new Semaphore(0, true);
/** Gets the singleton activity for the game. **/
public static GameActivity Get() {
return _activity;
}
private class VibrateRunnable implements Runnable {
private int duration;
private Vibrator vibrator;
VibrateRunnable(final int duration, final Vibrator vibrator) {
this.duration = duration;
this.vibrator = vibrator;
}
public void run () {
if (duration < 1) {
vibrator.cancel();
} else {
vibrator.vibrate(duration);
}
}
}
public void vibrate(int duration) {
Vibrator vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
if (vibrator != null) {
_activity.runOnUiThread(new VibrateRunnable(duration, vibrator));
}
}
public void showAlert(final String text, final String caption) {
final GameActivity activity = this;
activity.runOnUiThread(new Runnable() {
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(activity, AlertDialog.THEME_HOLO_DARK);
builder.setTitle(caption);
builder.setMessage(text);
builder.setPositiveButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
_semaphore.release();
}
});
builder.setCancelable(false);
AlertDialog dialog = builder.create();
dialog.show();
}
});
try {
_semaphore.acquire();
}
catch (InterruptedException e) {
}
}
public int getRotation() {
return getWindowManager().getDefaultDisplay().getRotation();
}
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
static boolean isAirplaneModeOn(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
}
return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
}
public int getNetworkConnectionType() {
try {
if (isAirplaneModeOn(getApplicationContext())) {
return 2;
}
ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if ((activeNetwork != null && activeNetwork.isAvailable() && activeNetwork.isConnectedOrConnecting())) {
switch (activeNetwork.getType()) {
case ConnectivityManager.TYPE_WIFI: return 4;
case ConnectivityManager.TYPE_BLUETOOTH: return 5;
case ConnectivityManager.TYPE_ETHERNET: return 6;
}
return 3;
}
return 0;
} catch (Exception e) {
Log.i("Flax", "Error", e);
return 1;
}
}
public void openUrl(String url) {
Uri webpage = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
static void copyAssetDir(AssetManager am, String path, String outpath) {
try {
String[] res = am.list(path);
for (int i = 0; i < res.length; i++) {
String fromFile = path + "/" + res[i];
String toFile = outpath + "/" + res[i];
InputStream fromStream;
try {
fromStream = am.open(fromFile);
} catch (FileNotFoundException e) {
new File(toFile).mkdirs();
copyAssetDir(am, fromFile, toFile);
continue;
}
copy(fromStream, new FileOutputStream(toFile));
}
} catch (Exception e) {
Log.i("Flax", "Error", e);
}
}
static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buff = new byte[1024];
for (int len = in.read(buff); len != -1; len = in.read(buff)) {
out.write(buff, 0, len);
}
in.close();
out.close();
}
static String readFileText(InputStream stream, Charset encoding) throws IOException {
byte[] buffer = new byte[stream.available()];
stream.read(buffer);
stream.close();
return new String(buffer, encoding);
}
void extractMonoFiles() throws IOException
{
String filesDir = getFilesDir().getAbsolutePath();
AssetManager am = getAssets();
String[] amRootFiles = am.list("");
// Skip if extracted has is the same as in the package
String hashFile = "hash.txt";
File monoHashFile = new File(filesDir + "/" + hashFile);
if (monoHashFile.exists()) {
for (int i = 0; i < amRootFiles.length; i++) {
if (amRootFiles[i].equals(hashFile)) {
String monoHash = readFileText(new FileInputStream(monoHashFile), StandardCharsets.US_ASCII);
String hash = readFileText(am.open(hashFile), StandardCharsets.US_ASCII);
if (monoHash.equals(hash)) {
return;
}
break;
}
}
}
// Extract files
Log.i("Flax", "Extracting Mono files");
new File(filesDir + "/Mono").mkdir();
copyAssetDir(am, "Mono", filesDir + "/Mono");
for (int i = 0; i < amRootFiles.length; i++) {
String fromFile = amRootFiles[i];
if (!fromFile.endsWith(".dll") && !fromFile.equals(hashFile))
continue;
String toFile = filesDir + "/" + amRootFiles[i];
InputStream fromStream = am.open(fromFile);
copy(fromStream, new FileOutputStream(toFile));
}
}
void goFullscreen() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN);
}
@Override
protected void onCreate(Bundle instance) {
_activity = this;
// Extract Mono files and other bundled C# libraries from APK (Mono uses unix file access API which doesn't work with AAssetManager API)
try {
extractMonoFiles();
} catch (Exception e) {
Log.i("Flax", "Error", e);
}
// Set native engine platform info
String appPackageName = getPackageName();
String deviceManufacturer = android.os.Build.MANUFACTURER;
String deviceModel = android.os.Build.MODEL;
String deviceBuildNumber = android.os.Build.DISPLAY;
String systemVersion = android.os.Build.VERSION.RELEASE;
String systemLanguage = java.util.Locale.getDefault().toString();
Display display = getWindowManager().getDefaultDisplay();
Point displayRealSize = new Point();
display.getRealSize(displayRealSize);
int screenWidth = displayRealSize.x;
int screenHeight = displayRealSize.y;
String cacheDir = getCacheDir().toString();
String executablePath = getApplicationInfo().nativeLibraryDir + "/libFlaxGame.so";
nativeSetPlatformInfo(appPackageName, deviceManufacturer, deviceModel, deviceBuildNumber, systemVersion, systemLanguage, screenWidth, screenHeight, cacheDir, executablePath);
super.onCreate(instance);
// Initialize
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
goFullscreen();
}
}
@Override
public void onResume() {
super.onResume();
goFullscreen();
}
public native void nativeSetPlatformInfo(String appPackageName, String deviceManufacturer, String deviceModel, String deviceBuildNumber, String systemVersion, String systemLanguage, int screenWidth, int screenHeight, String cacheDir, String executablePath);
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">${ProjectName}</string>
</resources>