[工作积累] Android system dialog with native callback

JNI: invoke java dialog with native callback:

store native function address in java, and invoke native another method to this function.

key points:

1.Store callback function pointer(address) in java: to support multiple calls, use data block for each call.

2.Use primitive long(64bit) in Java to store native callback pointer, for 64 bit native compatibility

3.intptr_t for pointer in native.

4.Show dialog  in UI thread (Activity.runOnUiThread )

5.optional: Let the native code to handle localization (minimize Java code)

Java:

 1 public static native void nativeOnSystemDialogResult(long nativeFuncAddr);
 2
 3
 4     class DialogRunnable implements Runnable {
 5         public String mTitle;
 6         public String mMessage;
 7         public String mYes;
 8         public String mNo;
 9         public long mOnYesAddr;
10         public long mOnNoAddr;
11         public boolean mTwoButton;
12
13         //////////////////////////////////////////////////////////////////////////
14         ///title, message, localized Yes No
15         DialogRunnable(String tittle, String message, String locYes, String locNo, long onYesAddr, long onNoAddr, boolean twoButton)
16         {
17             mTitle = tittle;
18             mMessage = message;
19             mYes = locYes;
20             mNo = locNo;
21             mOnYesAddr = onYesAddr;
22             mOnNoAddr = onNoAddr;
23             mTwoButton = twoButton;
24         }
25
26         //////////////////////////////////////////////////////////////////////////
27         public void run() {
28
29             if( mTwoButton ) {
30                 Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )
31                 .setTitle(mTitle)
32                 .setMessage(mMessage)
33                 .setPositiveButton( mYes, new DialogInterface.OnClickListener() {
34                                                     public void onClick(DialogInterface dialog, int whichButton) {
35                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );
36                                                     }
37                                                 })
38                 .setNegativeButton( mNo, new DialogInterface.OnClickListener() {
39                                                     public void onClick(DialogInterface dialog, int whichButton) {
40                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnNoAddr );
41                                                     }
42                                                 })
43                 .setCancelable(false)
44                 .create();
45                 dialog.show();
46             }else {
47                 Dialog dialog = new AlertDialog.Builder( GameActivity.getInstance() )
48                 .setTitle(mTitle)
49                 .setMessage(mMessage)
50                 .setPositiveButton( mNo, new DialogInterface.OnClickListener() {
51                                                     public void onClick(DialogInterface dialog, int whichButton) {
52                                                         GameActivity.getInstance().nativeOnSystemDialogResult( mOnYesAddr );
53                                                     }
54                                                 })
55                 .setCancelable(false)
56                 .create();
57                 dialog.show();
58             }
59         }
60     }
61
62
63     //////////////////////////////////////////////////////////////////////////
64     //Cooperate with native code. DO NOT call on Java
65     //////////////////////////////////////////////////////////////////////////
66     public void showDialogYesNo(String title, String showText, String locYes, String locNo, long onYesAddr, long onNoAddr) {
67         this.runOnUiThread( new DialogRunnable(title, showText, locYes, locNo, onYesAddr, onNoAddr, true) );
68     }
69
70
71
72     

C (for C++, JNI calls are simpler & different)

1 JNIEXPORT void JNICALL Java_com_org_package_GameActivity_nativeOnSystemDialogResult(JNIEnv *env, jobject thiz, jlong functionAddr)
2 {
3     typedef void(*FUNCPTR)(void);
4     FUNCPTR ptr = (FUNCPTR)(void*)function;
5     if( ptr != null )
6         ptr();
7 }
 1 //////////////////////////////////////////////////////////////////////////
 2 //Note: onOK & onCancel can be NULL
 3 void    Android_SystemDialog(const char* title, const char* message, const char* yes, const char* no, void(*onOK)(void), void(*onCancel)(void) )
 4 {
 5     android_app* app = GetApp();
 6     JNIEnv* env = app->activity->env;
 7     //note: we need to attach dalvik VM to current thread, as it is not main thread
 8     JavaVM* vm = app->activity->vm;
 9     if ( (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) < 0 )
10         (*vm)->AttachCurrentThread(vm, &env, NULL);
11
12     jclass ActivityClass = (*env)->GetObjectClass(env, app->activity->clazz);
13     jmethodID java_method = (*env)->GetMethodID(env, ActivityClass,
14         (char8*)"showDialogYesNo",
15         (char8*)"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJ)V");
16     assert( java_method != NULL );
17
18     jstring jTitle = (*env)->NewStringUTF(env, title, strlen(title) );
19     jstring jMsg = (*env)->NewStringUTF(env, message, strlen(message) );
20     jstring jOK = (*env)->NewStringUTF(env, yes, strlen(yes) );
21     jstring jCancel = (*env)->NewStringUTF(env, no, strlen(no) );
22     //Note: jlong is 64 bit
23     jlong jOnOK = (intptr_t)onOK;
24     jlong jOnCancel = (intptr_t)onCancel;
25     //invoke UI Dialog in another thread
26     (*env)->CallVoidMethod(env, app->activity->clazz , java_method, jTitle, jMsg, jOK, jCancel, jOnOK, jOnCancel);
27
28     (*env)->DeleteLocalRef(env, jTitle);
29     (*env)->DeleteLocalRef(env, jMsg);
30     (*env)->DeleteLocalRef(env, jOK);
31     (*env)->DeleteLocalRef(env, jCancel);
32     (*env)->DeleteLocalRef(env, ActivityClass);
33 }

native usage sample:

 1 static void OnExit()
 2 {
 3     exit(0);
 4 }
 5
 6 void Android_Confirm_Exit()
 7 {
 8     const char* title = "Quit";
 9     const char* message = "Unsaved progress will be lost.\nAre you sure you want to quit game?";
10     const char* yes = "Ok";
11     const char* no = "Cancel";
12     Android_SystemDialog(title, message, yes, no, &OnExit, NULL);
13 }
时间: 2024-10-20 07:41:14

[工作积累] Android system dialog with native callback的相关文章

[工作积累] Android dynamic library &amp; JNI_OnLoad

Bionic libc doesn't load dependencies for current .so file (diff from Windows or Linux) so a explicit calling of Java's System.loadLibrary() is needed, in order to load depedency libraries. otherwise the original .so will fail to load. JNI_OnLoad wil

[工作积累] android 中添加libssl和libcurl

1. libssl https://github.com/guardianproject/openssl-android 然后执行ndk-build 2.libcurl 源代码组织结构, 下面的makefile要依赖这个结构. 因为curl依赖openssl, 所以需要先编译openssl: src/openssl-android src/curl-android 下载curl的代码, 并放入src/curl-android/jni 下. 本来想用cygwin来运行configure, 生成an

[工作积累] Android: Hide Navigation bar 隐藏导航条

https://developer.android.com/training/system-ui/navigation.html 1 View decorView = getWindow().getDecorView(); 2 // Hide both the navigation bar and the status bar. 3 // SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as 4

[工作积累] Google/Amazon平台的各种坑

所谓坑, 就是文档中没有标明的特别需要处理的细节, 工作中会被无故的卡住各种令人恼火的问题. 包括系统级的bug和没有文档化的限制. 继Android的各种坑后, 现在做Amazon平台, 遇到的坑很多, 这里记录一下备忘: 先汇总下Android Native下的各种问题, 当然有些限制有明确文档说明,不算坑,但是限制太多还是很不爽: android平台下的某些限制: android下的各种坑 (我的C/C++/汇编/计算机原理博客) OBB的各种bug: OBB的解决方案 arm gcc t

工作积累之NDK编译STL (zhuan)

方法: 1.在jni目录下新建Application.mk; 加入 APP_STL :=  stlport_static  右边的值还可以换成下面几个: system - 使用默认最小的C++运行库,这样生成的应用体积小,内存占用小,但部分功能将无法支持 stlport_static - 使用STLport作为静态库,这项是Android开发网极力推荐的 stlport_shared - STLport 作为动态库,这个可能产生兼容性和部分低版本的Android固件,目前不推荐使用. gnust

[工作记录] Android OpenSL ES: references &amp; AAC related

AAC V.S. MP3 http://en.wikipedia.org/wiki/Advanced_Audio_Coding#AAC.27s_improvements_over_MP3 AAC patent lisense FAQ: http://www.vialicensing.com/licensing/aac-faq.aspx you may need a license but usually no fees, exept that when end user products are

[工作记录] Android OpenGL ES: non-square texture - continue

previous: [工作记录] Android OpenGL ES 2.0: square texture not supported on some device recently I found that it is the mipmap of a non-square texture that cause the black texture problem: http://stackoverflow.com/questions/5052762/using-mipmaps-results-

工作积累(五)——使用[email&#160;protected]注解实现常量功能

之前的博客中提到过如何通过 java.util.ResourceBundle 和 java.util.Properties类通过读取 key-value 文件的形式实现常量功能.其实 spring 已经通过@Value 注解实现,下面看看如何使用. 1.创建.properties文件: 在如下目录创建 keyvalue.properties文件src/main/resources/META-INF/spring/keyvalue.properties ,写入如下内容: test.value=il

Android 封装Dialog

1 package com.example.myandroid01; 2 3 import android.support.v7.app.ActionBarActivity; 4 import android.os.Bundle; 5 import android.view.Menu; 6 import android.view.MenuItem; 7 import android.view.View; 8 import android.widget.Button; 9 import andro