diff --git a/source/funkin/mobile/external/android/CallbackUtil.hx b/source/funkin/mobile/external/android/CallbackUtil.hx index f8310d826..440368ecf 100644 --- a/source/funkin/mobile/external/android/CallbackUtil.hx +++ b/source/funkin/mobile/external/android/CallbackUtil.hx @@ -12,7 +12,15 @@ class CallbackUtil /** * The result code for `DATA_FOLDER_CLOSED` activity. */ - public static final DATA_FOLDER_CLOSED:Int = JNI.createStaticField('funkin/extensions/CallbackUtil', 'DATA_FOLDER_CLOSED', 'I').get(); + public static var DATA_FOLDER_CLOSED(get, never):Int; + + @:noCompletion + static function get_DATA_FOLDER_CLOSED():Int + { + final field:Null = JNIUtil.createStaticField('funkin/extensions/CallbackUtil', 'DATA_FOLDER_CLOSED', 'I'); + + return field != null ? field.get() : 0; + } /** * Signal triggered when an activity result is received. @@ -21,21 +29,27 @@ class CallbackUtil */ public static var onActivityResult:FlxTypedSignalInt->Void> = new FlxTypedSignalInt->Void>(); + /** + * Initializes the callback utility. + */ public static function init():Void { - final initCallBackJNI:Null = JNI.createStaticMethod('funkin/extensions/CallbackUtil', 'initCallBack', '(Lorg/haxe/lime/HaxeObject;)V'); + final initCallBackJNI:Null = JNIUtil.createStaticMethod('funkin/extensions/CallbackUtil', 'initCallBack', '(Lorg/haxe/lime/HaxeObject;)V'); - if (initCallBackJNI != null) initCallBackJNI(new CallBackHandler()); + if (initCallBackJNI != null) + { + initCallBackJNI(new CallbackHandler()); + } } } /** * Internal class to handle native callback events. */ -@:noCompletion -private class CallBackHandler #if (lime >= "8.0.0") implements JNISafety #end +class CallbackHandler #if (lime >= "8.0.0") implements JNISafety #end { - public function new():Void {} + @:allow(funkin.mobile.external.android.CallbackUtil) + function new():Void {} /** * Handles the activity result callback from native code. diff --git a/source/funkin/mobile/external/android/DataFolderUtil.hx b/source/funkin/mobile/external/android/DataFolderUtil.hx index adaefbe45..90b63ddd2 100644 --- a/source/funkin/mobile/external/android/DataFolderUtil.hx +++ b/source/funkin/mobile/external/android/DataFolderUtil.hx @@ -1,34 +1,21 @@ package funkin.mobile.external.android; -import lime.system.JNI; - /** * A Utility class to manage the Application's Data folder on Android. */ @:unreflective class DataFolderUtil { - @:noCompletion - static var staticMethodCache:Map = []; - + /** + * Opens the data folder on an Android device using JNI. + */ public static function openDataFolder():Void { - final openDataFolderJNI:Null = createStaticMethod('funkin/util/DataFolderUtil', 'openDataFolder', '()V'); + final openDataFolderJNI:Null = JNIUtil.createStaticMethod('funkin/util/DataFolderUtil', 'openDataFolder', '(I)V'); - if (openDataFolderJNI != null) openDataFolderJNI(); - } - - @:noCompletion - static function createStaticMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null - { - @:privateAccess - className = JNI.transformClassName(className); - - final key:String = '$className::$methodName::$signature'; - - if (cache && !staticMethodCache.exists(key)) staticMethodCache.set(key, JNI.createStaticMethod(className, methodName, signature)); - else if (!cache) return JNI.createStaticMethod(className, methodName, signature); - - return staticMethodCache.get(key); + if (openDataFolderJNI != null) + { + openDataFolderJNI(CallbackUtil.DATA_FOLDER_CLOSED); + } } } diff --git a/source/funkin/mobile/external/android/JNIUtil.hx b/source/funkin/mobile/external/android/JNIUtil.hx new file mode 100644 index 000000000..52d66e55e --- /dev/null +++ b/source/funkin/mobile/external/android/JNIUtil.hx @@ -0,0 +1,111 @@ +package funkin.mobile.external.android; + +#if android +import lime.system.JNI; + +/** + * A utility class for caching JNI method and field references. + */ +class JNIUtil +{ + @:noCompletion + private static var staticMethodCache:Map = []; + + @:noCompletion + private static var memberMethodCache:Map = []; + + @:noCompletion + private static var staticFieldCache:Map = []; + + @:noCompletion + private static var memberFieldCache:Map = []; + + /** + * Retrieves or creates a cached static method reference. + * + * @param className The name of the Java class containing the method. + * @param methodName The name of the method. + * @param signature The method signature in JNI format. + * @param cache Whether to cache the result (default true). + * @return A dynamic reference to the static method. + */ + public static function createStaticMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null + { + @:privateAccess + className = JNI.transformClassName(className); + + final key:String = '$className::$methodName::$signature'; + + if (cache && !staticMethodCache.exists(key)) staticMethodCache.set(key, JNI.createStaticMethod(className, methodName, signature)); + else if (!cache) return JNI.createStaticMethod(className, methodName, signature); + + return staticMethodCache.get(key); + } + + /** + * Retrieves or creates a cached member method reference. + * + * @param className The name of the Java class containing the method. + * @param methodName The name of the method. + * @param signature The method signature in JNI format. + * @param cache Whether to cache the result (default true). + * @return A dynamic reference to the member method. + */ + public static function createMemberMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null + { + @:privateAccess + className = JNI.transformClassName(className); + + final key:String = '$className::$methodName::$signature'; + + if (cache && !memberMethodCache.exists(key)) memberMethodCache.set(key, JNI.createMemberMethod(className, methodName, signature)); + else if (!cache) return JNI.createMemberMethod(className, methodName, signature); + + return memberMethodCache.get(key); + } + + /** + * Retrieves or creates a cached static field reference. + * + * @param className The name of the Java class containing the field. + * @param fieldName The name of the field. + * @param signature The field signature in JNI format. + * @param cache Whether to cache the result (default true). + * @return A reference to the static field. + */ + public static function createStaticField(className:String, fieldName:String, signature:String, cache:Bool = true):Null + { + @:privateAccess + className = JNI.transformClassName(className); + + final key:String = '$className::$fieldName::$signature'; + + if (cache && !staticFieldCache.exists(key)) staticFieldCache.set(key, JNI.createStaticField(className, fieldName, signature)); + else if (!cache) return JNI.createStaticField(className, fieldName, signature); + + return staticFieldCache.get(key); + } + + /** + * Retrieves or creates a cached member field reference. + * + * @param className The name of the Java class containing the field. + * @param fieldName The name of the field. + * @param signature The field signature in JNI format. + * @param cache Whether to cache the result (default true). + * @return A reference to the member field. + */ + public static function createMemberField(className:String, fieldName:String, signature:String, cache:Bool = true):Null + { + @:privateAccess + className = JNI.transformClassName(className); + + final key:String = '$className::$fieldName::$signature'; + + if (cache && !memberFieldCache.exists(key)) memberFieldCache.set(key, JNI.createMemberField(className, fieldName, signature)); + else if (!cache) return JNI.createMemberField(className, fieldName, signature); + + return memberFieldCache.get(key); + } +} +#end diff --git a/source/funkin/mobile/external/android/ScreenUtil.hx b/source/funkin/mobile/external/android/ScreenUtil.hx new file mode 100644 index 000000000..966bc4a0f --- /dev/null +++ b/source/funkin/mobile/external/android/ScreenUtil.hx @@ -0,0 +1,50 @@ +package funkin.mobile.external.android; + +import lime.math.Rectangle; +import lime.system.JNI; + +/** + * A Utility class to get Android screen related informations. + */ +@:unreflective +class ScreenUtil +{ + /** + * Retrieves the dimensions of display cutouts (such as notches) on Android devices. + * + * @return An array of `Rectangle` objects, each representing a display cutout's position and size. + */ + public static function getCutoutDimensions():Array + { + final getCutoutDimensionsJNI:Null = JNIUtil.createStaticMethod('funkin/util/ScreenUtil', 'getCutoutDimensions', '()[Landroid/graphics/Rect;'); + + if (getCutoutDimensionsJNI != null) + { + final rectangles:Array = []; + + for (rectangle in cast(getCutoutDimensionsJNI(), Array)) + { + if (rectangle == null) continue; + + final topJNI:Null = JNIUtil.createMemberField('android/graphics/Rect', 'top', 'I'); + final leftJNI:Null = JNIUtil.createMemberField('android/graphics/Rect', 'left', 'I'); + final rightJNI:Null = JNIUtil.createMemberField('android/graphics/Rect', 'right', 'I'); + final bottomJNI:Null = JNIUtil.createMemberField('android/graphics/Rect', 'bottom', 'I'); + + if (topJNI != null && leftJNI != null && rightJNI != null && bottomJNI != null) + { + final top:Int = topJNI.get(rectangle); + final left:Int = leftJNI.get(rectangle); + final right:Int = rightJNI.get(rectangle); + final bottom:Int = bottomJNI.get(rectangle); + + rectangles.push(new Rectangle(left, top, right - left, bottom - top)); + } + } + + return rectangles; + } + + return []; + } +} diff --git a/source/funkin/mobile/external/android/ScreenUtils.hx b/source/funkin/mobile/external/android/ScreenUtils.hx deleted file mode 100644 index 3ba2a0a1e..000000000 --- a/source/funkin/mobile/external/android/ScreenUtils.hx +++ /dev/null @@ -1,79 +0,0 @@ -package funkin.mobile.external.android; - -import lime.math.Rectangle; -import lime.system.JNI; - -/** - * A Utility class to get Android screen related informations. - */ -@:unreflective -class ScreenUtils -{ - @:noCompletion - static var staticMethodCache:Map = []; - - @:noCompletion - static var memberFieldCache:Map = []; - - public static function getCutoutDimensions():Array - { - final getCutoutDimensionsJNI:Null = createStaticMethod('funkin/util/ScreenUtils', 'getCutoutDimensions', '()[Landroid/graphics/Rect;'); - - if (getCutoutDimensionsJNI != null) - { - final rectangles:Array = []; - - for (rectangle in cast(getCutoutDimensionsJNI(), Array)) - { - if (rectangle == null) continue; - - final topJNI:Null = createMemberField('android/graphics/Rect', 'top', 'I'); - final leftJNI:Null = createMemberField('android/graphics/Rect', 'left', 'I'); - final rightJNI:Null = createMemberField('android/graphics/Rect', 'right', 'I'); - final bottomJNI:Null = createMemberField('android/graphics/Rect', 'bottom', 'I'); - - if (topJNI != null && leftJNI != null && rightJNI != null && bottomJNI != null) - { - final top:Int = topJNI.get(rectangle); - final left:Int = leftJNI.get(rectangle); - final right:Int = rightJNI.get(rectangle); - final bottom:Int = bottomJNI.get(rectangle); - - rectangles.push(new Rectangle(left, top, right - left, bottom - top)); - } - } - - return rectangles; - } - - return []; - } - - @:noCompletion - static function createStaticMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null - { - @:privateAccess - className = JNI.transformClassName(className); - - final key:String = '$className::$methodName::$signature'; - - if (cache && !staticMethodCache.exists(key)) staticMethodCache.set(key, JNI.createStaticMethod(className, methodName, signature)); - else if (!cache) return JNI.createStaticMethod(className, methodName, signature); - - return staticMethodCache.get(key); - } - - @:noCompletion - static function createMemberField(className:String, fieldName:String, signature:String, cache:Bool = true):Null - { - @:privateAccess - className = JNI.transformClassName(className); - - final key:String = '$className::$fieldName::$signature'; - - if (cache && !memberFieldCache.exists(key)) memberFieldCache.set(key, JNI.createMemberField(className, fieldName, signature)); - else if (!cache) return JNI.createMemberField(className, fieldName, signature); - - return memberFieldCache.get(key); - } -} diff --git a/source/funkin/mobile/external/android/java/funkin/extension/CallbackUtil.java b/source/funkin/mobile/external/android/java/funkin/extension/CallbackUtil.java index 9a3966c11..617a6f3b7 100644 --- a/source/funkin/mobile/external/android/java/funkin/extension/CallbackUtil.java +++ b/source/funkin/mobile/external/android/java/funkin/extension/CallbackUtil.java @@ -3,42 +3,33 @@ package funkin.extensions; import android.content.Intent; import org.haxe.extension.Extension; + import org.haxe.lime.HaxeObject; public class CallbackUtil extends Extension { - public static HaxeObject cbObject; - + /** + * Constant representing the event when the data folder is closed. + */ public static int DATA_FOLDER_CLOSED = 0x01; + private static HaxeObject haxeObject; + /** * Initializes the callback object for handling Haxe callbacks. * - * @param cbObject The HaxeObject instance to handle callbacks. + * @param haxeObject The HaxeObject instance to handle callbacks. */ - public static void initCallBack(final HaxeObject cbObject) + public static void initCallBack(final HaxeObject haxeObject) { - CallbackUtil.cbObject = cbObject; + CallbackUtil.haxeObject = haxeObject; } @Override public boolean onActivityResult(int requestCode, int resultCode, Intent data) { - if (cbObject != null) - { - try - { - Object[] args = new Object[2]; - args[0] = requestCode; - args[1] = resultCode; - - cbObject.call("onActivityResult", args); - } - catch (Exception e) - { - e.printStackTrace(); - } - } + if (haxeObject != null) + haxeObject.call2("onActivityResult", requestCode, resultCode); return true; } diff --git a/source/funkin/mobile/external/android/java/funkin/util/DataFolderUtil.java b/source/funkin/mobile/external/android/java/funkin/util/DataFolderUtil.java index d4da85722..94b7b97b1 100644 --- a/source/funkin/mobile/external/android/java/funkin/util/DataFolderUtil.java +++ b/source/funkin/mobile/external/android/java/funkin/util/DataFolderUtil.java @@ -7,13 +7,10 @@ import android.os.Build; import android.provider.DocumentsContract; import android.content.pm.PackageInfo; -import funkin.extensions.CallbackUtil; - import java.util.List; import org.haxe.extension.Extension; - public class DataFolderUtil { /** @@ -21,41 +18,16 @@ public class DataFolderUtil * It's highly based on some code borrowed from Mterial Files * https://github.com/zhanghai/MaterialFiles */ - public static void openDataFolder() + public static void openDataFolder(int requestCode) { ::if (APP_PACKAGE != ""):: if (Extension.mainActivity != null) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(DocumentsContract.buildRootUri("::APP_PACKAGE::.docprovider", ""), "vnd.android.document/directory"); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - String documentsUiPackage = getDocumentsUiPackage(); - if (documentsUiPackage != null) { - intent.setPackage(documentsUiPackage); - Extension.mainActivity.startActivityForResult(intent, CallbackUtil.DATA_FOLDER_CLOSED); - } + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(DocumentsContract.buildRootUri("::APP_PACKAGE::.docprovider", ""), "vnd.android.document/directory"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Extension.mainActivity.startActivityForResult(intent, requestCode); } ::end:: } - - private static String getDocumentsUiPackage() { - List packageInfos = Extension.mainContext.getPackageManager().getPackagesHoldingPermissions( - new String[]{"android.permission.MANAGE_DOCUMENTS"}, 0 - ); - - PackageInfo targetPackage = null; - for (PackageInfo pkg : packageInfos) { - if (pkg.packageName.endsWith(".documentsui")) { - targetPackage = pkg; - break; - } - } - - if (targetPackage == null && !packageInfos.isEmpty()) { - targetPackage = packageInfos.get(0); - } - - return targetPackage != null ? targetPackage.packageName : null; - } } diff --git a/source/funkin/mobile/external/android/java/funkin/util/ScreenUtils.java b/source/funkin/mobile/external/android/java/funkin/util/ScreenUtil.java similarity index 96% rename from source/funkin/mobile/external/android/java/funkin/util/ScreenUtils.java rename to source/funkin/mobile/external/android/java/funkin/util/ScreenUtil.java index 788d54337..6cc9845c1 100644 --- a/source/funkin/mobile/external/android/java/funkin/util/ScreenUtils.java +++ b/source/funkin/mobile/external/android/java/funkin/util/ScreenUtil.java @@ -9,7 +9,7 @@ import java.util.List; import org.haxe.extension.Extension; -public class ScreenUtils +public class ScreenUtil { public static Rect[] getCutoutDimensions() { diff --git a/source/funkin/mobile/external/ios/ScreenUtils.hx b/source/funkin/mobile/external/ios/ScreenUtil.hx similarity index 90% rename from source/funkin/mobile/external/ios/ScreenUtils.hx rename to source/funkin/mobile/external/ios/ScreenUtil.hx index c1e532dea..76d93a704 100644 --- a/source/funkin/mobile/external/ios/ScreenUtils.hx +++ b/source/funkin/mobile/external/ios/ScreenUtil.hx @@ -4,9 +4,9 @@ package funkin.mobile.external.ios; * A Utility class to get iOS screen related informations. */ @:build(funkin.mobile.macros.LinkerMacro.xml('project/Build.xml')) -@:include('ScreenUtils.hpp') +@:include('ScreenUtil.hpp') @:unreflective -extern class ScreenUtils +extern class ScreenUtil { @:native('getSafeAreaInsets') static function getSafeAreaInsets(top:cpp.RawPointer, bottom:cpp.RawPointer, left:cpp.RawPointer, right:cpp.RawPointer):Void; diff --git a/source/funkin/mobile/external/ios/project/Build.xml b/source/funkin/mobile/external/ios/project/Build.xml index 22d80effb..a81ee08f2 100644 --- a/source/funkin/mobile/external/ios/project/Build.xml +++ b/source/funkin/mobile/external/ios/project/Build.xml @@ -13,7 +13,7 @@ - + diff --git a/source/funkin/mobile/external/ios/project/ios/include/ScreenUtils.hpp b/source/funkin/mobile/external/ios/project/ios/include/ScreenUtil.hpp similarity index 100% rename from source/funkin/mobile/external/ios/project/ios/include/ScreenUtils.hpp rename to source/funkin/mobile/external/ios/project/ios/include/ScreenUtil.hpp diff --git a/source/funkin/mobile/external/ios/project/ios/src/ScreenUtils.mm b/source/funkin/mobile/external/ios/project/ios/src/ScreenUtil.mm similarity index 97% rename from source/funkin/mobile/external/ios/project/ios/src/ScreenUtils.mm rename to source/funkin/mobile/external/ios/project/ios/src/ScreenUtil.mm index 77fb6ed9b..7b7a29097 100644 --- a/source/funkin/mobile/external/ios/project/ios/src/ScreenUtils.mm +++ b/source/funkin/mobile/external/ios/project/ios/src/ScreenUtil.mm @@ -1,4 +1,4 @@ -#import "ScreenUtils.hpp" +#import "ScreenUtil.hpp" #import #import diff --git a/source/funkin/mobile/util/ScreenUtil.hx b/source/funkin/mobile/util/ScreenUtil.hx index 72b2209de..27bf023f3 100644 --- a/source/funkin/mobile/util/ScreenUtil.hx +++ b/source/funkin/mobile/util/ScreenUtil.hx @@ -1,9 +1,9 @@ package funkin.mobile.util; #if ios -import funkin.mobile.external.ios.ScreenUtils; +import funkin.mobile.external.ios.ScreenUtil as NativeScreenUtil; #elseif android -import funkin.mobile.external.android.ScreenUtils; +import funkin.mobile.external.android.ScreenUtil as NativeScreenUtil; #end import lime.math.Rectangle; import lime.system.System; @@ -26,7 +26,7 @@ class ScreenUtil final rectDimensions:Array> = [[], [], [], []]; // Push all the dimensions of the cutouts into an array - for (rect in ScreenUtils.getCutoutDimensions()) + for (rect in NativeScreenUtil.getCutoutDimensions()) { rectDimensions[0].push(rect.x); rectDimensions[1].push(rect.y); @@ -59,13 +59,12 @@ class ScreenUtil var bottomInset:Float = -1; var deviceWidth:Float = -1; var deviceHeight:Float = -1; + var displayOrientation:DisplayOrientation = System.getDisplayOrientation(0); - ScreenUtils.getSafeAreaInsets(cpp.RawPointer.addressOf(topInset), cpp.RawPointer.addressOf(bottomInset), cpp.RawPointer.addressOf(leftInset), + NativeScreenUtil.getSafeAreaInsets(cpp.RawPointer.addressOf(topInset), cpp.RawPointer.addressOf(bottomInset), cpp.RawPointer.addressOf(leftInset), cpp.RawPointer.addressOf(rightInset)); - ScreenUtils.getScreenSize(cpp.RawPointer.addressOf(deviceWidth), cpp.RawPointer.addressOf(deviceHeight)); - - var displayOrientation = System.getDisplayOrientation(0); + NativeScreenUtil.getScreenSize(cpp.RawPointer.addressOf(deviceWidth), cpp.RawPointer.addressOf(deviceHeight)); notchRect.x = 0; notchRect.y = 0.0; diff --git a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx index d96e51575..51424c1f3 100644 --- a/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx +++ b/source/funkin/util/plugins/ReloadAssetsDebugPlugin.hx @@ -69,6 +69,7 @@ class ReloadAssetsDebugPlugin extends FlxBasic } } + #if android @:noCompletion function onActivityResult(resultCode:Int, requestCode:Int):Void { @@ -77,4 +78,5 @@ class ReloadAssetsDebugPlugin extends FlxBasic reload(); } } + #end }