From 6c46de8cbdf5080bf7b29bfc62b8669320f9d9ae Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 13:30:55 +0800 Subject: [PATCH 1/7] android: remove unused code --- src/android/main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/main.cc b/src/android/main.cc index 35cd492c3..947b0f23f 100644 --- a/src/android/main.cc +++ b/src/android/main.cc @@ -37,7 +37,6 @@ static EGLSurface g_EglSurface = EGL_NO_SURFACE; static EGLContext g_EglContext = EGL_NO_CONTEXT; static struct android_app* g_App = nullptr; static bool g_Initialized = false; -static char g_LogTag[] = "ImGuiExample"; static std::string g_IniFilename = ""; // Forward declarations of helper functions @@ -49,6 +48,7 @@ static int PollUnicodeChars(); static int GetAssetData(const char* filename, void** out_data); static Worker g_worker; + enum StartState { STOPPED = 0, STOPPING, From ce22d4881b5485d4e0719d30b94254d318fedf5c Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 13:35:13 +0800 Subject: [PATCH 2/7] android: make unicodeCharacterQueue final --- android/yass/src/main/java/it/gui/yass/YassActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/yass/src/main/java/it/gui/yass/YassActivity.java b/android/yass/src/main/java/it/gui/yass/YassActivity.java index 905772e7a..4139aa497 100644 --- a/android/yass/src/main/java/it/gui/yass/YassActivity.java +++ b/android/yass/src/main/java/it/gui/yass/YassActivity.java @@ -37,7 +37,7 @@ public void hideSoftInput() { } // Queue for the Unicode characters to be polled from native code (via pollUnicodeChar()) - private LinkedBlockingQueue unicodeCharacterQueue = new LinkedBlockingQueue(); + private final LinkedBlockingQueue unicodeCharacterQueue = new LinkedBlockingQueue(); // We assume dispatchKeyEvent() of the NativeActivity is actually called for every // KeyEvent and not consumed by any View before it reaches here From 1f3adeb3b5260b4e4d76281cd40890d59df473ac Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 13:40:28 +0800 Subject: [PATCH 3/7] android: limit fps --- src/android/main.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/android/main.cc b/src/android/main.cc index 947b0f23f..481a20556 100644 --- a/src/android/main.cc +++ b/src/android/main.cc @@ -108,7 +108,8 @@ static void WorkFunc() { int events; struct android_poll_source* source; - while ((ident=ALooper_pollAll(g_Initialized ? 0 : -1, nullptr, &events, + while ((ident=ALooper_pollAll(g_Initialized ? 67 /* limit to 15 fps */ : -1, + nullptr, &events, (void**)&source)) >= 0) { // Process this event. From 868bf1b3c2711148b8bbfd7288a89ec83abd8041 Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 13:29:42 +0800 Subject: [PATCH 4/7] android: show current ip --- android/yass/src/main/AndroidManifest.xml | 1 + .../main/java/it/gui/yass/YassActivity.java | 6 ++++ src/android/main.cc | 34 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/android/yass/src/main/AndroidManifest.xml b/android/yass/src/main/AndroidManifest.xml index 92ee83a62..522558f95 100644 --- a/android/yass/src/main/AndroidManifest.xml +++ b/android/yass/src/main/AndroidManifest.xml @@ -21,5 +21,6 @@ + diff --git a/android/yass/src/main/java/it/gui/yass/YassActivity.java b/android/yass/src/main/java/it/gui/yass/YassActivity.java index 4139aa497..4708223f1 100644 --- a/android/yass/src/main/java/it/gui/yass/YassActivity.java +++ b/android/yass/src/main/java/it/gui/yass/YassActivity.java @@ -7,10 +7,12 @@ import android.app.NativeActivity; import android.content.Context; +import android.net.wifi.WifiManager; import android.os.Bundle; import android.view.KeyEvent; import android.view.inputmethod.InputMethodManager; +import java.util.Formatter; import java.util.concurrent.LinkedBlockingQueue; @@ -54,4 +56,8 @@ public int pollUnicodeChar() { return poll != null ? poll.intValue() : 0; } + public int getIpAddress() { + WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE); + return wm.getConnectionInfo().getIpAddress(); + } } diff --git a/src/android/main.cc b/src/android/main.cc index 481a20556..f29e1783b 100644 --- a/src/android/main.cc +++ b/src/android/main.cc @@ -46,6 +46,8 @@ static void MainLoopStep(); static int ShowSoftKeyboardInput(); static int PollUnicodeChars(); static int GetAssetData(const char* filename, void** out_data); +// returning in host byte order +static int32_t GetIpAddress(); static Worker g_worker; @@ -309,6 +311,7 @@ CIPHER_METHOD_VALID_MAP(XX) static char local_host[140]; static int local_port; static int timeout; + static std::string ipaddress = asio::ip::make_address_v4(GetIpAddress()).to_string(); static bool _init = [&]() -> bool { strcpy(server_host, absl::GetFlag(FLAGS_server_host).c_str()); server_port = absl::GetFlag(FLAGS_server_port); @@ -333,6 +336,7 @@ CIPHER_METHOD_VALID_MAP(XX) ImGui::InputText("local_host", local_host, IM_ARRAYSIZE(local_host)); ImGui::InputInt("local_port", &local_port); ImGui::InputInt("timeout", &timeout); + ImGui::Text("Current Ip Address: %s", ipaddress.c_str()); ImGui::Checkbox("Option Window", &show_option_window); @@ -507,6 +511,36 @@ static int GetAssetData(const char* filename, void** outData) return num_bytes; } +static int32_t GetIpAddress() +{ + JavaVM* java_vm = g_App->activity->vm; + JNIEnv* java_env = nullptr; + + jint jni_return = java_vm->GetEnv((void**)&java_env, JNI_VERSION_1_6); + if (jni_return == JNI_ERR) + return 0; + + jni_return = java_vm->AttachCurrentThread(&java_env, nullptr); + if (jni_return != JNI_OK) + return 0; + + jclass native_activity_clazz = java_env->GetObjectClass(g_App->activity->clazz); + if (native_activity_clazz == nullptr) + return 0; + + jmethodID method_id = java_env->GetMethodID(native_activity_clazz, "getIpAddress", "()I"); + if (method_id == nullptr) + return 0; + + jint ip_address = java_env->CallIntMethod(g_App->activity->clazz, method_id); + + jni_return = java_vm->DetachCurrentThread(); + if (jni_return != JNI_OK) + return 0; + + return ntohl(ip_address); +} + void android_main(android_app* app) { CHECK(app); app->onAppCmd = handleAppCmd; From 68a64cb246a9d7ba5895c762b2676ee95267dea0 Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 15:02:34 +0800 Subject: [PATCH 5/7] android: add notify native thread --- .../main/java/it/gui/yass/YassActivity.java | 6 +++ src/android/main.cc | 53 +++++++++++++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/android/yass/src/main/java/it/gui/yass/YassActivity.java b/android/yass/src/main/java/it/gui/yass/YassActivity.java index 4708223f1..84ca77fd3 100644 --- a/android/yass/src/main/java/it/gui/yass/YassActivity.java +++ b/android/yass/src/main/java/it/gui/yass/YassActivity.java @@ -12,6 +12,9 @@ import android.view.KeyEvent; import android.view.inputmethod.InputMethodManager; +import java.io.FileDescriptor; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Formatter; import java.util.concurrent.LinkedBlockingQueue; @@ -47,6 +50,7 @@ public void hideSoftInput() { public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { unicodeCharacterQueue.offer(event.getUnicodeChar(event.getMetaState())); + notifyNativeThread(); } return super.dispatchKeyEvent(event); } @@ -60,4 +64,6 @@ public int getIpAddress() { WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE); return wm.getConnectionInfo().getIpAddress(); } + + private native void notifyNativeThread(); } diff --git a/src/android/main.cc b/src/android/main.cc index f29e1783b..97fb00ab9 100644 --- a/src/android/main.cc +++ b/src/android/main.cc @@ -38,6 +38,7 @@ static EGLContext g_EglContext = EGL_NO_CONTEXT; static struct android_app* g_App = nullptr; static bool g_Initialized = false; static std::string g_IniFilename = ""; +static int g_NotifyFd[2] = {-1, -1}; // Forward declarations of helper functions static void Init(struct android_app* app); @@ -49,6 +50,9 @@ static int GetAssetData(const char* filename, void** out_data); // returning in host byte order static int32_t GetIpAddress(); +extern "C" +JNIEXPORT void JNICALL Java_it_gui_yass_YassActivity_notifyNativeThread(JNIEnv *env, jobject obj); + static Worker g_worker; enum StartState { @@ -156,15 +160,40 @@ static int32_t handleInputEvent(struct android_app* app, AInputEvent* inputEvent return ImGui_ImplAndroid_HandleInputEvent(inputEvent); } +/* Invoked by ALooper to process a message */ +static int messagepipe_cb(int fd, int events, void* user) { + while (true) { + char msg; + ssize_t ret = read(fd, &msg, sizeof(msg)); + if (ret < 0 && errno == EINTR) + continue; + if (ret < 0) { + break; + } + } + + return 1; +} + void Init(struct android_app* app) { if (g_Initialized) return; - LOG(INFO) << "imgui: Initialize"; + g_App = app; + DCHECK_EQ(g_App, a_app); + config::ReadConfigFileOption(0, nullptr); config::ReadConfig(); - g_App = app; - DCHECK_EQ(g_App, a_app); + /* Call this from your main thread to set up the callback pipe. */ + int ret = pipe2(g_NotifyFd, O_NONBLOCK | O_CLOEXEC); + CHECK_NE(ret, -1); + + /* Register the file descriptor to listen on. */ + ALooper_addFd(g_App->looper, g_NotifyFd[0], LOOPER_ID_USER, + ALOOPER_EVENT_INPUT, messagepipe_cb, nullptr); + + LOG(INFO) << "imgui: Initialize"; + ANativeWindow_acquire(g_App->window); // Initialize EGL @@ -421,6 +450,14 @@ void Shutdown() g_EglSurface = EGL_NO_SURFACE; ANativeWindow_release(g_App->window); + /* UnRegister the file descriptor to listen on. */ + ALooper_removeFd(g_App->looper, g_NotifyFd[0]); + + close(g_NotifyFd[0]); + close(g_NotifyFd[1]); + g_NotifyFd[0] = -1; + g_NotifyFd[1] = -1; + g_Initialized = false; } @@ -541,6 +578,16 @@ static int32_t GetIpAddress() return ntohl(ip_address); } +JNIEXPORT void JNICALL Java_it_gui_yass_YassActivity_notifyNativeThread(JNIEnv *env, jobject obj) { + while (g_Initialized) { + char byte; + ssize_t ret = write(g_NotifyFd[1], &byte, sizeof(byte)); + if (ret < 0 && (errno == EINTR || errno == EAGAIN)) + continue; + break; + } +} + void android_main(android_app* app) { CHECK(app); app->onAppCmd = handleAppCmd; From 70d7de0fd6fe4f0e5addd05823e836da982f028d Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 15:44:45 +0800 Subject: [PATCH 6/7] gh actions: add publish apk action --- .github/workflows/releases-android-binary.yml | 9 +++- tools/build.go | 42 ++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/.github/workflows/releases-android-binary.yml b/.github/workflows/releases-android-binary.yml index 36413e699..b0bcd626b 100644 --- a/.github/workflows/releases-android-binary.yml +++ b/.github/workflows/releases-android-binary.yml @@ -83,6 +83,11 @@ jobs: key: ${{ runner.os }}-go-docker-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-docker- + - name: Gradle cache + uses: actions/cache@v3 + with: + path: ~/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('android/**/*.gradle') }} - name: Cache sdk root id: ndk-cache uses: actions/cache@v3 @@ -134,7 +139,7 @@ jobs: echo "CXX=${{ github.workspace }}/third_party/llvm-build/Release+Asserts/bin/clang++" >> $GITHUB_ENV - name: Build TGZ packages run: | - ./tools/build --variant gui --arch ${{ matrix.arch }} --system android -build-benchmark -build-test -nc + ./tools/build --variant gui --arch ${{ matrix.arch }} --system android --cmake-build-type MinSizeRel -build-benchmark -build-test -android-sdk-dir "${ANDROID_HOME}" - name: "Install dependency: android sysroot (test purpose)" if: ${{ steps.sysroot-cache.outputs.cache-hit != 'true' }} run: | @@ -163,4 +168,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release upload ${{ github.event.release.tag_name }} yass*.tgz + gh release upload ${{ github.event.release.tag_name }} yass*.tgz yass*.apk diff --git a/tools/build.go b/tools/build.go index 43cb90378..4663ebeec 100644 --- a/tools/build.go +++ b/tools/build.go @@ -58,6 +58,8 @@ var msvcAllowXpFlag bool var freebsdAbiFlag int +var androidSdkDir string + var systemNameFlag string var subSystemNameFlag string var sysrootFlag string @@ -144,6 +146,7 @@ func InitFlag() { flag.BoolVar(&msvcAllowXpFlag, "msvc-allow-xp", getEnvBool("MSVC_ALLOW_XP", false), "Enable Windows XP Build") flag.IntVar(&freebsdAbiFlag, "freebsd-abi", getFreebsdABI(11), "Select FreeBSD ABI") + flag.StringVar(&androidSdkDir, "android-sdk-dir", "", "Android SDK Home Path") flag.StringVar(&systemNameFlag, "system", runtime.GOOS, "Specify host system name") flag.StringVar(&subSystemNameFlag, "subsystem", "", "Specify host subsystem name") @@ -1124,7 +1127,7 @@ func archiveMainFile(output string, prefix string, paths []string) { // Use this command line to update .DS_Store // hdiutil convert -format UDRW -o yass.dmg yass-macos-release-universal-*.dmg // hdiutil resize -size 1G yass.dmg - cmdCheckOutput([]string{"../scripts/pkg-dmg", + cmdRun([]string{"../scripts/pkg-dmg", "--source", paths[0], "--target", output, "--sourcefile", @@ -1133,7 +1136,39 @@ func archiveMainFile(output string, prefix string, paths []string) { "--icon", "../src/mac/yass.icns", "--copy", "../macos/.DS_Store:/.DS_Store", "--copy", "../macos/.background:/", - "--symlink", "/Applications:/Applications"}) + "--symlink", "/Applications:/Applications"}, true) + } else if systemNameFlag == "android" && variantFlag == "gui" { + androidDir := "../android" + err := os.Chdir(androidDir) + if err != nil { + glog.Fatalf("%v", err) + } + if (androidSdkDir != "") { + glog.Infof("android sdk dir to %s", androidSdkDir) + localProperties := fmt.Sprintf("sdk.dir=%s\n", androidSdkDir) + err = ioutil.WriteFile("local.properties", []byte(localProperties), 0666) + if err != nil { + glog.Fatalf("%v", err) + } + } + _, abi := getAndroidTargetAndAppAbi(archFlag) + if cmakeBuildTypeFlag == "Release" || cmakeBuildTypeFlag == "MinSizeRel" { + cmdRun([]string{"./gradlew", "yass:assembleRelease"}, true) + err = os.Rename(fmt.Sprintf("./yass/build/outputs/apk/release/yass-%s-release-unsigned.apk", abi), output) + if err != nil { + glog.Fatalf("%v", err) + } + } else { + cmdRun([]string{"./gradlew", "yass:assembleDebug"}, true) + err = os.Rename(fmt.Sprintf("./yass/build/outputs/apk/debug/yass-%s-release-unsigned.apk", abi), output) + if err != nil { + glog.Fatalf("%v", err) + } + } + err = os.Chdir(buildDir) + if err != nil { + glog.Fatalf("%v", err) + } } else { archiveFiles(output, prefix, paths) } @@ -1261,6 +1296,9 @@ func postStateArchives() map[string][]string { archivePrefix := fmt.Sprintf(archiveFormat, strings.Replace(APPNAME, "_", "-", 1), "", "") archiveSuffix := fmt.Sprintf(archiveFormat, "", "", "") archiveSuffix = archiveSuffix[1:] + if systemNameFlag == "android" && variantFlag == "gui" { + archive = fmt.Sprintf(archiveFormat, APPNAME, archFlag, ".apk") + } if systemNameFlag == "darwin" { archive = fmt.Sprintf(archiveFormat, APPNAME, "", ".dmg") } From 09b762a0eee1309c62f9598c4d6a5441eab89a22 Mon Sep 17 00:00:00 2001 From: Keeyou Date: Thu, 7 Dec 2023 16:07:52 +0800 Subject: [PATCH 7/7] Revert "android: update gradle plugins to 8.2.0" This reverts commit 124de25a8bee4d8534b0f91e14a5f20d1eef477f. --- android/build.gradle | 2 +- android/gradle.properties | 3 --- android/gradle/wrapper/gradle-wrapper.properties | 2 +- android/yass/build.gradle | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a9a24a5fa..b11499b00 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -12,7 +12,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.0' + classpath 'com.android.tools.build:gradle:7.4.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/android/gradle.properties b/android/gradle.properties index 2b474b577..d1e13c170 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -11,7 +11,4 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sun May 28 17:34:07 CST 2023 -android.defaults.buildfeatures.buildconfig=true -android.nonFinalResIds=false -android.nonTransitiveRClass=false org.gradle.jvmargs=-Xmx4096M diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index af36f6ed4..d5477567b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sat Jul 15 09:20:22 BST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/android/yass/build.gradle b/android/yass/build.gradle index d284ab971..f3730d4c7 100644 --- a/android/yass/build.gradle +++ b/android/yass/build.gradle @@ -1,8 +1,6 @@ apply plugin: 'com.android.application' android { - // https://developer.android.com/build/configure-app-module#set-namespace - namespace = "it.gui.yass" compileSdkVersion rootProject.ext.compileSdkVersion defaultConfig { applicationId 'it.gui.yass'