379 lines
11 KiB
Java
379 lines
11 KiB
Java
/*************************************************************************/
|
|
/* GodotIO.java */
|
|
/*************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* https://godotengine.org */
|
|
/*************************************************************************/
|
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
|
/* */
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
/* a copy of this software and associated documentation files (the */
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
/* the following conditions: */
|
|
/* */
|
|
/* The above copyright notice and this permission notice shall be */
|
|
/* included in all copies or substantial portions of the Software. */
|
|
/* */
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
/*************************************************************************/
|
|
|
|
package org.godotengine.godot;
|
|
|
|
import org.godotengine.godot.input.GodotEditText;
|
|
|
|
import android.app.Activity;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Intent;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.content.res.AssetManager;
|
|
import android.graphics.Point;
|
|
import android.graphics.Rect;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import android.os.Environment;
|
|
import android.provider.Settings;
|
|
import android.text.TextUtils;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
import android.util.SparseArray;
|
|
import android.view.Display;
|
|
import android.view.DisplayCutout;
|
|
import android.view.WindowInsets;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Locale;
|
|
|
|
// Wrapper for native library
|
|
|
|
public class GodotIO {
|
|
private static final String TAG = GodotIO.class.getSimpleName();
|
|
|
|
private final AssetManager am;
|
|
private final Activity activity;
|
|
private final String uniqueId;
|
|
GodotEditText edit;
|
|
|
|
final int SCREEN_LANDSCAPE = 0;
|
|
final int SCREEN_PORTRAIT = 1;
|
|
final int SCREEN_REVERSE_LANDSCAPE = 2;
|
|
final int SCREEN_REVERSE_PORTRAIT = 3;
|
|
final int SCREEN_SENSOR_LANDSCAPE = 4;
|
|
final int SCREEN_SENSOR_PORTRAIT = 5;
|
|
final int SCREEN_SENSOR = 6;
|
|
|
|
/////////////////////////
|
|
/// DIRECTORIES
|
|
/////////////////////////
|
|
|
|
static class AssetDir {
|
|
public String[] files;
|
|
public int current;
|
|
public String path;
|
|
}
|
|
|
|
private int last_dir_id = 1;
|
|
|
|
private final SparseArray<AssetDir> dirs;
|
|
|
|
public int dir_open(String path) {
|
|
AssetDir ad = new AssetDir();
|
|
ad.current = 0;
|
|
ad.path = path;
|
|
|
|
try {
|
|
ad.files = am.list(path);
|
|
// no way to find path is directory or file exactly.
|
|
// but if ad.files.length==0, then it's an empty directory or file.
|
|
if (ad.files.length == 0) {
|
|
return -1;
|
|
}
|
|
} catch (IOException e) {
|
|
System.out.printf("Exception on dir_open: %s\n", e);
|
|
return -1;
|
|
}
|
|
|
|
++last_dir_id;
|
|
dirs.put(last_dir_id, ad);
|
|
|
|
return last_dir_id;
|
|
}
|
|
|
|
public boolean dir_is_dir(int id) {
|
|
if (dirs.get(id) == null) {
|
|
System.out.printf("dir_next: invalid dir id: %d\n", id);
|
|
return false;
|
|
}
|
|
AssetDir ad = dirs.get(id);
|
|
//System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
|
|
int idx = ad.current;
|
|
if (idx > 0)
|
|
idx--;
|
|
|
|
if (idx >= ad.files.length)
|
|
return false;
|
|
String fname = ad.files[idx];
|
|
|
|
try {
|
|
if (ad.path.equals(""))
|
|
am.open(fname);
|
|
else
|
|
am.open(ad.path + "/" + fname);
|
|
return false;
|
|
} catch (Exception e) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public String dir_next(int id) {
|
|
if (dirs.get(id) == null) {
|
|
System.out.printf("dir_next: invalid dir id: %d\n", id);
|
|
return "";
|
|
}
|
|
|
|
AssetDir ad = dirs.get(id);
|
|
//System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
|
|
|
|
if (ad.current >= ad.files.length) {
|
|
ad.current++;
|
|
return "";
|
|
}
|
|
String r = ad.files[ad.current];
|
|
ad.current++;
|
|
return r;
|
|
}
|
|
|
|
public void dir_close(int id) {
|
|
if (dirs.get(id) == null) {
|
|
System.out.printf("dir_close: invalid dir id: %d\n", id);
|
|
return;
|
|
}
|
|
|
|
dirs.remove(id);
|
|
}
|
|
|
|
GodotIO(Activity p_activity) {
|
|
am = p_activity.getAssets();
|
|
activity = p_activity;
|
|
dirs = new SparseArray<>();
|
|
String androidId = Settings.Secure.getString(activity.getContentResolver(),
|
|
Settings.Secure.ANDROID_ID);
|
|
if (androidId == null) {
|
|
androidId = "";
|
|
}
|
|
|
|
uniqueId = androidId;
|
|
}
|
|
|
|
/////////////////////////
|
|
// MISCELLANEOUS OS IO
|
|
/////////////////////////
|
|
|
|
public int openURI(String p_uri) {
|
|
try {
|
|
String path = p_uri;
|
|
String type = "";
|
|
if (path.startsWith("/")) {
|
|
//absolute path to filesystem, prepend file://
|
|
path = "file://" + path;
|
|
if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) {
|
|
type = "image/*";
|
|
}
|
|
}
|
|
|
|
Intent intent = new Intent();
|
|
intent.setAction(Intent.ACTION_VIEW);
|
|
if (!type.equals("")) {
|
|
intent.setDataAndType(Uri.parse(path), type);
|
|
} else {
|
|
intent.setData(Uri.parse(path));
|
|
}
|
|
|
|
activity.startActivity(intent);
|
|
return 0;
|
|
} catch (ActivityNotFoundException e) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public String getCacheDir() {
|
|
return activity.getCacheDir().getAbsolutePath();
|
|
}
|
|
|
|
public String getDataDir() {
|
|
return activity.getFilesDir().getAbsolutePath();
|
|
}
|
|
|
|
public String getLocale() {
|
|
return Locale.getDefault().toString();
|
|
}
|
|
|
|
public String getModel() {
|
|
return Build.MODEL;
|
|
}
|
|
|
|
public int getScreenDPI() {
|
|
DisplayMetrics metrics = activity.getApplicationContext().getResources().getDisplayMetrics();
|
|
return (int)(metrics.density * 160f);
|
|
}
|
|
|
|
public int[] screenGetUsableRect() {
|
|
DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
|
|
Display display = activity.getWindowManager().getDefaultDisplay();
|
|
Point size = new Point();
|
|
display.getRealSize(size);
|
|
|
|
int[] result = { 0, 0, size.x, size.y };
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
|
|
DisplayCutout cutout = insets.getDisplayCutout();
|
|
if (cutout != null) {
|
|
int insetLeft = cutout.getSafeInsetLeft();
|
|
int insetTop = cutout.getSafeInsetTop();
|
|
result[0] = insetLeft;
|
|
result[1] = insetTop;
|
|
result[2] -= insetLeft + cutout.getSafeInsetRight();
|
|
result[3] -= insetTop + cutout.getSafeInsetBottom();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public int[] screenGetInactiveRect() {
|
|
int[] result = { 0, 0, 0, 0 };
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
|
|
DisplayCutout cutout = insets.getDisplayCutout();
|
|
if (cutout != null) {
|
|
Rect boundingRect = cutout.getBoundingRects().get(0);
|
|
result[0] = boundingRect.left;
|
|
result[1] = boundingRect.top;
|
|
result[2] = boundingRect.width();
|
|
result[3] = boundingRect.height();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
|
if (edit != null)
|
|
edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
|
|
|
|
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
|
}
|
|
|
|
public void hideKeyboard() {
|
|
if (edit != null)
|
|
edit.hideKeyboard();
|
|
}
|
|
|
|
public void setScreenOrientation(int p_orientation) {
|
|
switch (p_orientation) {
|
|
case SCREEN_LANDSCAPE: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
} break;
|
|
case SCREEN_PORTRAIT: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
} break;
|
|
case SCREEN_REVERSE_LANDSCAPE: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
|
} break;
|
|
case SCREEN_REVERSE_PORTRAIT: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
|
} break;
|
|
case SCREEN_SENSOR_LANDSCAPE: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
|
} break;
|
|
case SCREEN_SENSOR_PORTRAIT: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);
|
|
} break;
|
|
case SCREEN_SENSOR: {
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
public int getScreenOrientation() {
|
|
return activity.getRequestedOrientation();
|
|
}
|
|
|
|
public void setEdit(GodotEditText _edit) {
|
|
edit = _edit;
|
|
}
|
|
|
|
public static final int SYSTEM_DIR_DESKTOP = 0;
|
|
public static final int SYSTEM_DIR_DCIM = 1;
|
|
public static final int SYSTEM_DIR_DOCUMENTS = 2;
|
|
public static final int SYSTEM_DIR_DOWNLOADS = 3;
|
|
public static final int SYSTEM_DIR_MOVIES = 4;
|
|
public static final int SYSTEM_DIR_MUSIC = 5;
|
|
public static final int SYSTEM_DIR_PICTURES = 6;
|
|
public static final int SYSTEM_DIR_RINGTONES = 7;
|
|
|
|
public String getSystemDir(int idx, boolean shared_storage) {
|
|
String what;
|
|
switch (idx) {
|
|
case SYSTEM_DIR_DESKTOP:
|
|
default: {
|
|
what = null; // This leads to the app specific external root directory.
|
|
} break;
|
|
|
|
case SYSTEM_DIR_DCIM: {
|
|
what = Environment.DIRECTORY_DCIM;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_DOCUMENTS: {
|
|
what = Environment.DIRECTORY_DOCUMENTS;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_DOWNLOADS: {
|
|
what = Environment.DIRECTORY_DOWNLOADS;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_MOVIES: {
|
|
what = Environment.DIRECTORY_MOVIES;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_MUSIC: {
|
|
what = Environment.DIRECTORY_MUSIC;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_PICTURES: {
|
|
what = Environment.DIRECTORY_PICTURES;
|
|
} break;
|
|
|
|
case SYSTEM_DIR_RINGTONES: {
|
|
what = Environment.DIRECTORY_RINGTONES;
|
|
} break;
|
|
}
|
|
|
|
if (shared_storage) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
Log.w(TAG, "Shared storage access is limited on Android 10 and higher.");
|
|
}
|
|
if (TextUtils.isEmpty(what)) {
|
|
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
|
} else {
|
|
return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath();
|
|
}
|
|
} else {
|
|
return activity.getExternalFilesDir(what).getAbsolutePath();
|
|
}
|
|
}
|
|
|
|
public String getUniqueID() {
|
|
return uniqueId;
|
|
}
|
|
}
|