aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorArslaan Pathan <[email protected]>2026-08-16 20:33:17 +1200
committerArslaan Pathan <[email protected]>2026-08-16 20:33:17 +1200
commit31a371d3a76f80df501210b1b3ea59b86cfecbf1 (patch)
tree735a81c4a02d1c5bf0514d43d07f1ab3255bc3ce /app/src/main
parent31dd56575a7aad761efcea7bcddd0377743aecfe (diff)
downloadmoku-assistant-31a371d3a76f80df501210b1b3ea59b86cfecbf1.tar.xz
moku-assistant-31a371d3a76f80df501210b1b3ea59b86cfecbf1.zip
[fix] use the activity's classloader to fix JNI and also create notification channel
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/com/arslaancodes/mokuassistant/AssistantService.java32
-rw-r--r--app/src/main/jni/main.c39
2 files changed, 64 insertions, 7 deletions
diff --git a/app/src/main/java/com/arslaancodes/mokuassistant/AssistantService.java b/app/src/main/java/com/arslaancodes/mokuassistant/AssistantService.java
index d30ed2e..7d381be 100644
--- a/app/src/main/java/com/arslaancodes/mokuassistant/AssistantService.java
+++ b/app/src/main/java/com/arslaancodes/mokuassistant/AssistantService.java
@@ -3,6 +3,7 @@ package com.arslaancodes.mokuassistant;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
@@ -14,6 +15,7 @@ import androidx.core.app.NotificationCompat;
public class AssistantService extends Service {
private static final String TAG = "moku";
private static final String CHANNEL_ID = "moku_assistant_channel";
+ private static final String CHANNEL_NAME = "moku Assistant";
private static final int NOTIFICATION_ID = 1001;
@Override
@@ -27,16 +29,14 @@ public class AssistantService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "AssistantService started");
- Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("moku Assistant").setContentText("listening...").setSmallIcon(android.R.drawable.ic_btn_speak_now).setPriority(NotificationCompat.PRIORITY_LOW).build();
-
+ Notification notification = buildNotification();
startForeground(NOTIFICATION_ID, notification);
startAssistant();
-
return START_STICKY;
}
- @Override
+ @Override
public void onDestroy() {
Log.i(TAG, "AssistantService destroyed");
stopAssistant();
@@ -52,10 +52,12 @@ public class AssistantService extends Service {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
- "moku Assistant",
+ CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW
);
channel.setDescription("Shows when moku Assistant is running");
+ channel.setShowBadge(false);
+
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(channel);
@@ -63,7 +65,25 @@ public class AssistantService extends Service {
}
}
- // JNI functions
+ private Notification buildNotification() {
+ Intent notificationIntent = new Intent(this, AssistantService.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ );
+
+ return new NotificationCompat.Builder(this, CHANNEL_ID)
+ .setContentTitle("moku Assistant")
+ .setContentText("listening...")
+ .setSmallIcon(android.R.drawable.ic_btn_speak_now)
+ .setContentIntent(pendingIntent)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setOngoing(true)
+ .build();
+ }
+
private static native void startAssistant();
private static native void stopAssistant();
diff --git a/app/src/main/jni/main.c b/app/src/main/jni/main.c
index 44f4a40..71d0f62 100644
--- a/app/src/main/jni/main.c
+++ b/app/src/main/jni/main.c
@@ -36,6 +36,43 @@ JNIEXPORT void JNICALL Java_com_arslaancodes_mokuassistant_AssistantService_stop
LOGI("stopAssistant called");
}
+void start_assistant_service(struct android_app *app) {
+ JNIEnv *env;
+ JavaVM *jvm = app->activity->vm;
+
+ (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+
+ jclass activity_class = (*env)->GetObjectClass(env, app->activity->clazz);
+
+ jmethodID get_class_loader = (*env)->GetMethodID(env, activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
+ jobject class_loader = (*env)->CallObjectMethod(env, app->activity->clazz, get_class_loader);
+
+ jclass class_loader_cls = (*env)->FindClass(env, "java/lang/ClassLoader");
+ jmethodID load_class = (*env)->GetMethodID(env, class_loader_cls, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ jstring class_name = (*env)->NewStringUTF(env, "com.arslaancodes.mokuassistant.AssistantService");
+ jclass service_class = (jclass)(*env)->CallObjectMethod(env, class_loader, load_class, class_name);
+ (*env)->DeleteLocalRef(env, class_name);
+
+ if (service_class == NULL) {
+ LOGE("Failed to find AssistantService class!");
+ (*jvm)->DetachCurrentThread(jvm);
+ return;
+ }
+
+ jmethodID start_service = (*env)->GetMethodID(env, activity_class, "startService", "(Landroid/content/Intent;)Landroid/content/ComponentName;");
+
+ jclass intent_class = (*env)->FindClass(env, "android/content/Intent");
+ jmethodID intent_constructor = (*env)->GetMethodID(env, intent_class, "<init>", "(Landroid/content/Context;Ljava/lang/Class;)V");
+ jobject intent = (*env)->NewObject(env, intent_class, intent_constructor, app->activity->clazz, service_class);
+
+ (*env)->CallObjectMethod(env, app->activity->clazz, start_service, intent);
+
+ (*jvm)->DetachCurrentThread(jvm);
+
+ LOGI("AssistantService started from C via JNI");
+}
+
enum Color {
COLOR_RED = 0x000000ff,
COLOR_GREEN = 0x0000ff00,
@@ -215,7 +252,7 @@ void android_main(struct android_app *state) {
state->userData = engine;
state->onAppCmd = engine_handle_cmd;
- /* do stuff here */
+ start_assistant_service(state);
while (!state->destroyRequested) {
if (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) {