From 26d58fd25e7ec66d56ff20160ab5f9cc63b854f3 Mon Sep 17 00:00:00 2001 From: inkeliz Date: Sun, 1 Jun 2025 16:51:44 +0100 Subject: [PATCH] [DRAFT] explorer: [android] open directory --- explorer/dir_android.go | 122 +++++++++++++++++++++++++++++++++ explorer/dir_android.jar | Bin 0 -> 2233 bytes explorer/dir_android.java | 72 +++++++++++++++++++ explorer/explorer.go | 13 ++++ explorer/explorer_android.go | 47 +++++++++++-- explorer/explorer_android.jar | Bin 7120 -> 8276 bytes explorer/explorer_android.java | 50 ++++++++++++++ go.mod | 8 +-- go.sum | 4 ++ 9 files changed, 306 insertions(+), 10 deletions(-) create mode 100644 explorer/dir_android.go create mode 100644 explorer/dir_android.jar create mode 100644 explorer/dir_android.java diff --git a/explorer/dir_android.go b/explorer/dir_android.go new file mode 100644 index 0000000..da5b62f --- /dev/null +++ b/explorer/dir_android.go @@ -0,0 +1,122 @@ +package explorer + +import ( + "gioui.org/app" + "git.wow.st/gmp/jni" + "os" +) + +//go:generate javac -source 8 -target 8 -bootclasspath $ANDROID_HOME/platforms/android-30/android.jar -d $TEMP/explorer_file_android/classes dir_android.java +//go:generate jar cf dir_android.jar -C $TEMP/explorer_file_android/classes . + +type Directory struct { + createFile jni.MethodID + libClass jni.Class + libObject jni.Object + + url jni.Object + openFile jni.MethodID +} + +func newDirectory(env jni.Env, url jni.Object) (*Directory, error) { + f := &Directory{url: url} + + class, err := jni.LoadClass(env, jni.ClassLoaderFor(env, jni.Object(app.AppContext())), "org/gioui/x/explorer/dir_android") + if err != nil { + return nil, err + } + + obj, err := jni.NewObject(env, class, jni.GetMethodID(env, class, "", `()V`)) + if err != nil { + return nil, err + } + + // For some reason, using `f.stream` as argument for a constructor (`public file_android(Object j) {}`) doesn't work. + if err := jni.CallVoidMethod(env, obj, jni.GetMethodID(env, class, "setHandle", `(Ljava/lang/Object;)V`), jni.Value(f.url)); err != nil { + return nil, err + } + + f.libObject = jni.NewGlobalRef(env, obj) + f.libClass = jni.Class(jni.NewGlobalRef(env, jni.Object(class))) + f.openFile = jni.GetMethodID(env, f.libClass, "readFile", "(Landroid/view/View;Ljava/lang/String;)Ljava/lang/Object;") + f.createFile = jni.GetMethodID(env, f.libClass, "writeFile", "(Landroid/view/View;Ljava/lang/String;)Ljava/lang/Object;") + + return f, nil + +} + +func (d *Directory) ReadFile(name string) (file *File, err error) { + if d == nil || d.libObject == 0 { + return nil, os.ErrClosed + } + + err = jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error { + nameJava := jni.JavaString(env, name) + stream, err := jni.CallObjectMethod(env, d.libObject, d.openFile, jni.Value(_View), jni.Value(nameJava)) + if err != nil { + return err + } + if stream == 0 { + return os.ErrNotExist + } + + file, err = newFile(env, stream) + return nil + }) + if err != nil { + return nil, err + } + + return file, nil +} + +/* +func (d *Directory) OpenDirectory(name string) (Directory, error) { + // Implementation for opening a subdirectory in the directory + return nil, nil +} + +*/ + +func (d *Directory) WriteFile(name string) (file *File, err error) { + if d == nil || d.libObject == 0 { + return nil, os.ErrClosed + } + + err = jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error { + nameJava := jni.JavaString(env, name) + stream, err := jni.CallObjectMethod(env, d.libObject, d.createFile, jni.Value(_View), jni.Value(nameJava)) + if err != nil { + return err + } + if stream == 0 { + return os.ErrExist + } + + file, err = newFile(env, stream) + return nil + }) + if err != nil { + return nil, err + } + + return file, nil +} + +/* +func (d *Directory) CreateDirectory(name string) (Directory, error) { + // Implementation for creating a subdirectory in the directory + return nil, nil +} + +func (d *Directory) ListFiles() ([]File, error) { + // Implementation for listing files in the directory + return nil, nil +} + +func (d *Directory) ListDirectories() ([]Directory, error) { + // Implementation for listing subdirectories in the directory + return nil, nil +} + +*/ diff --git a/explorer/dir_android.jar b/explorer/dir_android.jar new file mode 100644 index 0000000000000000000000000000000000000000..3f343afc9f7deb1551d23a9237bd39ccd68c0263 GIT binary patch literal 2233 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 O%a74zZ)-|^b@YD|O$*`x diff --git a/explorer/explorer_android.java b/explorer/explorer_android.java index 7c520a2..93fa763 100644 --- a/explorer/explorer_android.java +++ b/explorer/explorer_android.java @@ -10,6 +10,8 @@ import android.os.Handler.Callback; import android.os.Handler; import android.net.Uri; +import android.os.Build; +import android.provider.DocumentsContract; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; @@ -30,10 +32,12 @@ public class explorer_android { // List of requestCode used in the callback, to identify the caller. static List import_codes = new ArrayList(); static List export_codes = new ArrayList(); + static List directory_codes = new ArrayList(); // Functions defined on Golang. static public native void ImportCallback(InputStream f, int id, String err); static public native void ExportCallback(OutputStream f, int id, String err); + static public native void DirectoryCallback(Uri path, int id, String err); public static class explorer_android_fragment extends Fragment { Context context; @@ -81,6 +85,29 @@ public void run() { return; } } + + if (directory_codes.contains(Integer.valueOf(requestCode))) { + directory_codes.remove(Integer.valueOf(requestCode)); + if (resultCode != Activity.RESULT_OK) { + explorer_android.DirectoryCallback(null, requestCode, ""); + activity.getFragmentManager().popBackStack(); + return; + } + try { + Uri treeUri = data.getData(); + + int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + activity.getContentResolver().takePersistableUriPermission(treeUri, takeFlags); + + + Uri folderUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, DocumentsContract.getTreeDocumentId(treeUri)); + + explorer_android.DirectoryCallback(folderUri, requestCode, ""); + + } catch (Exception e) { + explorer_android.DirectoryCallback(null, requestCode, e.toString()); + } + } } }); @@ -126,6 +153,29 @@ public void run() { }); } + public void openDirectory(View view, int id) { + askPermission(view); + + ((Activity) view.getContext()).runOnUiThread(new Runnable() { + public void run() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + Log.e("explorer_android", "openDirectory requires Android Lollipop or higher."); + explorer_android.DirectoryCallback(null, id, "Android version too low"); + return; + } + + registerFrag(view); + directory_codes.add(Integer.valueOf(id)); + + final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); + + frag.startActivityForResult(Intent.createChooser(intent, ""), id); + } + }); + } + public void registerFrag(View view) { final Context ctx = view.getContext(); final FragmentManager fm; diff --git a/go.mod b/go.mod index 030eccc..6f46d86 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module gioui.org/x go 1.21 require ( - gioui.org v0.8.0 + gioui.org v0.8.1-0.20250424183133-e18db649912a git.sr.ht/~jackmordaunt/go-toast v1.0.0 git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 github.com/andybalholm/stroke v0.0.0-20221221101821-bd29b49d73f0 @@ -12,13 +12,13 @@ require ( github.com/yuin/goldmark v1.4.13 golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 - golang.org/x/image v0.18.0 + golang.org/x/image v0.23.0 golang.org/x/sys v0.22.0 - golang.org/x/text v0.16.0 + golang.org/x/text v0.21.0 ) require ( gioui.org/shader v1.0.8 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-text/typesetting v0.2.1 // indirect + github.com/go-text/typesetting v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index b78f9e9..3a4cba6 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKw eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA= gioui.org v0.8.0 h1:QV5p5JvsmSmGiIXVYOKn6d9YDliTfjtLlVf5J+BZ9Pg= gioui.org v0.8.0/go.mod h1:vEMmpxMOd/iwJhXvGVIzWEbxMWhnMQ9aByOGQdlQ8rc= +gioui.org v0.8.1-0.20250424183133-e18db649912a/go.mod h1:JnoLsqpYezue9ZRMG7E2hOXar1/oAE9ZFkiFfF4oULs= gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA= gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= @@ -17,6 +18,7 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8= github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= +github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -30,8 +32,10 @@ golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmG golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= +golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=