aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorArslaan Pathan <[email protected]>2026-08-16 15:04:51 +1200
committerArslaan Pathan <[email protected]>2026-08-16 15:04:51 +1200
commit13abcce7858ab0a5ac787557f57761d37b4a335b (patch)
tree02f3d1d0480b90457baad93985eb9f60562bcf4c /app/src/main
parent9bfe3a31971fea1c8667fc3097ac8aaa6290bcb1 (diff)
downloadmoku-assistant-13abcce7858ab0a5ac787557f57761d37b4a335b.tar.xz
moku-assistant-13abcce7858ab0a5ac787557f57761d37b4a335b.zip
[chore/migrate-gradle] Get basic folder structure and add settings.gradle
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml15
-rw-r--r--app/src/main/jni/Android.mk19
-rw-r--r--app/src/main/jni/Application.mk2
-rw-r--r--app/src/main/jni/main.c218
4 files changed, 254 insertions, 0 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9976775
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.arslaancodes.mokuassistant">
+
+ <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="34"/>
+ <application android:label="moku Assistant">
+ <activity android:name="android.app.NativeActivity" android:exported="true">
+ <meta-data android:name="android.app.lib_name"
+ android:value="moku" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
new file mode 100644
index 0000000..ddaaa2a
--- /dev/null
+++ b/app/src/main/jni/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := vosk
+LOCAL_SRC_FILES := ../vosk/libvosk.so
+include $(PREBUILT_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := moku
+# _eventually_ add lvgl source files to here when i feel like making the UI
+LOCAL_SRC_FILES := main.c
+# LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
+LOCAL_LDLIBS := -llog -landroid
+LOCAL_C_INCLUDES := vosk/include
+LOCAL_SHARED_LIBRARIES := vosk
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+include $(BUILD_SHARED_LIBRARY)
+
+$(call import-module,android/native_app_glue)
diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk
new file mode 100644
index 0000000..67a4e98
--- /dev/null
+++ b/app/src/main/jni/Application.mk
@@ -0,0 +1,2 @@
+APP_ABI := arm64-v8a
+APP_PLATFORM := android-26
diff --git a/app/src/main/jni/main.c b/app/src/main/jni/main.c
new file mode 100644
index 0000000..1c4adfc
--- /dev/null
+++ b/app/src/main/jni/main.c
@@ -0,0 +1,218 @@
+#include <vosk_api.h>
+#include <aaudio/AAudio.h>
+#include <android_native_app_glue.h>
+#include <android/log.h>
+#include <android/sensor.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <android/native_window.h>
+#include <android/set_abort_message.h>
+#include <android/choreographer.h>
+#include <android/hardware_buffer.h>
+#include <time.h>
+
+#define LOG_TAG "moku"
+
+#define _LOG(priority, fmt, ...) \
+ ((void)__android_log_print((priority), (LOG_TAG), \
+ (fmt)__VA_OPT__(, ) __VA_ARGS__))
+
+#define LOGE(fmt, ...) _LOG(ANDROID_LOG_ERROR, (fmt)__VA_OPT__(, ) __VA_ARGS__)
+#define LOGW(fmt, ...) _LOG(ANDROID_LOG_WARN, (fmt)__VA_OPT__(, ) __VA_ARGS__)
+#define LOGI(fmt, ...) _LOG(ANDROID_LOG_INFO, (fmt)__VA_OPT__(, ) __VA_ARGS__)
+
+enum Color {
+ COLOR_RED = 0x000000ff,
+ COLOR_GREEN = 0x0000ff00,
+ COLOR_BLUE = 0x00ff0000
+};
+
+struct engine {
+ struct android_app *app;
+ int window_initialized;
+ int running;
+ uint64_t last_update;
+ int color;
+};
+
+struct engine *engine_new(struct android_app* app) {
+ struct engine *engine;
+
+ engine = malloc(sizeof(struct engine));
+ if (!engine) {
+ LOGE("Failed to allocate engine!");
+ return NULL;
+ }
+
+ engine->window_initialized = 0;
+ engine->app = app;
+ engine->running = 0;
+ engine->color = COLOR_RED;
+ engine->last_update = (uint64_t)0;
+
+ return engine;
+}
+
+uint64_t get_timestamp_ns() {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return (uint64_t)ts.tv_nsec + (uint64_t)ts.tv_sec * 1000000000;
+}
+
+static void engine_schedule_tick(struct engine *engine);
+
+static void engine_draw_frame(struct engine *engine) {
+ ANativeWindow_Buffer buffer;
+ int x, y;
+ size_t pixel_idx;
+
+ if (!engine->app->window) return;
+
+ if (ANativeWindow_lock(engine->app->window, &buffer, NULL) < 0) {
+ LOGE("Unable to lock window buffer");
+ return;
+ }
+
+ if (!engine->window_initialized) {
+ return;
+ }
+
+ for (y = 0; y < buffer.height; y++) {
+ for (x = 0; x < buffer.width; x++) {
+ pixel_idx = y * buffer.stride + x;
+ ((uint32_t*)(buffer.bits))[pixel_idx] = (uint32_t)engine->color;
+ }
+ }
+
+ ANativeWindow_unlockAndPost(engine->app->window);
+}
+
+static void engine_update(struct engine *engine) {
+ /* uint64_t now = get_timestamp_ns();
+ if (now - engine->last_update > 1000000000LL) {
+ switch (engine->color) {
+ case COLOR_RED:
+ engine->color = COLOR_GREEN;
+ break;
+ case COLOR_GREEN:
+ engine->color = COLOR_BLUE;
+ break;
+ case COLOR_BLUE:
+ engine->color = COLOR_RED;
+ break;
+ default:
+ LOGE("unexpected color %08x", (uint32_t)engine->color);
+ }
+ engine->last_update = now;
+ } */
+}
+
+static void engine_real_tick(struct engine *engine) {
+ if (!engine->running) return;
+
+ // LOGI("tick");
+ engine_schedule_tick(engine);
+ engine_update(engine);
+ engine_draw_frame(engine);
+}
+
+static void engine_tick(long frameTimeNanos, void *data) {
+ struct engine *engine;
+
+ if (!data) return;
+ engine = (struct engine*)data;
+
+ engine_real_tick(engine);
+}
+
+static void engine_schedule_tick(struct engine *engine) {
+ AChoreographer_postFrameCallback(AChoreographer_getInstance(), engine_tick, (void*)engine);
+}
+
+/* TODO implement these stubs */
+void engine_attach_window(struct engine *engine) {
+ if (ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM) < 0) {
+ engine->window_initialized = 0;
+ return;
+ }
+ engine->window_initialized = 1;
+ engine->last_update = get_timestamp_ns();
+};
+
+void engine_detach_window(struct engine *engine) {
+ /* Called when native window for app is destroyed.
+ * Doesn't mean app is being killed, also happens on rotate
+ * Normally, with a traditional OpenGL app, do cleanup here
+ * At the moment, it's fine to just set a flag to disable the rendering loop
+ */
+ engine->window_initialized = 0;
+};
+
+void engine_resume(struct engine *engine) {
+ if (!engine->running) {
+ engine->running = 1;
+ engine_schedule_tick(engine);
+ LOGI("engine running");
+ }
+};
+
+
+void engine_pause(struct engine *engine) {
+ engine->running = 0;
+ LOGI("engine paused");
+};
+
+static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
+ struct engine *engine;
+
+ engine = (struct engine *)app->userData;
+
+ switch (cmd) {
+ case APP_CMD_INIT_WINDOW:
+ engine_attach_window(engine);
+ break;
+ case APP_CMD_TERM_WINDOW:
+ engine_detach_window(engine);
+ break;
+ case APP_CMD_GAINED_FOCUS:
+ engine_resume(engine);
+ break;
+ case APP_CMD_LOST_FOCUS:
+ engine_pause(engine);
+ break;
+ }
+}
+
+void android_main(struct android_app *state) {
+ /* Declarations */
+ struct android_poll_source *source;
+ struct engine *engine;
+ int events;
+
+ /* Code starts here */
+ app_dummy();
+
+ engine = engine_new(state);
+ if (!engine) {
+ LOGE("Failed to create engine!");
+ return;
+ }
+
+ state->userData = engine;
+ state->onAppCmd = engine_handle_cmd;
+
+ /* do stuff here */
+
+ while (!state->destroyRequested) {
+ if (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) {
+ if (source) {
+ source->process(state, source);
+ }
+ }
+ /* more stuff here */
+ }
+
+ free(engine);
+}