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