diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index 41a4730..ace2185 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -96,6 +96,23 @@ static jobject jnistr_from_ascii(JNIEnv *env, const char *str) return r; } +static jobject get_kotlin_global_object(JNIEnv *env, const char *id) +{ + size_t idlen = strlen(id); + char *sig = malloc(idlen + 3); + if(!sig) + return NULL; + sig[0] = 'L'; + memcpy(sig + 1, id, idlen); + sig[1 + idlen] = ';'; + sig[1 + idlen + 1] = '\0'; + jclass cls = E->FindClass(env, id); + jfieldID field_id = E->GetStaticFieldID(env, cls, "INSTANCE", sig); + jobject r = E->GetStaticObjectField(env, cls, field_id); + free(sig); + return r; +} + static ChiakiLog global_log; static JavaVM *global_vm; @@ -609,13 +626,52 @@ JNIEXPORT void JNICALL JNI_FCN(discoveryServiceFree)(JNIEnv *env, jobject obj, j typedef struct android_chiaki_regist_t { AndroidChiakiLog log; - jobject java_regist; ChiakiRegist regist; + + jobject java_regist; + jmethodID java_regist_event_meth; + + jobject java_regist_event_canceled; + jobject java_regist_event_failed; + jclass java_regist_event_success_class; + jmethodID java_regist_event_success_ctor; } AndroidChiakiRegist; static void android_chiaki_regist_cb(ChiakiRegistEvent *event, void *user) { - // TODO + AndroidChiakiRegist *regist = user; + + JNIEnv *env = attach_thread_jni(); + if(!env) + return; + + jobject java_event = NULL; + switch(event->type) + { + case CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED: + java_event = regist->java_regist_event_canceled; + break; + case CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED: + java_event = regist->java_regist_event_failed; + break; + case CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS: + java_event = E->NewObject(env, regist->java_regist_event_success_class, regist->java_regist_event_success_ctor, NULL /* TODO: RegistHost */); + break; + } + + if(java_event) + E->CallVoidMethod(env, regist->java_regist, regist->java_regist_event_meth, java_event); + + (*global_vm)->DetachCurrentThread(global_vm); +} + +static void android_chiaki_regist_fini_partial(JNIEnv *env, AndroidChiakiRegist *regist) +{ + android_chiaki_log_fini(®ist->log, env); + E->DeleteGlobalRef(env, regist->java_regist); + E->DeleteGlobalRef(env, regist->java_regist_event_canceled); + E->DeleteGlobalRef(env, regist->java_regist_event_failed); + E->DeleteGlobalRef(env, regist->java_regist_event_success_class); } JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject result, jobject regist_info_obj, jobject log_obj, jobject java_regist) @@ -632,6 +688,12 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re android_chiaki_log_init(®ist->log, env, log_obj); regist->java_regist = E->NewGlobalRef(env, java_regist); + regist->java_regist_event_meth = E->GetMethodID(env, E->GetObjectClass(env, regist->java_regist), "event", "(L"BASE_PACKAGE"/RegistEvent;)V"); + + regist->java_regist_event_canceled = E->NewGlobalRef(env, get_kotlin_global_object(env, BASE_PACKAGE"/RegistEventCanceled")); + regist->java_regist_event_failed = E->NewGlobalRef(env, get_kotlin_global_object(env, BASE_PACKAGE"/RegistEventFailed")); + regist->java_regist_event_success_class = E->NewGlobalRef(env, E->FindClass(env, BASE_PACKAGE"/RegistEventSuccess")); + regist->java_regist_event_success_ctor = E->GetMethodID(env, regist->java_regist_event_success_class, "", "(L"BASE_PACKAGE"/RegistHost;)V"); jclass regist_info_class = E->GetObjectClass(env, regist_info_obj); jstring host_string = E->GetObjectField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "host", "Ljava/lang/String;")); @@ -652,8 +714,7 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re if(err != CHIAKI_ERR_SUCCESS) { - android_chiaki_log_fini(®ist->log, env); - E->DeleteGlobalRef(env, regist->java_regist); + android_chiaki_regist_fini_partial(env, regist); free(regist); regist = NULL; } @@ -673,7 +734,6 @@ JNIEXPORT void JNICALL JNI_FCN(registFree)(JNIEnv *env, jobject obj, jlong ptr) { AndroidChiakiRegist *regist = (AndroidChiakiRegist *)ptr; chiaki_regist_fini(®ist->regist); - android_chiaki_log_fini(®ist->log, env); - E->DeleteGlobalRef(env, regist->java_regist); + android_chiaki_regist_fini_partial(env, regist); free(regist); } diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index 5579fbc..7802e3d 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -89,6 +89,12 @@ class ChiakiLog(val levelMask: Int, val callback: (level: Int, text: String) -> { callback(level, text) } + + fun d(text: String) = log(Level.DEBUG.value, text) + fun v(text: String) = log(Level.VERBOSE.value, text) + fun i(text: String) = log(Level.INFO.value, text) + fun w(text: String) = log(Level.WARNING.value, text) + fun e(text: String) = log(Level.ERROR.value, text) } private fun maxAbs(a: Short, b: Short) = if(abs(a.toInt()) > abs(b.toInt())) a else b diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt index b03ca3e..437cfee 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteActivity.kt @@ -17,9 +17,10 @@ package com.metallic.chiaki.regist +import android.content.Intent import android.os.Bundle import android.text.method.ScrollingMovementMethod -import android.util.Log +import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders @@ -55,6 +56,33 @@ class RegistExecuteActivity: AppCompatActivity() logTextView.scrollTo(0, max(scrollY, 0)) }) + viewModel.state.observe(this, Observer { + progressBar.visibility = if(it == RegistExecuteViewModel.State.RUNNING) View.VISIBLE else View.GONE + when(it) + { + RegistExecuteViewModel.State.FAILED -> + { + infoTextView.visibility = View.VISIBLE + infoTextView.setText(R.string.regist_info_failed) + } + RegistExecuteViewModel.State.SUCCESSFUL -> + { + infoTextView.visibility = View.VISIBLE + infoTextView.setText(R.string.regist_info_success) + } + else -> infoTextView.visibility = View.GONE + } + }) + + shareLogButton.setOnClickListener { + val log = viewModel.logText.value ?: "" + Intent(Intent.ACTION_SEND).also { + it.type = "text/plain" + it.putExtra(Intent.EXTRA_TEXT, log) + startActivity(Intent.createChooser(it, resources.getString(R.string.action_share_log))) + } + } + val registInfo = RegistInfo( intent.getStringExtra(EXTRA_HOST) ?: return, intent.getBooleanExtra(EXTRA_BROADCAST, false), diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteViewModel.kt index 2a049af..8136ace 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistExecuteViewModel.kt @@ -53,7 +53,7 @@ class RegistExecuteViewModel: ViewModel() } catch(error: CreateError) { - // TODO: log about error + log.log.e("Failed to create Regist: ${error.errorCode}") _state.value = State.FAILED } } diff --git a/android/app/src/main/res/layout/activity_regist.xml b/android/app/src/main/res/layout/activity_regist.xml index c0eeaa6..aa47b88 100644 --- a/android/app/src/main/res/layout/activity_regist.xml +++ b/android/app/src/main/res/layout/activity_regist.xml @@ -74,7 +74,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textNoSuggestions|textVisiblePassword" - android:maxLines="1"/> + android:maxLines="1" + android:text="test"/> + android:maxLength="8" + android:text="01234567"/> + android:padding="8dp" + tools:context=".regist.RegistExecuteActivity"> Please enter a valid PSN ID Please enter a valid %d-digit PIN Share Log + Regist successful. + Regist failed.