OpenCPN Partial API docs
Loading...
Searching...
No Matches
android_support.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2015 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include "android_support.h"
25
26#include <QtAndroidExtras/QAndroidJniObject>
27#include <qdebug.h>
28
29#include <wx/wxprec.h>
30#ifndef WX_PRECOMP
31#include <wx/wx.h>
32#endif
33#include <wx/tokenzr.h>
34
35#include "android_jvm.h"
36
37extern int g_Android_SDK_Version;
38
39bool CheckPendingJNIException() {
40 JNIEnv *jenv;
41
42 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) return true;
43
44 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
45 // Handle exception here.
46 (jenv)->ExceptionDescribe(); // writes to logcat
47 (jenv)->ExceptionClear();
48
49 return false; // There was a pending exception, but cleared OK
50 // interesting discussion:
51 // http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/
52 }
53
54 return false;
55}
56
57wxString callActivityMethod_s4s(const char *method, wxString parm1,
58 wxString parm2, wxString parm3,
59 wxString parm4) {
60 if (CheckPendingJNIException()) return _T("NOK");
61 JNIEnv *jenv;
62
63 wxString return_string;
64 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
65 "org/qtproject/qt5/android/QtNative", "activity",
66 "()Landroid/app/Activity;");
67 if (CheckPendingJNIException()) return _T("NOK");
68
69 if (!activity.isValid()) {
70 // qDebug() << "Activity is not valid";
71 return return_string;
72 }
73
74 // Need a Java environment to decode the resulting string
75 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
76 // qDebug() << "GetEnv failed.";
77 return _T("jenv Error");
78 }
79
80 wxCharBuffer p1b = parm1.ToUTF8();
81 jstring p1 = (jenv)->NewStringUTF(p1b.data());
82
83 wxCharBuffer p2b = parm2.ToUTF8();
84 jstring p2 = (jenv)->NewStringUTF(p2b.data());
85
86 wxCharBuffer p3b = parm3.ToUTF8();
87 jstring p3 = (jenv)->NewStringUTF(p3b.data());
88
89 wxCharBuffer p4b = parm4.ToUTF8();
90 jstring p4 = (jenv)->NewStringUTF(p4b.data());
91
92 // const char *ts = (jenv)->GetStringUTFChars(p2, NULL);
93 // qDebug() << "Test String p2" << ts;
94
95 // Call the desired method
96 // qDebug() << "Calling method_s4s" << " (" << method << ")";
97
98 QAndroidJniObject data = activity.callObjectMethod(
99 method,
100 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
101 "String;)Ljava/lang/String;",
102 p1, p2, p3, p4);
103 (jenv)->DeleteLocalRef(p1);
104 (jenv)->DeleteLocalRef(p2);
105 (jenv)->DeleteLocalRef(p3);
106 (jenv)->DeleteLocalRef(p4);
107
108 if (CheckPendingJNIException()) return _T("NOK");
109
110 // qDebug() << "Back from method_s4s";
111
112 jstring s = data.object<jstring>();
113
114 if ((jenv)->GetStringLength(s)) {
115 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
116 return_string = wxString(ret_string, wxConvUTF8);
117 }
118
119 return return_string;
120}
121
122wxString callActivityMethod_ss(const char *method, wxString parm) {
123 if (CheckPendingJNIException()) return _T("NOK");
124 JNIEnv *jenv;
125
126 wxString return_string;
127 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
128 "org/qtproject/qt5/android/QtNative", "activity",
129 "()Landroid/app/Activity;");
130 if (CheckPendingJNIException()) return _T("NOK");
131
132 if (!activity.isValid()) {
133 // qDebug() << "Activity is not valid";
134 return return_string;
135 }
136
137 // Need a Java environment to decode the resulting string
138 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
139 // qDebug() << "GetEnv failed.";
140 return _T("jenv Error");
141 }
142
143 jstring p = (jenv)->NewStringUTF(parm.c_str());
144
145 // Call the desired method
146 // qDebug() << "Calling method_ss";
147 // qDebug() << method;
148
149 QAndroidJniObject data = activity.callObjectMethod(
150 method, "(Ljava/lang/String;)Ljava/lang/String;", p);
151
152 (jenv)->DeleteLocalRef(p);
153
154 if (CheckPendingJNIException()) return _T("NOK");
155
156 // qDebug() << "Back from method_ss";
157
158 jstring s = data.object<jstring>();
159
160 if ((jenv)->GetStringLength(s)) {
161 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
162 return_string = wxString(ret_string, wxConvUTF8);
163 }
164
165 return return_string;
166}
167
168wxString callActivityMethod_vs(const char *method) {
169 if (CheckPendingJNIException()) return _T("NOK");
170
171 JNIEnv *jenv;
172
173 wxString return_string;
174 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
175 "org/qtproject/qt5/android/QtNative", "activity",
176 "()Landroid/app/Activity;");
177 if (CheckPendingJNIException()) return _T("NOK");
178
179 if (!activity.isValid()) {
180 // qDebug() << "Activity is not valid";
181 return return_string;
182 }
183
184 // Call the desired method
185 QAndroidJniObject data =
186 activity.callObjectMethod(method, "()Ljava/lang/String;");
187 if (CheckPendingJNIException()) return _T("NOK");
188
189 jstring s = data.object<jstring>();
190
191 if (s) {
192 // Need a Java environment to decode the resulting string
193 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
194 // qDebug() << "GetEnv failed.";
195 } else {
196 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
197 return_string = wxString(ret_string, wxConvUTF8);
198 }
199 }
200
201 return return_string;
202}
203
204wxString callActivityMethod_s2s(const char *method, wxString parm1,
205 wxString parm2) {
206 if (CheckPendingJNIException()) return _T("NOK");
207 JNIEnv *jenv;
208
209 wxString return_string;
210 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
211 "org/qtproject/qt5/android/QtNative", "activity",
212 "()Landroid/app/Activity;");
213 if (CheckPendingJNIException()) return _T("NOK");
214
215 if (!activity.isValid()) {
216 // qDebug() << "Activity is not valid";
217 return return_string;
218 }
219
220 // Need a Java environment to decode the resulting string
221 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
222 // qDebug() << "GetEnv failed.";
223 return _T("jenv Error");
224 }
225
226 jstring p1 = (jenv)->NewStringUTF(parm1.c_str());
227 jstring p2 = (jenv)->NewStringUTF(parm2.c_str());
228
229 // Call the desired method
230 // qDebug() << "Calling method_s2s" << " (" << method << ")";
231
232 QAndroidJniObject data = activity.callObjectMethod(
233 method, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", p1,
234 p2);
235
236 (jenv)->DeleteLocalRef(p1);
237 (jenv)->DeleteLocalRef(p2);
238
239 if (CheckPendingJNIException()) return _T("NOK");
240
241 // qDebug() << "Back from method_s2s";
242
243 jstring s = data.object<jstring>();
244
245 if ((jenv)->GetStringLength(s)) {
246 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
247 return_string = wxString(ret_string, wxConvUTF8);
248 }
249
250 return return_string;
251}
252
253bool AndroidUnzip(wxString zipFile, wxString destDir, int nStrip,
254 bool bRemoveZip) {
255 qDebug() << "AndroidUnzip" << zipFile.mb_str() << destDir.mb_str();
256
257 wxString ns;
258 ns.Printf(_T("%d"), nStrip);
259
260 wxString br = _T("0");
261 if (bRemoveZip) br = _T("1");
262
263 qDebug() << "br" << br.mb_str();
264
265 wxString stat = callActivityMethod_s4s("unzipFile", zipFile, destDir, ns, br);
266
267 if (wxNOT_FOUND == stat.Find(_T("OK"))) return false;
268
269 qDebug() << "unzip start";
270
271 bool bDone = false;
272 while (!bDone) {
273 wxMilliSleep(1000);
274 // wxSafeYield(NULL, true);
275
276 qDebug() << "unzip poll";
277
278 wxString result = callActivityMethod_ss("getUnzipStatus", _T(""));
279 if (wxNOT_FOUND != result.Find(_T("DONE"))) bDone = true;
280 }
281 qDebug() << "unzip done";
282
283 return true;
284}
285
286wxString AndroidGetCacheDir() {
287 wxString dirs = callActivityMethod_vs("getSystemDirs");
288 qDebug() << "dirs: " << dirs.mb_str();
289
290 wxString cacheDir;
291
292 wxStringTokenizer tk(dirs, _T(";"));
293 if (tk.HasMoreTokens()) {
294 wxString token = tk.GetNextToken();
295 // if(wxNOT_FOUND != token.Find(_T("EXTAPP")))
296 // g_bExternalApp = true;
297
298 token = tk.GetNextToken();
299 // g_androidFilesDir = token; // used for "home dir"
300 token = tk.GetNextToken();
301 // g_androidCacheDir = token;
302 token = tk.GetNextToken();
303 // g_androidExtFilesDir = token; // used as PrivateDataDir,
304 // "/storage/emulated/0/Android/data/org.opencpn.opencpn/files"
305 // if app has been moved to sdcard, this gives like (on Android 6)
306 // /storage/2385-1BF8/Android/data/org.opencpn.opencpn/files
307
308 token = tk.GetNextToken();
309 cacheDir = token;
310
311 // token = tk.GetNextToken();
312 // g_androidExtStorageDir = token;
313 }
314
315 return cacheDir;
316}
317
318bool AndroidSecureCopyFile(wxString in, wxString out) {
319 bool bret = true;
320
321 wxString result = callActivityMethod_s2s("SecureFileCopy", in, out);
322
323 if (wxNOT_FOUND == result.Find(_T("OK"))) bret = false;
324
325 return bret;
326}
327
328bool b_androidBusyShown;
329void androidShowBusyIcon() {
330 if (b_androidBusyShown) return;
331
332 // qDebug() << "ShowBusy";
333
334 // Get a reference to the running native activity
335 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
336 "org/qtproject/qt5/android/QtNative", "activity",
337 "()Landroid/app/Activity;");
338 if (!activity.isValid()) {
339 // qDebug() << "Activity is not valid";
340 return;
341 }
342
343 // Call the desired method
344 QAndroidJniObject data =
345 activity.callObjectMethod("showBusyCircle", "()Ljava/lang/String;");
346
347 b_androidBusyShown = true;
348}
349
350void androidHideBusyIcon() {
351 if (!b_androidBusyShown) return;
352
353 // Get a reference to the running native activity
354 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
355 "org/qtproject/qt5/android/QtNative", "activity",
356 "()Landroid/app/Activity;");
357
358 if (!activity.isValid()) {
359 // qDebug() << "Activity is not valid";
360 return;
361 }
362
363 // Call the desired method
364 QAndroidJniObject data =
365 activity.callObjectMethod("hideBusyCircle", "()Ljava/lang/String;");
366
367 b_androidBusyShown = false;
368}
369
370void androidEnableRotation(void) { callActivityMethod_vs("EnableRotation"); }
371
372void androidDisableRotation(void) { callActivityMethod_vs("DisableRotation"); }
373
374int androidGetSDKVersion() {
375 wxString deviceInfo = callActivityMethod_vs("getDeviceInfo");
376 wxStringTokenizer tkz(deviceInfo, _T("\n"));
377 while (tkz.HasMoreTokens()) {
378 wxString s1 = tkz.GetNextToken();
379 if (wxNOT_FOUND != s1.Find(_T("OS API Level"))) {
380 int a = s1.Find(_T("{"));
381 if (wxNOT_FOUND != a) {
382 wxString b = s1.Mid(a + 1, 2);
383 long SDK;
384 b.ToLong(&SDK);
385 g_Android_SDK_Version = SDK;
386 }
387 }
388 }
389 return g_Android_SDK_Version;
390}
OpenCPN Android support utilities.