Some adjustments

This commit is contained in:
MAJigsaw77
2025-07-13 08:49:32 +03:00
committed by Mihai Alexandru
parent f91261f748
commit 314d8af9c8
14 changed files with 218 additions and 171 deletions
+20 -6
View File
@@ -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<Dynamic> = 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:FlxTypedSignal<Int->Int->Void> = new FlxTypedSignal<Int->Int->Void>();
/**
* Initializes the callback utility.
*/
public static function init():Void
{
final initCallBackJNI:Null<Dynamic> = JNI.createStaticMethod('funkin/extensions/CallbackUtil', 'initCallBack', '(Lorg/haxe/lime/HaxeObject;)V');
final initCallBackJNI:Null<Dynamic> = 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.
+8 -21
View File
@@ -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<String, Dynamic> = [];
/**
* Opens the data folder on an Android device using JNI.
*/
public static function openDataFolder():Void
{
final openDataFolderJNI:Null<Dynamic> = createStaticMethod('funkin/util/DataFolderUtil', 'openDataFolder', '()V');
final openDataFolderJNI:Null<Dynamic> = 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<Dynamic>
{
@: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);
}
}
}
+111
View File
@@ -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<String, Dynamic> = [];
@:noCompletion
private static var memberMethodCache:Map<String, Dynamic> = [];
@:noCompletion
private static var staticFieldCache:Map<String, JNIStaticField> = [];
@:noCompletion
private static var memberFieldCache:Map<String, JNIMemberField> = [];
/**
* 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<Dynamic>
{
@: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<Dynamic>
{
@: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<JNIStaticField>
{
@: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<JNIMemberField>
{
@: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
+50
View File
@@ -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<Rectangle>
{
final getCutoutDimensionsJNI:Null<Dynamic> = JNIUtil.createStaticMethod('funkin/util/ScreenUtil', 'getCutoutDimensions', '()[Landroid/graphics/Rect;');
if (getCutoutDimensionsJNI != null)
{
final rectangles:Array<Rectangle> = [];
for (rectangle in cast(getCutoutDimensionsJNI(), Array<Dynamic>))
{
if (rectangle == null) continue;
final topJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'top', 'I');
final leftJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'left', 'I');
final rightJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'right', 'I');
final bottomJNI:Null<JNIMemberField> = 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 [];
}
}
-79
View File
@@ -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<String, Dynamic> = [];
@:noCompletion
static var memberFieldCache:Map<String, JNIMemberField> = [];
public static function getCutoutDimensions():Array<Rectangle>
{
final getCutoutDimensionsJNI:Null<Dynamic> = createStaticMethod('funkin/util/ScreenUtils', 'getCutoutDimensions', '()[Landroid/graphics/Rect;');
if (getCutoutDimensionsJNI != null)
{
final rectangles:Array<Rectangle> = [];
for (rectangle in cast(getCutoutDimensionsJNI(), Array<Dynamic>))
{
if (rectangle == null) continue;
final topJNI:Null<JNIMemberField> = createMemberField('android/graphics/Rect', 'top', 'I');
final leftJNI:Null<JNIMemberField> = createMemberField('android/graphics/Rect', 'left', 'I');
final rightJNI:Null<JNIMemberField> = createMemberField('android/graphics/Rect', 'right', 'I');
final bottomJNI:Null<JNIMemberField> = 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<Dynamic>
{
@: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<JNIMemberField>
{
@: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);
}
}
@@ -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;
}
@@ -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<PackageInfo> 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;
}
}
@@ -9,7 +9,7 @@ import java.util.List;
import org.haxe.extension.Extension;
public class ScreenUtils
public class ScreenUtil
{
public static Rect[] getCutoutDimensions()
{
@@ -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<Float>, bottom:cpp.RawPointer<Float>, left:cpp.RawPointer<Float>, right:cpp.RawPointer<Float>):Void;
+1 -1
View File
@@ -13,7 +13,7 @@
<files id="external-ios" dir="${this_dir}/ios" if="iphoneos || iphonesim">
<compilerflag value="-I${this_dir}/ios/include" />
<file name="src/ScreenUtils.mm" />
<file name="src/ScreenUtil.mm" />
<file name="src/AudioSession.mm" />
</files>
@@ -1,4 +1,4 @@
#import "ScreenUtils.hpp"
#import "ScreenUtil.hpp"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
+6 -7
View File
@@ -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<Array<Float>> = [[], [], [], []];
// 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;
@@ -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
}