Ver código fonte

wallet: android autosuggest typing module!!

darkfi 1 ano atrás
pai
commit
b4a620986b

+ 1 - 1
bin/darkwallet/Cargo.lock

@@ -2863,7 +2863,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 [[package]]
 name = "miniquad"
 version = "0.4.7"
-source = "git+https://github.com/narodnik/miniquad#fc1fc9bbf11cd14137c5b37ed1a8590383cb20b1"
+source = "git+https://github.com/not-fl3/miniquad#55a94c5499c41a28f966f9693882ca6dc97c0f7d"
 dependencies = [
  "libc",
  "ndk-sys",

+ 2 - 1
bin/darkwallet/Cargo.toml

@@ -13,7 +13,7 @@ repository = "https://codeberg.org/darkrenaissance/darkfi"
 #path = "bin/drawsim.rs"
 
 [dependencies]
-miniquad = { git = "https://github.com/narodnik/miniquad" }
+miniquad = { git = "https://github.com/not-fl3/miniquad" }
 
 # Currently latest version links to freetype-sys 0.19 but we use 0.21
 #harfbuzz-sys = "0.6.1"
@@ -89,3 +89,4 @@ assets = "assets"
 name = "android.permission.INTERNET"
 [[package.metadata.android.permission]]
 name = "android.permission.ACCESS_NETWORK_STATE"
+

+ 1 - 1
bin/darkwallet/Dockerfile

@@ -47,7 +47,7 @@ ENV NDK_HOME /usr/local/android-ndk-r25
 WORKDIR /root/
 RUN git clone https://github.com/not-fl3/cargo-quad-apk cargo-apk
 # For deterministic builds, we want a deterministic toolchain
-RUN cd /root/cargo-apk && git checkout c9c5dfeac69921c888e0fac7963b23068cbc9446
+RUN cd /root/cargo-apk && git checkout 8962f6888e748e201f6ac2ced411669a3f939e07
 
 # ArmV7a
 #ENV CC ${NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang

+ 5 - 0
bin/darkwallet/README.md

@@ -37,3 +37,8 @@ nm libharfbuzz_rs-5d6b743170eb0207.rlib | grep hb_ | less
 cargo tree --target aarch64-linux-android --invert openssl-sys
 ```
 
+## Examine the APK
+
+```
+apktool d target/android-artifacts/release/apk/darkwallet.apk -o dw-apk
+```

+ 21 - 0
bin/darkwallet/java/MainActivity.java

@@ -0,0 +1,21 @@
+//% IMPORTS
+
+import autosuggest.CustomInputConnection;
+
+//% END
+
+//% QUAD_SURFACE_ON_CREATE_INPUT_CONNECTION
+
+// Needed to fix error: unreachable statement in Java
+if (true) {
+    outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
+        | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
+    outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
+        | EditorInfo.IME_ACTION_NONE;
+    // fullEditor is false, but we might set this to true for enabling
+    // text selection, and copy/paste. Lets see.
+    return new CustomInputConnection(this, false);
+}
+
+//% END
+

+ 85 - 0
bin/darkwallet/java/autosuggest/CustomInputConnection.java

@@ -0,0 +1,85 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package autosuggest;
+
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.BaseInputConnection;
+import android.inputmethodservice.InputMethodService;
+
+// setComposingText() - change text being composed
+
+// See 30b299cb04b4ba2330ef61a8a24c1e58513a0af2
+// content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
+
+public class CustomInputConnection extends BaseInputConnection {
+
+    native static void setup();
+    native static void onCommitText(String text);
+    native static void onEndEdit(String text);
+
+    public CustomInputConnection(View view, boolean fullEditor) {
+        super(view, fullEditor);
+        setup();
+    }
+
+    @Override
+    public boolean sendKeyEvent(KeyEvent event) {
+        int action = event.getAction();
+        int keycode = event.getKeyCode();
+        // If this is backspace/del or if the key has a character representation,
+        // need to update the underlying Editable (i.e. the local representation of the text
+        // being edited).  Some IMEs like Jellybean stock IME and Samsung IME mix in delete
+        // KeyPress events instead of calling deleteSurroundingText.
+        if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_DEL) {
+            deleteSurroundingText(1, 0);
+
+            //String text = getTextBeforeCursor(100, 0).toString();
+            //text = text.substring(0, text.length() - 1);
+            //setComposingText(text, 1);
+        } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_FORWARD_DEL) {
+            deleteSurroundingText(0, 1);
+        } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_ENTER) {
+            setComposingText("", 0);
+
+            // Chromium does this but the above seems to work too.
+            //beginBatchEdit();
+            //finishComposingText();
+            //endBatchEdit();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+        //Log.i("darkfi", String.format("commitText(%s, %d)", text.toString(), newCursorPosition));
+        onCommitText(text.toString());
+        return super.commitText(text, newCursorPosition);
+    }
+
+    @Override
+    public boolean endBatchEdit() {
+        //Log.i("darkfi", "endBatchEdit: " + curr);
+        String text = getTextBeforeCursor(100, 0).toString();
+        onEndEdit(text);
+        return super.endBatchEdit();
+    }
+}
+

+ 5 - 0
bin/darkwallet/quad.toml

@@ -0,0 +1,5 @@
+main_activity_inject = "java/MainActivity.java"
+java_files = [
+    "java/autosuggest/CustomInputConnection.java",
+]
+

+ 61 - 0
bin/darkwallet/src/android.rs

@@ -0,0 +1,61 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use miniquad::native::android::{self, ndk_sys, ndk_utils};
+use std::sync::{LazyLock, Mutex as SyncMutex};
+
+struct GlobalData {
+    inp_conn: ndk_sys::jobject,
+}
+
+unsafe impl Send for GlobalData {}
+unsafe impl Sync for GlobalData {}
+
+static GLOBALS: LazyLock<SyncMutex<GlobalData>> =
+    LazyLock::new(|| SyncMutex::new(GlobalData { inp_conn: std::ptr::null_mut() }));
+
+#[no_mangle]
+pub unsafe extern "C" fn Java_autosuggest_CustomInputConnection_setup() {
+    let env = android::attach_jni_env();
+
+    let inp_conn = ndk_utils::new_object!(env, "autosuggest/CustomInputConnection", "()V");
+    assert!(!inp_conn.is_null());
+
+    let inp_conn = ndk_utils::new_global_ref!(env, inp_conn);
+    GLOBALS.lock().unwrap().inp_conn = inp_conn;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Java_autosuggest_CustomInputConnection_onCommitText(
+    env: *mut ndk_sys::JNIEnv,
+    _: ndk_sys::jobject,
+    text: ndk_sys::jobject,
+) {
+    let text = ndk_utils::get_utf_str!(env, text);
+    debug!(target: "android", "onCommitText: {text}");
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Java_autosuggest_CustomInputConnection_onEndEdit(
+    env: *mut ndk_sys::JNIEnv,
+    _: ndk_sys::jobject,
+    text: ndk_sys::jobject,
+) {
+    let text = ndk_utils::get_utf_str!(env, text);
+    debug!(target: "android", "onEditText: {text}");
+}

+ 4 - 12
bin/darkwallet/src/main.rs

@@ -47,6 +47,8 @@ extern crate log;
 #[allow(unused_imports)]
 use log::LevelFilter;
 
+#[cfg(target_os = "android")]
+mod android;
 mod app;
 mod build_info;
 mod darkirc;
@@ -82,18 +84,6 @@ fn panic_hook(panic_info: &std::panic::PanicInfo) {
     std::process::exit(1);
 }
 
-/*
-async fn whomain() {
-    use std::sync::Mutex as SyncMutex;
-    let file_data = Arc::new(SyncMutex::new(None));
-    android_fileopen::find_file(file_data.clone());
-
-    //if let Some(ref file_data) = &*file_data.lock().unwrap() {
-    //    info!("content byte length: {}", file_data.len());
-    //}
-}
-*/
-
 fn main() {
     // Exit the application on panic right away
     std::panic::set_hook(Box::new(panic_hook));
@@ -155,6 +145,7 @@ fn main() {
     });
     async_runtime.push_task(app_task);
 
+    /*
     let app2 = app.clone();
     let sg_root = app.sg_root.clone();
     let ex2 = ex.clone();
@@ -167,6 +158,7 @@ fn main() {
         }
     });
     async_runtime.push_task(darkirc_task);
+    */
 
     /*
     // Nice to see which events exist