comparison android/dw.cpp @ 2522:66c490aa719d

Android: Implement notifications, images on notifications incomplete. Also detect the Android application ID, and generate one if not set or detected. Also store the path as the application directory.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sun, 09 May 2021 19:27:23 +0000
parents 5f92284e2b08
children 82cdb3ad7c25
comparison
equal deleted inserted replaced
2521:5f92284e2b08 2522:66c490aa719d
34 extern "C" { 34 extern "C" {
35 #endif 35 #endif
36 36
37 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows" 37 #define DW_CLASS_NAME "org/dbsoft/dwindows/DWindows"
38 38
39 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0};
40 static char _dw_app_name[_DW_APP_ID_SIZE+1]= {0};
41 static char _dw_exec_dir[MAX_PATH+1] = {0};
42
39 static pthread_key_t _dw_env_key; 43 static pthread_key_t _dw_env_key;
40 static HEV _dw_main_event; 44 static HEV _dw_main_event;
41 static JavaVM *_dw_jvm; 45 static JavaVM *_dw_jvm;
42 static jobject _dw_obj; 46 static jobject _dw_obj;
43 static jobject _dw_class_loader; 47 static jobject _dw_class_loader;
108 * to be called and return. 112 * to be called and return.
109 * Parameters: 113 * Parameters:
110 * path: The path to the Android app. 114 * path: The path to the Android app.
111 */ 115 */
112 JNIEXPORT void JNICALL 116 JNIEXPORT void JNICALL
113 Java_org_dbsoft_dwindows_DWindows_dwindowsInit(JNIEnv* env, jobject obj, jstring path) 117 Java_org_dbsoft_dwindows_DWindows_dwindowsInit(JNIEnv* env, jobject obj, jstring path, jstring appID)
114 { 118 {
115 char *arg = strdup(env->GetStringUTFChars((jstring) path, NULL)); 119 char *arg = strdup(env->GetStringUTFChars((jstring)path, NULL));
120 const char *appid = env->GetStringUTFChars((jstring)appID, NULL);
116 121
117 if(!_dw_main_event) 122 if(!_dw_main_event)
118 { 123 {
119 /* Save our class object pointer for later */ 124 /* Save our class object pointer for later */
120 _dw_obj = env->NewGlobalRef(obj); 125 _dw_obj = env->NewGlobalRef(obj);
123 pthread_key_create(&_dw_env_key, NULL); 128 pthread_key_create(&_dw_env_key, NULL);
124 pthread_setspecific(_dw_env_key, env); 129 pthread_setspecific(_dw_env_key, env);
125 130
126 /* Create the dwmain event */ 131 /* Create the dwmain event */
127 _dw_main_event = dw_event_new(); 132 _dw_main_event = dw_event_new();
133 }
134
135 if(arg)
136 {
137 /* Store the passed in path for dw_app_dir() */
138 strncpy(_dw_exec_dir, arg, MAX_PATH);
139 }
140 if(appid)
141 {
142 /* Store our reported Android AppID */
143 strncpy(_dw_app_id, appid, _DW_APP_ID_SIZE);
128 } 144 }
129 145
130 /* Launch the new thread to execute dwmain() */ 146 /* Launch the new thread to execute dwmain() */
131 dw_thread_new((void *) _dw_main_launch, arg, 0); 147 dw_thread_new((void *) _dw_main_launch, arg, 0);
132 } 148 }
626 * Returns a pointer to a static buffer which contains the 642 * Returns a pointer to a static buffer which contains the
627 * private application data directory. 643 * private application data directory.
628 */ 644 */
629 char * API dw_app_dir(void) 645 char * API dw_app_dir(void)
630 { 646 {
631 static char _dw_exec_dir[MAX_PATH+1] = {0}; 647 /* The path is passed in via JNI dwindowsInit() */
632 /* Code to determine the execution directory here,
633 * some implementations make this variable global
634 * and determine the location in dw_init().
635 */
636 return _dw_exec_dir; 648 return _dw_exec_dir;
637 } 649 }
638 650
639 /* 651 /*
640 * Sets the application ID used by this Dynamic Windows application instance. 652 * Sets the application ID used by this Dynamic Windows application instance.
647 * DW_ERROR_GENERAL if the application ID is not allowed. 659 * DW_ERROR_GENERAL if the application ID is not allowed.
648 * Remarks: 660 * Remarks:
649 * This must be called before dw_init(). If dw_init() is called first 661 * This must be called before dw_init(). If dw_init() is called first
650 * it will create a unique ID in the form: org.dbsoft.dwindows.application 662 * it will create a unique ID in the form: org.dbsoft.dwindows.application
651 * or if the application name cannot be detected: org.dbsoft.dwindows.pid.# 663 * or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
652 * The appname is only required on Windows. If NULL is passed the detected 664 * The appname is used on Windows and Android. If NULL is passed the
653 * application name will be used, but a prettier name may be desired. 665 * detected name will be used, but a prettier name may be desired.
654 */ 666 */
655 int API dw_app_id_set(const char *appid, const char *appname) 667 int API dw_app_id_set(const char *appid, const char *appname)
656 { 668 {
657 return DW_ERROR_UNKNOWN; 669 if(appid)
670 strncpy(_dw_app_id, appid, _DW_APP_ID_SIZE);
671 if(appname)
672 strncpy(_dw_app_name, appname, _DW_APP_ID_SIZE);
673 return DW_ERROR_NONE;
658 } 674 }
659 675
660 /* 676 /*
661 * Displays a debug message on the console... 677 * Displays a debug message on the console...
662 * Parameters: 678 * Parameters:
4235 * Parameters: 4251 * Parameters:
4236 * env: Pointer to a DWEnv struct. 4252 * env: Pointer to a DWEnv struct.
4237 */ 4253 */
4238 void API dw_environment_query(DWEnv *env) 4254 void API dw_environment_query(DWEnv *env)
4239 { 4255 {
4240 strcpy(env->osName, "Unknown"); 4256 strcpy(env->osName, "Android");
4241 4257
4242 strcpy(env->buildDate, __DATE__); 4258 strcpy(env->buildDate, __DATE__);
4243 strcpy(env->buildTime, __TIME__); 4259 strcpy(env->buildTime, __TIME__);
4244 env->DWMajorVersion = DW_MAJOR_VERSION; 4260 env->DWMajorVersion = DW_MAJOR_VERSION;
4245 env->DWMinorVersion = DW_MINOR_VERSION; 4261 env->DWMinorVersion = DW_MINOR_VERSION;
5378 * Returns: 5394 * Returns:
5379 * DW_ERROR_NONE (0) on success. 5395 * DW_ERROR_NONE (0) on success.
5380 */ 5396 */
5381 int API dw_init(int newthread, int argc, char *argv[]) 5397 int API dw_init(int newthread, int argc, char *argv[])
5382 { 5398 {
5399 JNIEnv *env;
5400
5401 if(!_dw_app_id[0])
5402 {
5403 /* Generate an Application ID based on the PID if all else fails. */
5404 snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.pid.%d", DW_APP_DOMAIN_DEFAULT, getpid());
5405 }
5406
5407 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
5408 {
5409 // Construct a String
5410 jstring appid = env->NewStringUTF(_dw_app_id);
5411 jstring appname = env->NewStringUTF(_dw_app_name);
5412 // First get the class that contains the method you need to call
5413 jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
5414 // Get the method that you want to call
5415 jmethodID dwInit = env->GetMethodID(clazz, "dwInit",
5416 "(Ljava/lang/String;Ljava/lang/String;)V");
5417 // Call the method on the object
5418 env->CallVoidMethod(_dw_obj, dwInit, appid, appname);
5419 }
5383 return DW_ERROR_NONE; 5420 return DW_ERROR_NONE;
5384 } 5421 }
5385 5422
5386 /* 5423 /*
5387 * Cleanly terminates a DW session, should be signal handler safe. 5424 * Cleanly terminates a DW session, should be signal handler safe.
5482 * This will create a system notification that will show in the notifaction panel 5519 * This will create a system notification that will show in the notifaction panel
5483 * on supported systems, which may be clicked to perform another task. 5520 * on supported systems, which may be clicked to perform another task.
5484 */ 5521 */
5485 HWND API dw_notification_new(const char *title, const char *imagepath, const char *description, ...) 5522 HWND API dw_notification_new(const char *title, const char *imagepath, const char *description, ...)
5486 { 5523 {
5524 JNIEnv *env;
5525
5526 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
5527 {
5528 // Construct a String
5529 jstring appid = env->NewStringUTF(_dw_app_id);
5530 jstring ntitle = env->NewStringUTF(title);
5531 jstring ndesc = NULL;
5532 jstring image = NULL;
5533
5534 if(description)
5535 {
5536 va_list args;
5537 char outbuf[1025] = {0};
5538
5539 va_start(args, description);
5540 vsnprintf(outbuf, 1024, description, args);
5541 va_end(args);
5542
5543 ndesc = env->NewStringUTF(outbuf);
5544 }
5545 if(imagepath)
5546 image = env->NewStringUTF(imagepath);
5547
5548 // First get the class that contains the method you need to call
5549 jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
5550 // Get the method that you want to call
5551 jmethodID notificationNew = env->GetMethodID(clazz, "notificationNew",
5552 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroidx/core/app/NotificationCompat$Builder;");
5553 // Call the method on the object
5554 jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, notificationNew, ntitle, image, ndesc, appid));
5555 return result;
5556 }
5487 return 0; 5557 return 0;
5488 } 5558 }
5489 5559
5490 /* 5560 /*
5491 * Sends a notification created by dw_notification_new() after attaching signal handler. 5561 * Sends a notification created by dw_notification_new() after attaching signal handler.
5494 * Returns: 5564 * Returns:
5495 * DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported. 5565 * DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported.
5496 */ 5566 */
5497 int API dw_notification_send(HWND notification) 5567 int API dw_notification_send(HWND notification)
5498 { 5568 {
5569 JNIEnv *env;
5570
5571 if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
5572 {
5573 // First get the class that contains the method you need to call
5574 jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
5575 // Get the method that you want to call
5576 jmethodID notificationNew = env->GetMethodID(clazz, "notificationSend",
5577 "(Landroidx/core/app/NotificationCompat$Builder;)V");
5578 // Call the method on the object
5579 env->CallVoidMethod(_dw_obj, notificationNew, notification);
5580 return DW_ERROR_NONE;
5581 }
5499 return DW_ERROR_UNKNOWN; 5582 return DW_ERROR_UNKNOWN;
5500 } 5583 }
5501 5584
5502 /* 5585 /*
5503 * Converts a UTF-8 encoded string into a wide string. 5586 * Converts a UTF-8 encoded string into a wide string.