33#include <wx/tokenzr.h>
34#include <wx/aui/aui.h>
36#include <wx/fontpicker.h>
37#include <wx/filepicker.h>
38#include <wx/zipstrm.h>
39#include <wx/textwrapper.h>
41#include <QtAndroidExtras/QAndroidJniObject>
44#include "AISTargetAlertDialog.h"
45#include "AISTargetListDialog.h"
46#include "AISTargetQueryDialog.h"
47#include "AndroidSound.h"
48#include "androidUTIL.h"
49#include "CanvasOptions.h"
54#include "config_vars.h"
56#include "glChartCanvas.h"
59#include "iENCToolbar.h"
63#include "multiplexer.h"
64#include "nav_object_database.h"
67#include "OCPNPlatform.h"
68#include "ocpn_plugin.h"
71#include "plugin_loader.h"
72#include "routemanagerdialog.h"
74#include "RoutePropDlgImpl.h"
78#include "S57QueryDialog.h"
83#include "TrackPropDlg.h"
89const wxString AndroidSuppLicense = wxT(
90 "<br><br>The software included in this product contains copyrighted "
91 "software that is licensed under the GPL.")
92 wxT("A copy of that license is shown above.") wxT(
93 "You may obtain the complete Corresponding Source code from us for ")
94 wxT("a period of three years after our last shipment of this product, ")
95 wxT("by sending a money order or check for $5 to:<br><br>")
96 wxT("GPL Compliance Division<br>") wxT("Dyad Inc.<br>")
97 wxT("31 Ocean Reef Dr<br>") wxT("
# C101-449<br>")
98 wxT("Key Largo, FL 33037-5282<br>")
99 wxT("United States<br><br>")
100 wxT("Please write “source for OpenCPN Version "
101 "{insert version here} in the memo line of "
102 "your payment.<br><br>");
105static const long long lNaN = 0xfff8000000000000;
106#define NAN (*(double *)&lNaN)
109class androidUtilHandler;
112extern MyFrame *gFrame;
113extern const wxEventType wxEVT_OCPN_DATASTREAM;
114// extern const wxEventType wxEVT_DOWNLOAD_EVENT;
116wxEvtHandler *s_pAndroidNMEAMessageConsumer;
117wxEvtHandler *s_pAndroidBTNMEAMessageConsumer;
119extern AISTargetAlertDialog *g_pais_alert_dialog_active;
120extern AISTargetQueryDialog *g_pais_query_dialog_active;
121extern AISTargetListDialog *g_pAISTargetList;
122// extern MarkInfoImpl *pMarkPropDialog;
123extern RoutePropDlgImpl *pRoutePropDialog;
124extern TrackPropDlg *pTrackPropDialog;
125extern S57QueryDialog *g_pObjectQueryDialog;
126extern options *g_options;
128androidUtilHandler *g_androidUtilHandler;
129extern wxDateTime g_start_time;
130extern RouteManagerDialog *pRouteManagerDialog;
131extern about *g_pAboutDlgLegacy;
132extern bool g_bFullscreen;
133extern OCPNPlatform *g_Platform;
136extern ChartDB *ChartData;
137extern MyConfig *pConfig;
139// Preferences globals
140extern bool g_bShowOutlines;
141extern bool g_bShowChartBar;
142extern bool g_bShowDepthUnits;
143extern bool g_bskew_comp;
144extern bool g_bopengl;
145extern bool g_bsmoothpanzoom;
146extern bool g_bShowMag;
147extern int g_chart_zoom_modifier_raster;
148extern int g_NMEAAPBPrecision;
150extern wxString *pInit_Chart_Dir;
151extern bool g_bfilter_cogsog;
152extern int g_COGFilterSec;
153extern int g_SOGFilterSec;
155extern bool g_bDisplayGrid;
157// AIS Global configuration
158extern bool g_bCPAMax;
159extern double g_CPAMax_NM;
160extern bool g_bCPAWarn;
161extern double g_CPAWarn_NM;
162extern bool g_bTCPA_Max;
163extern double g_TCPA_Max;
164extern bool g_bMarkLost;
165extern double g_MarkLost_Mins;
166extern bool g_bRemoveLost;
167extern double g_RemoveLost_Mins;
168extern bool g_bShowCOG;
169extern double g_ShowCOG_Mins;
170extern bool g_bAISShowTracks;
171extern double g_AISShowTracks_Mins;
172extern bool g_bHideMoored;
173extern double g_ShowMoored_Kts;
174extern bool g_bAIS_CPA_Alert;
175extern bool g_bAIS_CPA_Alert_Audio;
176extern wxString g_sAIS_Alert_Sound_File;
177extern bool g_bAIS_CPA_Alert_Suppress_Moored;
178extern bool g_bShowAreaNotices;
179extern bool g_bDrawAISSize;
180extern bool g_bShowAISName;
181extern int g_Show_Target_Name_Scale;
182extern bool g_bWplIsAprsPosition;
184extern int g_iNavAidRadarRingsNumberVisible;
185extern float g_fNavAidRadarRingsStep;
186extern int g_pNavAidRadarRingsStepUnits;
187extern int g_iWaypointRangeRingsNumber;
188extern float g_fWaypointRangeRingsStep;
189extern int g_iWaypointRangeRingsStepUnits;
190extern wxColour g_colourWaypointRangeRingsColour;
191extern bool g_bWayPointPreventDragging;
193extern bool g_bPreserveScaleOnX;
194extern bool g_bPlayShipsBells;
195extern int g_iSoundDeviceIndex;
196extern bool g_bFullscreenToolbar;
198extern int g_OwnShipIconType;
199extern double g_n_ownship_length_meters;
200extern double g_n_ownship_beam_meters;
201extern double g_n_gps_antenna_offset_y;
202extern double g_n_gps_antenna_offset_x;
203extern int g_n_ownship_min_mm;
204extern double g_n_arrival_circle_radius;
206extern bool g_bEnableZoomToCursor;
207extern bool g_bTrackDaily;
208extern bool g_bHighliteTracks;
209extern double g_TrackIntervalSeconds;
210extern double g_TrackDeltaDistance;
211extern double g_TrackDeltaDistance;
212extern int g_nTrackPrecision;
214extern int g_iSDMMFormat;
215extern int g_iDistanceFormat;
216extern int g_iSpeedFormat;
218extern bool g_bAdvanceRouteWaypointOnArrivalOnly;
220extern int g_cm93_zoom_factor;
222extern int g_COGAvgSec;
224extern bool g_bCourseUp;
225extern bool g_bLookAhead;
227extern double g_ownship_predictor_minutes;
228extern double g_ownship_HDTpredictor_miles;
230extern bool g_bAISRolloverShowClass;
231extern bool g_bAISRolloverShowCOG;
232extern bool g_bAISRolloverShowCPA;
234extern bool g_bAIS_ACK_Timeout;
235extern double g_AckTimeout_Mins;
237extern bool g_bQuiltEnable;
238extern bool g_bFullScreenQuilt;
239extern bool g_bConfirmObjectDelete;
241#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
242extern wxLocale *plocale_def_lang;
245// extern OCPN_Sound g_anchorwatch_sound;
246extern bool g_bMagneticAPB;
248extern bool g_fog_overzoom;
249extern double g_overzoom_emphasis_base;
250extern bool g_oz_vector_scale;
251extern bool g_bShowStatusBar;
253extern ocpnGLOptions g_GLOptions;
255extern s52plib *ps52plib;
257extern wxString g_locale;
258extern bool g_bportable;
259extern bool g_bdisable_opengl;
261extern ChartGroupArray *g_pGroupArray;
263extern bool g_bUIexpert;
265#define ID_CHOICE_NMEA wxID_HIGHEST + 1
267// extern wxArrayString *EnumerateSerialPorts(void); // in chart1.cpp
269extern wxArrayString TideCurrentDataSet;
270extern wxString g_TCData_Dir;
272extern AisDecoder *g_pAIS;
274extern options *g_pOptions;
277extern bool g_bresponsive;
278extern bool g_bAutoHideToolbar;
279extern int g_nAutoHideToolbar;
280extern int g_GUIScaleFactor;
281extern int g_ChartScaleFactor;
283extern double g_config_display_size_mm;
284extern float g_ChartScaleFactorExp;
285extern bool g_config_display_size_manual;
287extern Multiplexer *g_pMUX;
288extern bool b_inCloseWindow;
289extern bool g_config_display_size_manual;
290extern MarkInfoDlg *g_pMarkInfoDialog;
291extern PlugInManager *g_pi_manager;
292extern iENCToolbar *g_iENCToolbar;
293extern int g_iENCToolbarPosX;
294extern int g_iENCToolbarPosY;
295extern ocpnFloatingToolbarDialog *g_MainToolbar;
296extern int g_maintoolbar_x;
297extern int g_maintoolbar_y;
298extern long g_maintoolbar_orient;
299extern int g_restore_stackindex;
300extern int g_restore_dbindex;
301extern ChartStack *pCurrentStack;
302extern Select *pSelect;
303extern WayPointman *pWayPointMan;
304extern bool g_bCruising;
305extern RoutePoint *pAnchorWatchPoint1;
306extern RoutePoint *pAnchorWatchPoint2;
307extern bool g_bAutoAnchorMark;
308extern wxAuiManager *g_pauimgr;
309extern wxString g_AisTargetList_perspective;
311extern ocpnFloatingToolbarDialog *g_MainToolbar;
313WX_DEFINE_ARRAY_PTR(ChartCanvas *, arrayofCanvasPtr);
314extern arrayofCanvasPtr g_canvasArray;
316wxString callActivityMethod_vs(const char *method);
317wxString callActivityMethod_is(const char *method, int parm);
319// Globals, accessible only to this module
323bool b_androidBusyShown;
325double g_androidDensity;
329wxString g_androidFilesDir;
330wxString g_androidCacheDir;
331wxString g_androidExtFilesDir;
332wxString g_androidExtCacheDir;
333wxString g_androidExtStorageDir;
334wxString g_androidGetFilesDirs0;
335wxString g_androidGetFilesDirs1;
336wxString g_androidDownloadDirectory;
341int g_ActionBarHeight;
349wxString s_requested_url;
350wxEvtHandler *s_download_evHandler;
351wxString s_download_destination;
355extern int g_GUIScaleFactor;
357wxString g_deviceInfo;
359int s_androidMemTotal;
362bool g_bFullscreenSave;
365extern int ShowNavWarning();
366extern bool g_btrackContinuous;
367extern wxString ChartListFileName;
369int doAndroidPersistState();
372AudioDoneCallback s_soundCallBack;
377int g_Android_SDK_Version;
378MigrateAssistantDialog *g_migrateDialog;
380// Some dummy devices to ensure plugins have static access to these classes
382wxFontPickerEvent g_dummy_wxfpe;
384#define ANDROID_EVENT_TIMER 4389
385#define ANDROID_STRESS_TIMER 4388
386#define ANDROID_RESIZE_TIMER 4387
388#define ACTION_NONE -1
389#define ACTION_RESIZE_PERSISTENTS 1
390#define ACTION_FILECHOOSER_END 3
391#define ACTION_COLORDIALOG_END 4
392#define ACTION_POSTASYNC_END 5
393#define ACTION_SAF_PERMISSION_END 6
395#define SCHEDULED_EVENT_CLEAN_EXIT 5498
397class androidUtilHandler : public wxEvtHandler {
399 androidUtilHandler();
400 ~androidUtilHandler() {}
402 void onTimerEvent(wxTimerEvent &event);
403 void onStressTimer(wxTimerEvent &event);
404 void OnResizeTimer(wxTimerEvent &event);
405 void OnScheduledEvent(wxCommandEvent &event);
407 wxString GetStringResult() { return m_stringResult; }
408 void LoadAuxClasses();
410 wxTimer m_eventTimer;
413 wxString m_stringResult;
414 wxTimer m_stressTimer;
415 wxTimer m_resizeTimer;
418 bool m_migratePermissionSetDone;
420 DECLARE_EVENT_TABLE()
423const char wxMessageBoxCaptionStr[] = "Message";
425BEGIN_EVENT_TABLE(androidUtilHandler, wxEvtHandler)
426EVT_TIMER(ANDROID_EVENT_TIMER, androidUtilHandler::onTimerEvent)
427EVT_TIMER(ANDROID_RESIZE_TIMER, androidUtilHandler::OnResizeTimer)
428EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED,
429 androidUtilHandler::OnScheduledEvent)
433androidUtilHandler::androidUtilHandler() {
434 m_eventTimer.SetOwner(this, ANDROID_EVENT_TIMER);
435 m_stressTimer.SetOwner(this, ANDROID_STRESS_TIMER);
436 m_resizeTimer.SetOwner(this, ANDROID_RESIZE_TIMER);
438 m_bskipConfirm = false;
443void androidUtilHandler::LoadAuxClasses()
445 // We do a few little dummy class accesses here, to cause the static link to
446 // wxWidgets to bring in some class members required by some plugins, that
447 // would be missing otherwise.
449 wxRegion a(0, 0, 1, 1);
450 wxRegion b(0, 0, 2, 2);
451 bool c = a.IsEqual(b);
453 wxFilePickerCtrl *pfpc = new wxFilePickerCtrl();
455 wxZipEntry *entry = new wxZipEntry();
457 wxSplitterWindow *swin = new wxSplitterWindow();
461void androidUtilHandler::onTimerEvent(wxTimerEvent &event) {
462 qDebug() << "onTimerEvent" << m_action;
465 case ACTION_RESIZE_PERSISTENTS: // Handle rotation/resizing of persistent
469 if (g_pais_query_dialog_active) {
472 bool bshown = g_pais_query_dialog_active->IsShown();
473 g_pais_query_dialog_active->Hide();
474 g_pais_query_dialog_active->RecalculateSize();
477 g_pais_query_dialog_active->Show();
478 g_pais_query_dialog_active->Raise();
483 if (RoutePropDlgImpl::getInstanceFlag()) {
484 bool bshown = pRoutePropDialog->IsShown();
486 pRoutePropDialog->Hide();
487 pRoutePropDialog->RecalculateSize();
488 pRoutePropDialog->Show();
490 pRoutePropDialog->Destroy();
491 pRoutePropDialog = NULL;
496 if (TrackPropDlg::getInstanceFlag()) {
497 bool bshown = pTrackPropDialog->IsShown();
499 pTrackPropDialog->Hide();
500 pTrackPropDialog->RecalculateSize();
501 pTrackPropDialog->Show();
503 pTrackPropDialog->Destroy();
504 pTrackPropDialog = NULL;
510 if (g_pMarkInfoDialog) {
511 bool bshown = g_pMarkInfoDialog->IsShown();
512 g_pMarkInfoDialog->Hide();
513 g_pMarkInfoDialog->RecalculateSize();
515 if (g_pMarkInfoDialog->m_SaveDefaultDlg) {
516 g_pMarkInfoDialog->m_SaveDefaultDlg->Destroy();
517 g_pMarkInfoDialog->m_SaveDefaultDlg = NULL;
519 g_pMarkInfoDialog->Show();
524 if (g_pObjectQueryDialog) {
525 bool bshown = g_pObjectQueryDialog->IsShown();
526 g_pObjectQueryDialog->Hide();
527 g_pObjectQueryDialog->RecalculateSize();
529 g_pObjectQueryDialog->Show();
533 // AIS Target List dialog
534 if (g_pAISTargetList) {
536 bool bshown = g_pAISTargetList->IsShown();
537 g_pAISTargetList->Hide();
538 g_pAISTargetList->RecalculateSize();
541 g_pAISTargetList->Show();
542 g_pAISTargetList->Raise();
546 // Tide/Current window
547 if (gFrame->GetPrimaryCanvas()->getTCWin()) {
548 bool bshown = gFrame->GetPrimaryCanvas()->getTCWin()->IsShown();
549 gFrame->GetPrimaryCanvas()->getTCWin()->Hide();
550 gFrame->GetPrimaryCanvas()->getTCWin()->RecalculateSize();
552 gFrame->GetPrimaryCanvas()->getTCWin()->Show();
553 gFrame->GetPrimaryCanvas()->getTCWin()->Refresh();
557 // Route Manager dialog
558 if (RouteManagerDialog::getInstanceFlag()) {
559 bool bshown = pRouteManagerDialog->IsShown();
561 pRouteManagerDialog->Hide();
562 pRouteManagerDialog->RecalculateSize();
563 pRouteManagerDialog->Show();
565 pRouteManagerDialog->Destroy();
566 pRouteManagerDialog = NULL;
571 if (g_pAboutDlgLegacy) {
572 bool bshown = g_pAboutDlgLegacy->IsShown();
574 g_pAboutDlgLegacy->Hide();
575 g_pAboutDlgLegacy->RecalculateSize();
576 g_pAboutDlgLegacy->Show();
581 g_options->RecalculateSize();
584 bInConfigChange = false;
588 case ACTION_FILECHOOSER_END: // Handle polling of android Dialog
590 // qDebug() << "chooser poll";
591 // Get a reference to the running FileChooser
592 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
593 "org/qtproject/qt5/android/QtNative", "activity",
594 "()Landroid/app/Activity;");
596 if (!activity.isValid()) {
597 // qDebug() << "onTimerEvent : Activity is not valid";
601 // Call the method which tracks the completion of the Intent.
602 QAndroidJniObject data = activity.callObjectMethod(
603 "isFileChooserFinished", "()Ljava/lang/String;");
605 jstring s = data.object<jstring>();
609 // Need a Java environment to decode the resulting string
610 if (java_vm->GetEnv((void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
611 // qDebug() << "GetEnv failed.";
613 // The string coming back will be one of:
614 // "no" ......Intent not done yet.
615 // "cancel:" .. user cancelled intent.
616 // "file:{file_name}" .. user selected this file, fully qualified.
618 // qDebug() << "isFileChooserFinished returned null";
619 } else if ((jenv)->GetStringLength(s)) {
620 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
621 // qDebug() << "isFileChooserFinished returned
623 if (!strncmp(ret_string,
"cancel:", 7)) {
625 m_stringResult = _T(
"cancel:");
626 }
else if (!strncmp(ret_string,
"file:", 5)) {
628 m_stringResult = wxString(ret_string, wxConvUTF8);
636 case ACTION_COLORDIALOG_END:
640 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
641 "org/qtproject/qt5/android/QtNative",
"activity",
642 "()Landroid/app/Activity;");
644 if (!activity.isValid()) {
650 QAndroidJniObject data = activity.callObjectMethod(
651 "isColorPickerDialogFinished",
"()Ljava/lang/String;");
653 jstring s = data.object<jstring>();
658 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
666 qDebug() <<
"isColorPickerDialogFinished returned null";
667 }
else if ((jenv)->GetStringLength(s)) {
668 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
670 if (!strncmp(ret_string,
"cancel:", 7)) {
672 m_stringResult = _T(
"cancel:");
673 }
else if (!strncmp(ret_string,
"color:", 6)) {
675 m_stringResult = wxString(ret_string, wxConvUTF8);
683 case ACTION_POSTASYNC_END:
688 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
689 "org/qtproject/qt5/android/QtNative",
"activity",
690 "()Landroid/app/Activity;");
692 if (!activity.isValid()) {
698 QAndroidJniObject data =
699 activity.callObjectMethod(
"checkPostAsync",
"()Ljava/lang/String;");
701 jstring s = data.object<jstring>();
706 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
713 qDebug() <<
"checkPostAsync returned null";
714 }
else if ((jenv)->GetStringLength(s)) {
715 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
716 qDebug() <<
"checkPostAsync returned " << ret_string;
717 if (strncmp(ret_string,
"ACTIVE", 6)) {
719 m_stringResult = wxString(ret_string, wxConvUTF8);
728 case ACTION_SAF_PERMISSION_END:
730 qDebug() <<
"SAF permission chooser poll";
732 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
733 "org/qtproject/qt5/android/QtNative",
"activity",
734 "()Landroid/app/Activity;");
736 if (!activity.isValid()) {
742 QAndroidJniObject data = activity.callObjectMethod(
743 "isSAFChooserFinished",
"()Ljava/lang/String;");
745 jstring s = data.object<jstring>();
750 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
759 }
else if ((jenv)->GetStringLength(s)) {
760 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
762 if (!strncmp(ret_string,
"cancel:", 7)) {
763 m_migratePermissionSetDone =
true;
764 m_stringResult = _T(
"cancel:");
765 }
else if (!strncmp(ret_string,
"file:", 5)) {
766 m_migratePermissionSetDone =
true;
767 m_stringResult = wxString(ret_string, wxConvUTF8);
771 if(m_migratePermissionSetDone){
772 g_androidUtilHandler->m_action = ACTION_NONE;
773 g_androidUtilHandler->m_eventTimer.Stop();
776 g_migrateDialog->onPermissionGranted(m_stringResult);
790void androidUtilHandler::OnResizeTimer(wxTimerEvent &event) {
791 if (timer_sequence == 0) {
803 qDebug() <<
"sequence 0";
809 m_resizeTimer.Start(1000, wxTIMER_ONE_SHOT);
813 if (timer_sequence == 1) {
814 qDebug() <<
"sequence 1";
816 qDebug() <<
"****config_size: " << config_size.x << config_size.y;
818 wxSize szt = gFrame->GetSize();
819 qDebug() <<
"****Frame Size: " << szt.x << szt.y;
828 wxSize new_size = getAndroidDisplayDimensions();
829 qDebug() <<
"****NewSize: " << new_size.x << new_size.y;
831 if ((g_orientation == 1) || (g_orientation == 3)) {
834 }
else if ((g_orientation == 2) || (g_orientation == 4)) {
839 qDebug() <<
"****Force config change";
840 gFrame->SetSize(config_size);
842 if (!m_bskipConfirm) m_resizeTimer.Start(10, wxTIMER_ONE_SHOT);
843 m_bskipConfirm =
false;
847 if (timer_sequence == 2) {
848 qDebug() <<
"sequence 2";
850 m_resizeTimer.Start(10, wxTIMER_ONE_SHOT);
854 if (timer_sequence == 3) {
855 qDebug() <<
"sequence 3";
856 androidConfirmSizeCorrection();
859 m_resizeTimer.Start(10, wxTIMER_ONE_SHOT);
863 if (timer_sequence == 4) {
864 qDebug() <<
"sequence 4";
868 if (g_options) g_options->Raise();
870 resizeAndroidPersistents();
877void androidUtilHandler::onStressTimer(wxTimerEvent &event) {
878 g_GUIScaleFactor = -5;
879 g_ChartScaleFactor = -5;
880 gFrame->SetGPSCompassScale();
882 s_androidMemUsed = 80;
884 g_GLOptions.m_bTextureCompression = 0;
885 g_GLOptions.m_bTextureCompressionCaching = 0;
887 if (600 == stime++) androidTerminate();
890void androidUtilHandler::OnScheduledEvent(wxCommandEvent &event) {
891 switch (event.GetId()) {
892 case SCHEDULED_EVENT_CLEAN_EXIT:
900 case ID_CMD_TRIGGER_RESIZE:
901 qDebug() <<
"Trigger Resize";
903 m_resizeTimer.Start(10, wxTIMER_ONE_SHOT);
904 bInConfigChange =
true;
907 case ID_CMD_SOUND_FINISHED:
909 if (s_soundCallBack) {
910 s_soundCallBack(s_soundData);
931bool androidUtilInit(
void) {
932 qDebug() <<
"androidUtilInit()";
938 s_androidMemTotal = 100;
939 s_androidMemUsed = 50;
941 wxString dirs = callActivityMethod_vs(
"getSystemDirs");
942 qDebug() <<
"dirs: " << dirs.mb_str();
944 wxStringTokenizer tk(dirs, _T(
";"));
945 if (tk.HasMoreTokens()) {
946 wxString token = tk.GetNextToken();
947 if (wxNOT_FOUND != token.Find(_T(
"EXTAPP"))) g_bExternalApp =
true;
949 token = tk.GetNextToken();
950 g_androidFilesDir = token;
951 token = tk.GetNextToken();
952 g_androidCacheDir = token;
953 token = tk.GetNextToken();
954 g_androidExtFilesDir =
959 token = tk.GetNextToken();
960 g_androidExtCacheDir = token;
961 token = tk.GetNextToken();
962 g_androidExtStorageDir = token;
964 token = tk.GetNextToken();
965 g_androidGetFilesDirs0 = token;
966 token = tk.GetNextToken();
967 g_androidGetFilesDirs1 = token;
969 token = tk.GetNextToken();
970 g_androidDownloadDirectory = token;
977 wxStringTokenizer tku(g_androidExtFilesDir, _T(
"/"));
978 while (tku.HasMoreTokens()) {
979 wxString s1 = tku.GetNextToken();
981 if (s1.Find(_T(
"org.")) != wxNOT_FOUND) {
982 if (s1 != _T(
"org.opencpn.opencpn")) g_bstress1 =
true;
987 g_androidUtilHandler->Connect(
988 g_androidUtilHandler->m_stressTimer.GetId(), wxEVT_TIMER,
989 wxTimerEventHandler(androidUtilHandler::onStressTimer), NULL,
990 g_androidUtilHandler);
991 g_androidUtilHandler->m_stressTimer.Start(1000, wxTIMER_CONTINUOUS);
998wxSize getAndroidConfigSize() {
return config_size; }
1000void resizeAndroidPersistents() {
1001 qDebug() <<
"resizeAndroidPersistents()";
1003 if (g_androidUtilHandler) {
1004 g_androidUtilHandler->m_action = ACTION_RESIZE_PERSISTENTS;
1005 g_androidUtilHandler->m_eventTimer.Start(100, wxTIMER_ONE_SHOT);
1009jint JNI_OnLoad(JavaVM *vm,
void *reserved) {
1013 if (vm->GetEnv((
void **)&global_jenv, JNI_VERSION_1_6) != JNI_OK) {
1017 return JNI_VERSION_1_6;
1020void sendNMEAMessageEvent(wxString &msg) {
1023 wxCharBuffer abuf = msg.ToUTF8();
1025 std::string s(abuf.data());
1027 OCPN_DataStreamEvent Nevent(wxEVT_OCPN_DATASTREAM, 0);
1028 Nevent.SetNMEAString(s);
1029 Nevent.SetStream(NULL);
1030 if (s_pAndroidNMEAMessageConsumer)
1031 s_pAndroidNMEAMessageConsumer->AddPendingEvent(Nevent);
1041JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_test(JNIEnv *env,
1050JNIEXPORT jint JNICALL
1051 Java_org_opencpn_OCPNNativeLib_onSoundDone(JNIEnv *env,
1054 auto sound =
reinterpret_cast<AndroidSound*
>(soundPtr);
1055 DEBUG_LOG <<
"on SoundDone, ptr: " << soundPtr;
1056 sound->OnSoundDone();
1063JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_processSailTimer(
1064 JNIEnv *env, jobject obj,
double WindAngleMagnetic,
double WindSpeedKnots) {
1070 if (!s_pAndroidNMEAMessageConsumer && g_pMUX)
1071 s_pAndroidNMEAMessageConsumer = g_pMUX;
1073 double wind_angle_mag = 0;
1074 double apparent_wind_angle = 0;
1076 double app_windSpeed = 0;
1077 double true_windSpeed = 0;
1078 double true_windDirection = 0;
1084 double variation = gVar;
1089 double osHead = gCog;
1090 bool buseCOG =
true;
1093 if (!wxIsNaN(gHdt)) {
1099 double osSog = gSog;
1101 wind_angle_mag = WindAngleMagnetic;
1102 app_windSpeed = WindSpeedKnots;
1108 if (!wxIsNaN(osHead) && ((!buseCOG) || (buseCOG && osSog > 0.2))) {
1109 apparent_wind_angle = wind_angle_mag - (osHead - variation);
1111 apparent_wind_angle = 0;
1113 if (apparent_wind_angle < 0) apparent_wind_angle += 360.;
1114 if (apparent_wind_angle > 360.) apparent_wind_angle -= 360.;
1117 if (!wxIsNaN(osSog)) {
1118 true_windSpeed = sqrt(
1119 (osSog * osSog) + (app_windSpeed * app_windSpeed) -
1120 (2 * osSog * app_windSpeed * cos(apparent_wind_angle * PI / 180.)));
1122 true_windSpeed = app_windSpeed;
1126 if ((!wxIsNaN(osSog)) && (!wxIsNaN(osHead)) && (osSog > 0.2) &&
1127 (true_windSpeed > 1)) {
1128 double acosTW = ((osSog * osSog) + (true_windSpeed * true_windSpeed) -
1129 (app_windSpeed * app_windSpeed)) /
1130 (2 * osSog * true_windSpeed);
1132 double twd0 = acos(acosTW) * (180. / PI);
1135 if (apparent_wind_angle > 180.) {
1136 true_windDirection = osHead + 180 + twd0;
1138 true_windDirection = osHead + 180 - twd0;
1141 true_windDirection = wind_angle_mag + variation;
1144 if (true_windDirection < 0) true_windDirection += 360.;
1145 if (true_windDirection > 360.) true_windDirection -= 360.;
1150 if (s_pAndroidNMEAMessageConsumer) {
1158 parser.TalkerID = _T(
"OS");
1162 parser.Mwd.WindAngleTrue = true_windDirection;
1163 parser.Mwd.WindAngleMagnetic = wind_angle_mag;
1164 parser.Mwd.WindSpeedKnots = true_windSpeed;
1165 parser.Mwd.WindSpeedms = true_windSpeed * 0.5144;
1166 parser.Mwd.Write(sntd);
1167 sendNMEAMessageEvent(sntd.Sentence);
1172 parser.Mwv.WindAngle = apparent_wind_angle;
1173 parser.Mwv.WindSpeed = app_windSpeed;
1174 parser.Mwv.WindSpeedUnits = _T(
"N");
1175 parser.Mwv.Reference = _T(
"R");
1176 parser.Mwv.IsDataValid = NTrue;
1177 parser.Mwv.Write(snt);
1178 sendNMEAMessageEvent(snt.Sentence);
1182 double true_relHead = 0;
1183 if (!wxIsNaN(osHead) && ((!buseCOG) || (buseCOG && osSog > 0.2)))
1184 true_relHead = true_windDirection - osHead;
1186 if (true_relHead < 0) true_relHead += 360.;
1187 if (true_relHead > 360.) true_relHead -= 360.;
1189 parser.Mwv.WindAngle = true_relHead;
1190 parser.Mwv.WindSpeed = true_windSpeed;
1191 parser.Mwv.WindSpeedUnits = _T(
"N");
1192 parser.Mwv.Reference = _T(
"T");
1193 parser.Mwv.IsDataValid = NTrue;
1194 parser.Mwv.Write(sntt);
1195 sendNMEAMessageEvent(sntt.Sentence);
1205JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_processNMEA(
1206 JNIEnv *env, jobject obj, jstring nmea_string) {
1212 wxEvtHandler *consumer = s_pAndroidNMEAMessageConsumer;
1214 if (!consumer && g_pMUX) consumer = g_pMUX;
1216 const char *
string = env->GetStringUTFChars(nmea_string, NULL);
1221 strncpy(tstr,
string, 190);
1222 strcat(tstr,
"\r\n");
1238JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_processBTNMEA(
1239 JNIEnv *env, jobject obj, jstring nmea_string) {
1240 const char *
string = env->GetStringUTFChars(nmea_string, NULL);
1241 wxString wstring = wxString(
string, wxConvUTF8);
1244 strncpy(tstr,
string, 190);
1245 strcat(tstr,
"\r\n");
1261JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onConfigChange(
1262 JNIEnv *env, jobject obj,
int orientation) {
1263 g_orientation = orientation;
1264 qDebug() <<
"onConfigChange";
1266 wxLogMessage(_T(
"onConfigChange"));
1267 GetAndroidDisplaySize();
1269 wxSize new_size = getAndroidDisplayDimensions();
1270 qDebug() <<
"NewSize: " << new_size.x << new_size.y;
1271 config_size = new_size;
1277 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1278 evt.SetId(ID_CMD_TRIGGER_RESIZE);
1279 g_androidUtilHandler->AddPendingEvent(evt);
1286JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onMouseWheel(JNIEnv *env,
1289 wxMouseEvent evt(wxEVT_MOUSEWHEEL);
1290 evt.m_wheelRotation = dir;
1292 if (gFrame->GetPrimaryCanvas()) {
1293 gFrame->GetPrimaryCanvas()->GetEventHandler()->AddPendingEvent(evt);
1301JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onMenuKey(JNIEnv *env,
1312JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onStop(JNIEnv *env,
1314 qDebug() <<
"onStop";
1315 wxLogMessage(_T(
"onStop"));
1322 pConfig->UpdateSettings();
1327 pConfig->UpdateNavObj(
true);
1332 qDebug() <<
"onStop return 98";
1338JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onStart(JNIEnv *env,
1340 qDebug() <<
"onStart";
1341 wxLogMessage(_T(
"onStart"));
1343 if (g_bstress1) ShowNavWarning();
1352JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onPause(JNIEnv *env,
1354 qDebug() <<
"onPause";
1355 wxLogMessage(_T(
"onPause"));
1358 callActivityMethod_is(
"setTrackContinuous", (
int)g_btrackContinuous);
1360 if (!g_btrackContinuous) androidGPSService(GPS_OFF);
1367JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onResume(JNIEnv *env,
1369 qDebug() <<
"onResume";
1370 wxLogMessage(_T(
"onResume"));
1376 if (bGPSEnabled) androidGPSService(GPS_ON);
1378 wxCommandEvent evt0(wxEVT_COMMAND_MENU_SELECTED);
1379 evt0.SetId(ID_CMD_CLOSE_ALL_DIALOGS);
1380 if (gFrame && gFrame->GetEventHandler())
1381 gFrame->GetEventHandler()->AddPendingEvent(evt0);
1383 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1384 evt.SetId(ID_CMD_INVALIDATE);
1385 if (gFrame) gFrame->GetEventHandler()->AddPendingEvent(evt);
1388 int orient = androidGetScreenOrientation();
1389 qDebug() <<
"Orient: " << orient;
1390 if (gFrame && gFrame->GetPrimaryCanvas()) {
1391 qDebug() <<
"Size: " << gFrame->GetSize().x << gFrame->GetSize().y;
1392 qDebug() <<
"CanvasSize: " << gFrame->GetPrimaryCanvas()->GetSize().x
1393 << gFrame->GetPrimaryCanvas()->GetSize().y;
1395 if (gFrame->GetSize().y > gFrame->GetSize().x) {
1396 qDebug() <<
"gFrame is Portrait";
1397 if ((orient == 2) || (orient == 4)) {
1398 qDebug() <<
"NEEDS RESIZE";
1399 GetAndroidDisplaySize();
1400 wxSize new_size = getAndroidDisplayDimensions();
1401 qDebug() <<
"NewSize: " << new_size.x << new_size.y;
1402 config_size = new_size;
1404 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1405 evt.SetId(ID_CMD_TRIGGER_RESIZE);
1406 if (g_androidUtilHandler) g_androidUtilHandler->AddPendingEvent(evt);
1409 qDebug() <<
"gFrame is Landscape";
1410 if ((orient == 1) || (orient == 3)) {
1411 qDebug() <<
"NEEDS RESIZE";
1412 GetAndroidDisplaySize();
1413 wxSize new_size = getAndroidDisplayDimensions();
1414 qDebug() <<
"NewSize: " << new_size.x << new_size.y;
1415 config_size = new_size;
1417 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1418 evt.SetId(ID_CMD_TRIGGER_RESIZE);
1419 if (g_androidUtilHandler) g_androidUtilHandler->AddPendingEvent(evt);
1429JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_onDestroy(JNIEnv *env,
1431 qDebug() <<
"onDestroy";
1432 wxLogMessage(_T(
"onDestroy"));
1437 pConfig->UpdateSettings();
1447JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_selectChartDisplay(
1448 JNIEnv *env, jobject obj,
int type,
int family) {
1449 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1450 if (type == CHART_TYPE_CM93COMP) {
1451 evt.SetId(ID_CMD_SELECT_CHART_TYPE);
1452 evt.SetExtraLong(CHART_TYPE_CM93COMP);
1454 evt.SetId(ID_CMD_SELECT_CHART_FAMILY);
1455 evt.SetExtraLong(family);
1458 if (gFrame) gFrame->GetEventHandler()->AddPendingEvent(evt);
1465JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_invokeCmdEventCmdString(
1466 JNIEnv *env, jobject obj,
int cmd_id, jstring s) {
1472 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1475 sparm = (jenv)->GetStringUTFChars(s, NULL);
1476 wx_sparm = wxString(sparm, wxConvUTF8);
1481 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1483 evt.SetString(wx_sparm);
1486 qDebug() <<
"add event" << cmd_id << wx_sparm.mbc_str();
1487 gFrame->GetEventHandler()->AddPendingEvent(evt);
1489 qDebug() <<
"No frame for EventCmdString";
1496JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_invokeMenuItem(
1497 JNIEnv *env, jobject obj,
int item) {
1502 msg1.Printf(_T(
"invokeMenuItem: %d"), item);
1506 if (gFrame && (gFrame->GetFocusCanvas()->m_routeState > 1) &&
1507 (OCPN_ACTION_ROUTE != item)) {
1508 wxLogMessage(_T(
"invokeMenuItem A"));
1512 wxLogMessage(_T(
"invokeMenuItem B"));
1514 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1517 case OCPN_ACTION_FOLLOW:
1518 evt.SetId(ID_MENU_NAV_FOLLOW);
1519 gFrame->GetEventHandler()->AddPendingEvent(evt);
1522 case OCPN_ACTION_ROUTE:
1523 evt.SetId(ID_MENU_ROUTE_NEW);
1524 gFrame->GetEventHandler()->AddPendingEvent(evt);
1527 case OCPN_ACTION_RMD:
1528 evt.SetId(ID_MENU_ROUTE_MANAGER);
1529 gFrame->GetEventHandler()->AddPendingEvent(evt);
1532 case OCPN_ACTION_SETTINGS_BASIC:
1533 evt.SetId(ID_MENU_SETTINGS_BASIC);
1534 wxLogMessage(_T(
"invokeMenuItem OCPN_ACTION_SETTINGS_BASIC"));
1535 gFrame->GetEventHandler()->AddPendingEvent(evt);
1538 case OCPN_ACTION_TRACK_TOGGLE:
1539 evt.SetId(ID_MENU_NAV_TRACK);
1540 gFrame->GetEventHandler()->AddPendingEvent(evt);
1543 case OCPN_ACTION_MOB:
1544 evt.SetId(ID_MENU_MARK_MOB);
1545 gFrame->GetEventHandler()->AddPendingEvent(evt);
1548 case OCPN_ACTION_TIDES_TOGGLE:
1549 evt.SetId(ID_MENU_SHOW_TIDES);
1550 gFrame->GetEventHandler()->AddPendingEvent(evt);
1553 case OCPN_ACTION_CURRENTS_TOGGLE:
1554 evt.SetId(ID_MENU_SHOW_CURRENTS);
1555 gFrame->GetEventHandler()->AddPendingEvent(evt);
1558 case OCPN_ACTION_ENCTEXT_TOGGLE:
1559 evt.SetId(ID_MENU_ENC_TEXT);
1560 gFrame->GetEventHandler()->AddPendingEvent(evt);
1563 case OCPN_ACTION_ENCSOUNDINGS_TOGGLE:
1564 evt.SetId(ID_MENU_ENC_SOUNDINGS);
1565 gFrame->GetEventHandler()->AddPendingEvent(evt);
1568 case OCPN_ACTION_ENCLIGHTS_TOGGLE:
1569 evt.SetId(ID_MENU_ENC_LIGHTS);
1570 gFrame->GetEventHandler()->AddPendingEvent(evt);
1582JNIEXPORT jstring JNICALL
1583Java_org_opencpn_OCPNNativeLib_getVPCorners(JNIEnv *env, jobject obj) {
1588 if (gFrame->GetPrimaryCanvas()) {
1590 vbox = gFrame->GetPrimaryCanvas()->GetVP().GetBBox();
1591 s.Printf(_T(
"%g;%g;%g;%g;"), vbox.GetMaxLat(), vbox.GetMaxLon(),
1592 vbox.GetMinLat(), vbox.GetMinLon());
1595 jstring ret = (env)->NewStringUTF(s.c_str());
1602JNIEXPORT jstring JNICALL Java_org_opencpn_OCPNNativeLib_getVPS(JNIEnv *env,
1606 if (gFrame->GetPrimaryCanvas()) {
1607 ViewPort vp = gFrame->GetPrimaryCanvas()->GetVP();
1608 s.Printf(_T(
"%g;%g;%g;%g;%g;"), vp.clat, vp.clon, vp.view_scale_ppm, gLat,
1612 jstring ret = (env)->NewStringUTF(s.c_str());
1619JNIEXPORT
int JNICALL Java_org_opencpn_OCPNNativeLib_getTLWCount(JNIEnv *env,
1622 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
1624 wxWindow *win = node->GetData();
1625 if (win->IsShown() && !win->IsKindOf(CLASSINFO(
CanvasOptions))) ret++;
1627 node = node->GetNext();
1634JNIEXPORT
int JNICALL Java_org_opencpn_OCPNNativeLib_notifyFullscreenChange(
1635 JNIEnv *env, jobject obj,
bool bFull) {
1636 g_bFullscreen = bFull;
1642JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_setDownloadStatus(
1643 JNIEnv *env, jobject obj,
int status, jstring url) {
1651 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1654 sparm = (jenv)->GetStringUTFChars(url, NULL);
1655 wx_sparm = wxString(sparm, wxConvUTF8);
1658 if (s_bdownloading && wx_sparm.IsSameAs(s_requested_url)) {
1664 OCPN_DLCondition dl_condition = OCPN_DL_EVENT_TYPE_UNKNOWN;
1665 OCPN_DLStatus dl_status = OCPN_DL_UNKNOWN;
1670 dl_condition = OCPN_DL_EVENT_TYPE_END;
1671 dl_status = OCPN_DL_FAILED;
1675 dl_condition = OCPN_DL_EVENT_TYPE_END;
1676 dl_status = OCPN_DL_NO_ERROR;
1682 dl_condition = OCPN_DL_EVENT_TYPE_PROGRESS;
1683 dl_status = OCPN_DL_NO_ERROR;
1686 ev.setDLEventCondition(dl_condition);
1687 ev.setDLEventStatus(dl_status);
1689 if (s_download_evHandler) {
1691 s_download_evHandler->AddPendingEvent(ev);
1700JNIEXPORT jint JNICALL Java_org_opencpn_OCPNNativeLib_sendPluginMessage(
1701 JNIEnv *env, jobject obj, jstring msgID, jstring msg) {
1708 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1711 sparm = (jenv)->GetStringUTFChars(msgID, NULL);
1712 MsgID = wxString(sparm, wxConvUTF8);
1714 sparm = (jenv)->GetStringUTFChars(msg, NULL);
1715 Msg = wxString(sparm, wxConvUTF8);
1718 SendPluginMessage(MsgID, Msg);
1724void androidTerminate() { callActivityMethod_vs(
"terminateApp"); }
1726bool CheckPendingJNIException() {
1729 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK)
return true;
1731 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
1733 (jenv)->ExceptionDescribe();
1734 (jenv)->ExceptionClear();
1744wxString callActivityMethod_vs(
const char *method) {
1745 if (CheckPendingJNIException())
return _T(
"NOK");
1749 wxString return_string;
1750 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1751 "org/qtproject/qt5/android/QtNative",
"activity",
1752 "()Landroid/app/Activity;");
1753 if (CheckPendingJNIException())
return _T(
"NOK");
1755 if (!activity.isValid()) {
1757 return return_string;
1761 QAndroidJniObject data =
1762 activity.callObjectMethod(method,
"()Ljava/lang/String;");
1763 if (CheckPendingJNIException())
return _T(
"NOK");
1765 jstring s = data.object<jstring>();
1770 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1773 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1774 return_string = wxString(ret_string, wxConvUTF8);
1778 return return_string;
1781wxString callActivityMethod_is(
const char *method,
int parm) {
1782 if (CheckPendingJNIException())
return _T(
"NOK");
1785 wxString return_string;
1786 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1787 "org/qtproject/qt5/android/QtNative",
"activity",
1788 "()Landroid/app/Activity;");
1790 if (!activity.isValid()) {
1792 return return_string;
1796 QAndroidJniObject data =
1797 activity.callObjectMethod(method,
"(I)Ljava/lang/String;", parm);
1798 if (CheckPendingJNIException())
return _T(
"NOK");
1800 jstring s = data.object<jstring>();
1803 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1806 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1807 return_string = wxString(ret_string, wxConvUTF8);
1810 return return_string;
1813wxString callActivityMethod_iis(
const char *method,
int parm1,
int parm2) {
1814 if (CheckPendingJNIException())
return _T(
"NOK");
1818 wxString return_string;
1819 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1820 "org/qtproject/qt5/android/QtNative",
"activity",
1821 "()Landroid/app/Activity;");
1822 if (CheckPendingJNIException())
return _T(
"NOK");
1824 if (!activity.isValid()) {
1826 return return_string;
1830 QAndroidJniObject data =
1831 activity.callObjectMethod(method,
"(II)Ljava/lang/String;", parm1, parm2);
1832 if (CheckPendingJNIException())
return _T(
"NOK");
1834 jstring s = data.object<jstring>();
1837 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1840 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1841 return_string = wxString(ret_string, wxConvUTF8);
1844 return return_string;
1847wxString callActivityMethod_ss(
const char *method, wxString parm) {
1848 if (CheckPendingJNIException())
return _T(
"NOK");
1851 wxString return_string;
1852 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1853 "org/qtproject/qt5/android/QtNative",
"activity",
1854 "()Landroid/app/Activity;");
1855 if (CheckPendingJNIException())
return _T(
"NOK");
1857 if (!activity.isValid()) {
1859 return return_string;
1863 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1865 return _T(
"jenv Error");
1868 jstring p = (jenv)->NewStringUTF(parm.c_str());
1874 QAndroidJniObject data = activity.callObjectMethod(
1875 method,
"(Ljava/lang/String;)Ljava/lang/String;", p);
1877 (jenv)->DeleteLocalRef(p);
1879 if (CheckPendingJNIException())
return _T(
"NOK");
1883 jstring s = data.object<jstring>();
1885 if ((jenv)->GetStringLength(s)) {
1886 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1887 return_string = wxString(ret_string, wxConvUTF8);
1890 return return_string;
1893wxString callActivityMethod_s2s(
const char *method,
const wxString parm1,
1894 const wxString parm2) {
1895 if (CheckPendingJNIException())
return _T(
"NOK");
1898 wxString return_string;
1899 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1900 "org/qtproject/qt5/android/QtNative",
"activity",
1901 "()Landroid/app/Activity;");
1902 if (CheckPendingJNIException())
return _T(
"NOK");
1904 if (!activity.isValid()) {
1906 return return_string;
1910 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1912 return _T(
"jenv Error");
1915 wxCharBuffer p1b = parm1.ToUTF8();
1916 jstring p1 = (jenv)->NewStringUTF(p1b.data());
1918 wxCharBuffer p2b = parm2.ToUTF8();
1919 jstring p2 = (jenv)->NewStringUTF(p2b.data());
1924 QAndroidJniObject data = activity.callObjectMethod(
1925 method,
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", p1,
1928 (jenv)->DeleteLocalRef(p1);
1929 (jenv)->DeleteLocalRef(p2);
1931 if (CheckPendingJNIException())
return _T(
"NOK");
1935 jstring s = data.object<jstring>();
1937 if ((jenv)->GetStringLength(s)) {
1938 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1939 return_string = wxString(ret_string, wxConvUTF8);
1942 return return_string;
1945wxString callActivityMethod_s3s(
const char *method, wxString parm1,
1946 wxString parm2, wxString parm3) {
1947 if (CheckPendingJNIException())
return _T(
"NOK");
1950 wxString return_string;
1951 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
1952 "org/qtproject/qt5/android/QtNative",
"activity",
1953 "()Landroid/app/Activity;");
1954 if (CheckPendingJNIException())
return _T(
"NOK");
1956 if (!activity.isValid()) {
1957 return return_string;
1961 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
1962 return _T(
"jenv Error");
1965 wxCharBuffer p1b = parm1.ToUTF8();
1966 jstring p1 = (jenv)->NewStringUTF(p1b.data());
1968 wxCharBuffer p2b = parm2.ToUTF8();
1969 jstring p2 = (jenv)->NewStringUTF(p2b.data());
1971 wxCharBuffer p3b = parm3.ToUTF8();
1972 jstring p3 = (jenv)->NewStringUTF(p3b.data());
1977 QAndroidJniObject data =
1978 activity.callObjectMethod(method,
1979 "(Ljava/lang/String;Ljava/lang/String;Ljava/"
1980 "lang/String;)Ljava/lang/String;",
1982 (jenv)->DeleteLocalRef(p1);
1983 (jenv)->DeleteLocalRef(p2);
1984 (jenv)->DeleteLocalRef(p3);
1986 if (CheckPendingJNIException())
return _T(
"NOK");
1990 jstring s = data.object<jstring>();
1992 if ((jenv)->GetStringLength(s)) {
1993 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
1994 return_string = wxString(ret_string, wxConvUTF8);
1997 return return_string;
2000wxString callActivityMethod_s4s(
const char *method, wxString parm1,
2001 wxString parm2, wxString parm3,
2003 if (CheckPendingJNIException())
return _T(
"NOK");
2006 wxString return_string;
2007 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2008 "org/qtproject/qt5/android/QtNative",
"activity",
2009 "()Landroid/app/Activity;");
2010 if (CheckPendingJNIException())
return _T(
"NOK");
2012 if (!activity.isValid()) {
2014 return return_string;
2018 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2020 return _T(
"jenv Error");
2023 wxCharBuffer p1b = parm1.ToUTF8();
2024 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2026 wxCharBuffer p2b = parm2.ToUTF8();
2027 jstring p2 = (jenv)->NewStringUTF(p2b.data());
2029 wxCharBuffer p3b = parm3.ToUTF8();
2030 jstring p3 = (jenv)->NewStringUTF(p3b.data());
2032 wxCharBuffer p4b = parm4.ToUTF8();
2033 jstring p4 = (jenv)->NewStringUTF(p4b.data());
2041 QAndroidJniObject data = activity.callObjectMethod(
2043 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
2044 "String;)Ljava/lang/String;",
2046 (jenv)->DeleteLocalRef(p1);
2047 (jenv)->DeleteLocalRef(p2);
2048 (jenv)->DeleteLocalRef(p3);
2049 (jenv)->DeleteLocalRef(p4);
2051 if (CheckPendingJNIException())
return _T(
"NOK");
2055 jstring s = data.object<jstring>();
2057 if ((jenv)->GetStringLength(s)) {
2058 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2059 return_string = wxString(ret_string, wxConvUTF8);
2062 return return_string;
2065wxString callActivityMethod_s2s2i(
const char *method, wxString parm1,
2066 wxString parm2,
int parm3,
int parm4) {
2067 if (CheckPendingJNIException())
return _T(
"NOK");
2069 wxString return_string;
2070 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2071 "org/qtproject/qt5/android/QtNative",
"activity",
2072 "()Landroid/app/Activity;");
2073 if (CheckPendingJNIException())
return _T(
"NOK");
2075 if (!activity.isValid()) {
2076 return return_string;
2082 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2084 return _T(
"jenv Error");
2087 wxCharBuffer p1b = parm1.ToUTF8();
2088 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2090 wxCharBuffer p2b = parm2.ToUTF8();
2091 jstring p2 = (jenv)->NewStringUTF(p2b.data());
2096 QAndroidJniObject data = activity.callObjectMethod(
2097 method,
"(Ljava/lang/String;Ljava/lang/String;II)Ljava/lang/String;", p1,
2100 (jenv)->DeleteLocalRef(p1);
2101 (jenv)->DeleteLocalRef(p2);
2103 if (CheckPendingJNIException())
return _T(
"NOK");
2105 jstring s = data.object<jstring>();
2107 if ((jenv)->GetStringLength(s)) {
2108 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2109 return_string = wxString(ret_string, wxConvUTF8);
2112 return return_string;
2115wxString callActivityMethod_ssi(
const char *method, wxString parm1,
int parm2) {
2116 if (CheckPendingJNIException())
return _T(
"NOK");
2118 wxString return_string;
2119 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2120 "org/qtproject/qt5/android/QtNative",
"activity",
2121 "()Landroid/app/Activity;");
2122 if (CheckPendingJNIException())
return _T(
"NOK");
2124 if (!activity.isValid()) {
2125 return return_string;
2131 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2133 return _T(
"jenv Error");
2136 wxCharBuffer p1b = parm1.ToUTF8();
2137 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2139 QAndroidJniObject data = activity.callObjectMethod(
2140 method,
"(Ljava/lang/String;I)Ljava/lang/String;", p1, parm2);
2142 (jenv)->DeleteLocalRef(p1);
2144 if (CheckPendingJNIException())
return _T(
"NOK");
2146 jstring s = data.object<jstring>();
2148 if ((jenv)->GetStringLength(s)) {
2149 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2150 return_string = wxString(ret_string, wxConvUTF8);
2153 return return_string;
2156wxString androidGetAndroidSystemLocale() {
2157 return callActivityMethod_vs(
"getAndroidLocaleString");
2160bool androidGetFullscreen() {
2161 wxString s = callActivityMethod_vs(
"getFullscreen");
2163 return s == _T(
"YES");
2166bool androidSetFullscreen(
bool bFull) {
2167 callActivityMethod_is(
"setFullscreen", (
int)bFull);
2172void androidDisableFullScreen() {
2173 if (g_bFullscreen) {
2174 g_bFullscreenSave =
true;
2175 androidSetFullscreen(
false);
2179void androidRestoreFullScreen() {
2180 if (g_bFullscreenSave) {
2181 g_bFullscreenSave =
false;
2182 androidSetFullscreen(
true);
2186int androidGetScreenOrientation() {
2187 wxString s = callActivityMethod_vs(
"getScreenOrientation");
2193void androidLaunchHelpView() {
2194 qDebug() <<
"androidLaunchHelpView ";
2195 wxString val = callActivityMethod_vs(
"isHelpAvailable");
2196 if (val.IsSameAs(_T(
"YES"))) {
2197 callActivityMethod_vs(
"launchHelpBook");
2200 _(
"OpenCPN Help is not installed.\nWould you like to install from "
2201 "Google PlayStore now?");
2202 if (androidShowSimpleYesNoDialog(_T(
"OpenCPN"), msg))
2203 androidInstallPlaystoreHelp();
2207void androidLaunchBrowser(wxString URL) {
2208 qDebug() <<
"androidLaunchBrowser";
2209 callActivityMethod_ss(
"launchWebView", URL);
2212void androidDisplayTimedToast(wxString message,
int timeMillisec) {
2213 callActivityMethod_ssi(
"showTimedToast", message, timeMillisec);
2216void androidCancelTimedToast() { callActivityMethod_vs(
"cancelTimedToast"); }
2218void androidDisplayToast(wxString message) {
2219 callActivityMethod_ss(
"showToast", message);
2222void androidEnableRotation(
void) {
2226 callActivityMethod_vs(
"EnableRotation");
2229void androidDisableRotation(
void) { callActivityMethod_vs(
"DisableRotation"); }
2231bool androidShowDisclaimer(wxString title, wxString msg) {
2232 if (CheckPendingJNIException())
return false;
2234 wxString return_string;
2235 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2236 "org/qtproject/qt5/android/QtNative",
"activity",
2237 "()Landroid/app/Activity;");
2238 if (CheckPendingJNIException())
return false;
2240 if (!activity.isValid())
return false;
2245 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK)
return false;
2247 wxCharBuffer p1b = title.ToUTF8();
2248 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2251 wxWCharBuffer b = msg.wc_str();
2252 jstring p2 = (jenv)->NewString((jchar *)b.data(), msg.Len() * 2);
2254 QAndroidJniObject data = activity.callObjectMethod(
2256 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", p1, p2);
2258 (jenv)->DeleteLocalRef(p1);
2259 (jenv)->DeleteLocalRef(p2);
2261 if (CheckPendingJNIException())
return false;
2263 jstring s = data.object<jstring>();
2265 if ((jenv)->GetStringLength(s)) {
2266 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2267 return_string = wxString(ret_string, wxConvUTF8);
2270 return (return_string == _T(
"OK"));
2273bool androidShowSimpleOKDialog(wxString title, wxString msg) {
2274 if (CheckPendingJNIException())
return false;
2276 wxString return_string;
2277 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2278 "org/qtproject/qt5/android/QtNative",
"activity",
2279 "()Landroid/app/Activity;");
2280 if (CheckPendingJNIException())
return false;
2282 if (!activity.isValid())
return false;
2287 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK)
return false;
2289 wxCharBuffer p1b = title.ToUTF8();
2290 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2293 wxWCharBuffer b = msg.wc_str();
2294 jstring p2 = (jenv)->NewString((jchar *)b.data(), msg.Len() * 2);
2296 QAndroidJniObject data = activity.callObjectMethod(
2298 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", p1, p2);
2300 (jenv)->DeleteLocalRef(p1);
2301 (jenv)->DeleteLocalRef(p2);
2303 if (CheckPendingJNIException())
return false;
2305 jstring s = data.object<jstring>();
2307 if ((jenv)->GetStringLength(s)) {
2308 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2309 return_string = wxString(ret_string, wxConvUTF8);
2312 return (return_string == _T(
"OK"));
2315bool androidShowSimpleYesNoDialog(wxString title, wxString msg) {
2316 if (CheckPendingJNIException())
return false;
2318 wxString return_string;
2319 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2320 "org/qtproject/qt5/android/QtNative",
"activity",
2321 "()Landroid/app/Activity;");
2322 if (CheckPendingJNIException())
return false;
2324 if (!activity.isValid())
return false;
2329 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK)
return false;
2331 wxCharBuffer p1b = title.ToUTF8();
2332 jstring p1 = (jenv)->NewStringUTF(p1b.data());
2335 wxWCharBuffer b = msg.wc_str();
2336 jstring p2 = (jenv)->NewString((jchar *)b.data(), msg.Len() * 2);
2338 QAndroidJniObject data = activity.callObjectMethod(
2339 "simpleYesNoDialog",
2340 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", p1, p2);
2342 (jenv)->DeleteLocalRef(p1);
2343 (jenv)->DeleteLocalRef(p2);
2345 if (CheckPendingJNIException())
return false;
2347 jstring s = data.object<jstring>();
2349 if ((jenv)->GetStringLength(s)) {
2350 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2351 return_string = wxString(ret_string, wxConvUTF8);
2354 return (return_string == _T(
"YES"));
2357bool androidInstallPlaystoreHelp() {
2358 qDebug() <<
"androidInstallPlaystoreHelp";
2361 if (CheckPendingJNIException())
return false;
2363 wxString return_string;
2364 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2365 "org/qtproject/qt5/android/QtNative",
"activity",
2366 "()Landroid/app/Activity;");
2367 if (CheckPendingJNIException())
return false;
2369 if (!activity.isValid())
return false;
2374 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK)
return false;
2376 QAndroidJniObject data =
2377 activity.callObjectMethod(
"installPlaystoreHelp",
"()Ljava/lang/String;");
2379 if (CheckPendingJNIException())
return false;
2381 jstring s = data.object<jstring>();
2383 if ((jenv)->GetStringLength(s)) {
2384 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2385 return_string = wxString(ret_string, wxConvUTF8);
2388 return (return_string == _T(
"OK"));
2391int androidGetTZOffsetMins() {
2394 wxString result = callActivityMethod_vs(
"getAndroidTZOffsetMinutes");
2395 qDebug() <<
"androidGetTZOffsetMins result: " << result.mb_str();
2397 result.ToLong(&value);
2403wxString androidGetDeviceInfo() {
2404 if (!g_deviceInfo.Length())
2405 g_deviceInfo = callActivityMethod_vs(
"getDeviceInfo");
2407 wxStringTokenizer tkz(g_deviceInfo, _T(
"\n"));
2408 while (tkz.HasMoreTokens()) {
2409 wxString s1 = tkz.GetNextToken();
2410 if (wxNOT_FOUND != s1.Find(_T(
"OS API Level"))) {
2411 int a = s1.Find(_T(
"{"));
2412 if (wxNOT_FOUND != a) {
2413 wxString b = s1.Mid(a + 1, 2);
2414 memset(android_plat_spc.msdk, 0,
sizeof(android_plat_spc.msdk));
2415 strncpy(android_plat_spc.msdk, b.c_str(), 2);
2416 g_Android_SDK_Version = atoi( android_plat_spc.msdk );
2419 if (wxNOT_FOUND != s1.Find(_T(
"opencpn"))) {
2420 strcpy(&android_plat_spc.hn[0], s1.c_str());
2427 if (wxNOT_FOUND != s1.Find(_T(
"SM-T590"))) {
2428 if (!strncmp(android_plat_spc.msdk,
"29",
2430 g_detect_smt590 =
true;
2434 return g_deviceInfo;
2437bool androidIsDirWritable( wxString dir )
2439 if (g_Android_SDK_Version < 30)
2447 return (dir.Contains(
"org.opencpn.opencpn"));
2451wxString androidGetHomeDir() {
return g_androidFilesDir + _T(
"/"); }
2454androidGetPrivateDir()
2456 if (g_bExternalApp) {
2460 public boolean isExternalStorageWritable() {
2461 String state = Environment.getExternalStorageState();
2462 if (Environment.MEDIA_MOUNTED.equals(state)) {
2469 public boolean isExternalStorageReadable() {
2470 String state = Environment.getExternalStorageState();
2471 if (Environment.MEDIA_MOUNTED.equals(state) ||
2472 Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
2478 return g_androidExtFilesDir;
2484 return g_androidExtFilesDir;
2487wxString androidGetSharedDir()
2494 return g_androidExtFilesDir + _T(
"/");
2505 return g_androidExtCacheDir;
2518wxString androidGetExtStorageDir()
2520 if (g_Android_SDK_Version >= 30)
2521 return g_androidExtFilesDir;
2523 return g_androidExtStorageDir;
2526extern void androidSetRouteAnnunciator(
bool viz) {
2527 callActivityMethod_is(
"setRouteAnnunciator", viz ? 1 : 0);
2530extern void androidSetFollowTool(
int state,
bool forceUpdate) {
2533 if ((g_follow_state != state) || forceUpdate)
2534 callActivityMethod_is(
"setFollowIconState", state);
2536 g_follow_state = state;
2539extern void androidSetTrackTool(
bool bactive) {
2540 if (g_track_active != bactive)
2541 callActivityMethod_is(
"setTrackIconState", bactive ? 1 : 0);
2543 g_track_active = bactive;
2546void androidSetChartTypeMaskSel(
int mask, wxString &indicator) {
2548 if (wxNOT_FOUND != indicator.Find(_T(
"raster")))
2550 else if (wxNOT_FOUND != indicator.Find(_T(
"vector")))
2552 else if (wxNOT_FOUND != indicator.Find(_T(
"cm93")))
2555 if ((g_mask != mask) || (g_sel != sel)) {
2557 callActivityMethod_iis(
"configureNavSpinnerTS", mask, sel);
2563void androidEnableBackButton(
bool benable) {
2564 callActivityMethod_is(
"setBackButtonState", benable ? 1 : 0);
2565 g_backEnabled = benable;
2568void androidEnableBackButtonCheck(
bool benable) {
2569 if (g_backEnabled != benable) androidEnableBackButton(benable);
2572void androidEnableOptionItems(
bool benable) {
2573 callActivityMethod_is(
"enableOptionItemAction", benable ? 1 : 0);
2576void androidEnableMulticast(
bool benable) {
2577 callActivityMethod_is(
"enableMulticast", benable ? 1 : 0);
2580void androidLastCall(
void) {
2581 CheckMigrateCharts();
2582 callActivityMethod_is(
"lastCallOnInit", 1);
2585bool androidGetMemoryStatus(
int *mem_total,
int *mem_used) {
2588 if (mem_total) *mem_total = s_androidMemTotal * 1024;
2589 if (mem_used) *mem_used = s_androidMemUsed * 1024;
2595 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
"org/qtproject/qt5/android/QtNative",
2596 "activity",
"()Landroid/app/Activity;");
2598 if ( !activity.isValid() ){
2599 qDebug() <<
"Activity is not valid";
2603 unsigned long android_processID = wxGetProcessId();
2606 QAndroidJniObject data = activity.callObjectMethod(
"getMemInfo",
"(I)Ljava/lang/String;", (
int)android_processID);
2609 jstring s = data.object<jstring>();
2613 if (java_vm->GetEnv( (
void **) &jenv, JNI_VERSION_1_6) != JNI_OK) {
2614 qDebug() <<
"GetEnv failed.";
2617 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2618 mu = atoi(ret_string);
2630double GetAndroidDisplaySize() {
2634 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2635 "org/qtproject/qt5/android/QtNative",
"activity",
2636 "()Landroid/app/Activity;");
2638 if (!activity.isValid()) {
2644 QAndroidJniObject data =
2645 activity.callObjectMethod(
"getDisplayMetrics",
"()Ljava/lang/String;");
2647 wxString return_string;
2648 jstring s = data.object<jstring>();
2652 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2655 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2656 return_string = wxString(ret_string, wxConvUTF8);
2661 return_string.Replace(_T(
","), _T(
"."));
2663 wxSize screen_size = wxSize(1, 2);
2665 if (QApplication::desktop()) {
2666 screen_size = ::wxGetDisplaySize();
2676 double density = 1.0;
2677 long androidWidth = 2;
2678 long androidHeight = 1;
2679 long androidDmWidth = 2;
2680 long androidDmHeight = 1;
2683 wxStringTokenizer tk(return_string, _T(
";"));
2684 if (tk.HasMoreTokens()) {
2685 wxString token = tk.GetNextToken();
2686 token = tk.GetNextToken();
2688 token.ToDouble(&density);
2690 token = tk.GetNextToken();
2692 token = tk.GetNextToken();
2693 token.ToLong(&androidWidth);
2694 token = tk.GetNextToken();
2695 token = tk.GetNextToken();
2696 token = tk.GetNextToken();
2697 token.ToLong(&androidHeight);
2699 token = tk.GetNextToken();
2700 token.ToLong(&androidDmWidth);
2701 token = tk.GetNextToken();
2702 token.ToLong(&androidDmHeight);
2704 token = tk.GetNextToken();
2708 double ldpi = 160. * density;
2709 if (ldpi < 160) ldpi = 160.;
2716 double maxDim = screen_size.x;
2717 maxDim = wxMax(maxDim, androidWidth);
2719 ret = (maxDim / ldpi) * 25.4;
2722 double ret_bad = ret;
2725 _T(
"WARNING: Android Auto Display Size OVERRIDE_TOO_SMALL: %g ldpi: ")
2726 _T(
"%g density: %g correctedsize: %g "),
2727 ret_bad, ldpi, density, ret);
2728 }
else if (ret > 400) {
2729 double ret_bad = ret;
2732 _T(
"WARNING: Android Auto Display Size OVERRIDE_TOO_LARGE: %g ldpi: ")
2733 _T(
"%g density: %g corrected size: %g"),
2734 ret_bad, ldpi, density, ret);
2737 _T(
"Android Auto Display Size (mm, est.): %g ldpi: %g density: %g"),
2738 ret, ldpi, density);
2742 g_androidDPmm = ldpi / 25.4;
2743 g_androidDensity = density;
2744 g_ActionBarHeight = wxMax(abh, 50);
2751int getAndroidActionBarHeight() {
return g_ActionBarHeight; }
2753double getAndroidDPmm() {
2755 GetAndroidDisplaySize();
2760 if (g_config_display_size_manual && (g_config_display_size_mm > 0)) {
2761 double maxDim = wxMax(::wxGetDisplaySize().x, ::wxGetDisplaySize().y);
2762 double size_mm = g_config_display_size_mm;
2763 size_mm = wxMax(size_mm, 50);
2764 size_mm = wxMin(size_mm, 400);
2765 double ret = maxDim / size_mm;
2772 if (g_androidDPmm > 0.01)
2773 return g_androidDPmm;
2778double getAndroidDisplayDensity() {
2779 if (g_androidDensity < 0.01) {
2780 GetAndroidDisplaySize();
2785 if (g_androidDensity > 0.01)
2786 return g_androidDensity;
2791wxSize getAndroidDisplayDimensions(
void) {
2792 wxSize sz_ret = ::wxGetDisplaySize();
2795 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2796 "org/qtproject/qt5/android/QtNative",
"activity",
2797 "()Landroid/app/Activity;");
2799 if (!activity.isValid()) {
2805 QAndroidJniObject data =
2806 activity.callObjectMethod(
"getDisplayMetrics",
"()Ljava/lang/String;");
2808 wxString return_string;
2809 jstring s = data.object<jstring>();
2813 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2816 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2817 return_string = wxString(ret_string, wxConvUTF8);
2821 wxStringTokenizer tk(return_string, _T(
";"));
2822 if (tk.HasMoreTokens()) {
2823 wxString token = tk.GetNextToken();
2824 token = tk.GetNextToken();
2825 token = tk.GetNextToken();
2827 token = tk.GetNextToken();
2829 if (token.ToLong(&a)) sz_ret.x = a;
2831 token = tk.GetNextToken();
2833 if (token.ToLong(&b)) sz_ret.y = b;
2834 token = tk.GetNextToken();
2835 token = tk.GetNextToken();
2837 token = tk.GetNextToken();
2838 token = tk.GetNextToken();
2841 token = tk.GetNextToken();
2842 if (token.ToLong(&abh)) sz_ret.y -= abh;
2846 if (g_detect_smt590) {
2847 if (sz_ret.x < sz_ret.y) sz_ret.y = 1650;
2855void androidConfirmSizeCorrection() {
2860 wxLogMessage(_T(
"androidConfirmSizeCorrection"));
2861 wxSize targetSize = getAndroidDisplayDimensions();
2862 qDebug() <<
"Confirming" << targetSize.y << config_size.y;
2863 if (config_size != targetSize) {
2864 qDebug() <<
"Correcting";
2865 gFrame->SetSize(targetSize);
2866 config_size = targetSize;
2870void androidForceFullRepaint(
bool b_skipConfirm) {
2871 wxLogMessage(_T(
"androidForceFullRepaint"));
2872 wxSize targetSize = getAndroidDisplayDimensions();
2873 wxSize tempSize = targetSize;
2875 gFrame->SetSize(tempSize);
2877 GetAndroidDisplaySize();
2879 wxSize new_size = getAndroidDisplayDimensions();
2880 config_size = new_size;
2882 g_androidUtilHandler->m_bskipConfirm = b_skipConfirm;
2884 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
2885 evt.SetId(ID_CMD_TRIGGER_RESIZE);
2886 if (gFrame && gFrame->GetEventHandler()) {
2887 g_androidUtilHandler->AddPendingEvent(evt);
2891void androidShowBusyIcon() {
2892 if (b_androidBusyShown)
return;
2897 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2898 "org/qtproject/qt5/android/QtNative",
"activity",
2899 "()Landroid/app/Activity;");
2900 if (!activity.isValid()) {
2906 QAndroidJniObject data =
2907 activity.callObjectMethod(
"showBusyCircle",
"()Ljava/lang/String;");
2909 b_androidBusyShown =
true;
2912void androidHideBusyIcon() {
2913 if (!b_androidBusyShown)
return;
2916 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2917 "org/qtproject/qt5/android/QtNative",
"activity",
2918 "()Landroid/app/Activity;");
2920 if (!activity.isValid()) {
2926 QAndroidJniObject data =
2927 activity.callObjectMethod(
"hideBusyCircle",
"()Ljava/lang/String;");
2929 b_androidBusyShown =
false;
2932int androidGetVersionCode() {
2934 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2935 "org/qtproject/qt5/android/QtNative",
"activity",
2936 "()Landroid/app/Activity;");
2938 if (!activity.isValid()) {
2944 QAndroidJniObject data = activity.callObjectMethod(
"getAndroidVersionCode",
2945 "()Ljava/lang/String;");
2947 wxString return_string;
2948 jstring s = data.object<jstring>();
2952 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2955 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2956 return_string = wxString(ret_string, wxConvUTF8);
2960 return_string.ToLong(&rv);
2965wxString androidGetVersionName() {
2967 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2968 "org/qtproject/qt5/android/QtNative",
"activity",
2969 "()Landroid/app/Activity;");
2971 if (!activity.isValid()) {
2977 QAndroidJniObject data = activity.callObjectMethod(
"getAndroidVersionName",
2978 "()Ljava/lang/String;");
2980 wxString return_string;
2981 jstring s = data.object<jstring>();
2985 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2988 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2989 return_string = wxString(ret_string, wxConvUTF8);
2992 return return_string;
2998bool androidDeviceHasGPS() {
2999 wxString query = androidGPSService(GPS_PROVIDER_AVAILABLE);
3000 wxLogMessage(query);
3002 bool result = query.Upper().IsSameAs(_T(
"YES"));
3005 wxLogMessage(_T(
"Android Device has internal GPS"));
3008 wxLogMessage(_T(
"Android Device has NO internal GPS"));
3013bool androidStartNMEA(wxEvtHandler *consumer) {
3014 s_pAndroidNMEAMessageConsumer = consumer;
3019 s = androidGPSService(GPS_ON);
3021 if (s.Upper().Find(_T(
"DISABLED")) != wxNOT_FOUND) {
3023 NULL, _(
"Your android device has an internal GPS, but it is disabled.\n\
3024 Please visit android Settings/Location dialog to enable GPS"),
3025 _T(
"OpenCPN"), wxOK);
3035bool androidStopNMEA() {
3036 s_pAndroidNMEAMessageConsumer = NULL;
3038 wxString s = androidGPSService(GPS_OFF);
3040 bGPSEnabled =
false;
3045wxString androidGPSService(
int parm) {
3046 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
3047 "org/qtproject/qt5/android/QtNative",
"activity",
3048 "()Landroid/app/Activity;");
3050 if (!activity.isValid()) {
3052 return _T(
"Activity is not valid");
3056 QAndroidJniObject data = activity.callObjectMethod(
3057 "queryGPSServer",
"(I)Ljava/lang/String;", parm);
3059 wxString return_string;
3060 jstring s = data.object<jstring>();
3062 if (s == NULL)
return return_string;
3066 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
3069 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
3070 return_string = wxString(ret_string, wxConvUTF8);
3073 return return_string;
3076bool androidDeviceHasBlueTooth() {
3077 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
3078 "org/qtproject/qt5/android/QtNative",
"activity",
3079 "()Landroid/app/Activity;");
3081 if (!activity.isValid()) {
3083 return _T(
"Activity is not valid");
3087 QAndroidJniObject data =
3088 activity.callObjectMethod(
"hasBluetooth",
"(I)Ljava/lang/String;", 0);
3091 jstring s = data.object<jstring>();
3095 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
3098 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
3099 query = wxString(ret_string, wxConvUTF8);
3102 bool result = query.Upper().IsSameAs(_T(
"YES"));
3106 wxLogMessage(_T(
"Android Device has internal Bluetooth"));
3109 wxLogMessage(_T(
"Android Device has NO internal Bluetooth"));
3115bool androidStartBluetoothScan() {
3116 wxString result = callActivityMethod_is(
"startBlueToothScan", 0);
3121bool androidStopBluetoothScan() {
3122 wxString result = callActivityMethod_is(
"stopBlueToothScan", 0);
3127bool androidStartBT(wxEvtHandler *consumer, wxString mac_address) {
3128 s_pAndroidBTNMEAMessageConsumer = consumer;
3130 if (mac_address.Find(
':') ==
3134 wxString result = callActivityMethod_ss(
"startBTService", mac_address);
3139bool androidStopBT() {
3142 s_pAndroidBTNMEAMessageConsumer = NULL;
3144 wxString result = callActivityMethod_is(
"stopBTService", 0);
3149wxArrayString androidGetBluetoothScanResults() {
3150 wxArrayString ret_array;
3152 wxString result = callActivityMethod_is(
"getBlueToothScanResults", 0);
3154 wxStringTokenizer tk(result, _T(
";"));
3155 while (tk.HasMoreTokens()) {
3156 wxString token = tk.GetNextToken();
3157 ret_array.Add(token);
3160 if (!ret_array.GetCount()) ret_array.Add(_(
"Nothing found"));
3165bool androidSendBTMessage(wxString &payload) {
3166 wxString result = callActivityMethod_ss(
"sendBTMessage", payload);
3171bool androidCheckOnline() {
3172 wxString val = callActivityMethod_vs(
"isNetworkAvailable");
3173 return val.IsSameAs(_T(
"YES"));
3176wxArrayString *androidGetSerialPortsArray(
void) {
3177 wxArrayString *pret_array =
new wxArrayString;
3178 wxString result = callActivityMethod_is(
"scanSerialPorts", 0);
3180 wxStringTokenizer tk(result, _T(
";"));
3181 while (tk.HasMoreTokens()) {
3182 wxString token = tk.GetNextToken();
3183 pret_array->Add(token);
3189bool androidStartUSBSerial(wxString &portname, wxString baudRate,
3190 wxEvtHandler *consumer) {
3192 callActivityMethod_s2s(
"startSerialPort", portname, baudRate);
3194 s_pAndroidNMEAMessageConsumer = consumer;
3199bool androidStopUSBSerial(wxString &portname) {
3200 s_pAndroidNMEAMessageConsumer = NULL;
3206 if (!b_inCloseWindow)
3207 wxString result = callActivityMethod_ss(
"stopSerialPort", portname);
3212bool androidWriteSerial(wxString &portname, wxString &message) {
3214 callActivityMethod_s2s(
"writeSerialPort", portname, message);
3218int androidFileChooser(wxString *result,
const wxString &initDir,
3219 const wxString &title,
const wxString &suggestion,
3220 const wxString &wildcard,
bool dirOnly,
bool addFile) {
3224 if (g_androidUtilHandler) {
3225 g_androidUtilHandler->m_eventTimer.Stop();
3226 g_androidUtilHandler->m_done =
false;
3228 wxString activityResult;
3230 activityResult = callActivityMethod_s2s2i(
"DirChooserDialog", initDir,
3234 activityResult = callActivityMethod_s4s(
"FileChooserDialog", initDir,
3235 title, suggestion, wildcard);
3237 if (activityResult == _T(
"OK")) {
3239 g_androidUtilHandler->m_action = ACTION_FILECHOOSER_END;
3240 g_androidUtilHandler->m_eventTimer.Start(1000, wxTIMER_CONTINUOUS);
3243 while (!g_androidUtilHandler->m_done) {
3245 wxSafeYield(NULL,
true);
3249 g_androidUtilHandler->m_action = ACTION_NONE;
3250 g_androidUtilHandler->m_eventTimer.Stop();
3252 tresult = g_androidUtilHandler->GetStringResult();
3254 if (tresult.StartsWith(_T(
"cancel:"))) {
3257 }
else if (tresult.StartsWith(_T(
"file:"))) {
3259 *result = tresult.AfterFirst(
':');
3275bool InvokeJNIPreferences(wxString &initial_settings) {
3277 wxCharBuffer abuf = initial_settings.ToUTF8();
3278 if (!abuf.data())
return false;
3281 QAndroidJniObject param1 = QAndroidJniObject::fromString(abuf.data());
3284 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
3285 "org/qtproject/qt5/android/QtNative",
"activity",
3286 "()Landroid/app/Activity;");
3288 if (!activity.isValid()) {
3294 activity.callObjectMethod(
"doAndroidSettings",
3295 "(Ljava/lang/String;)Ljava/lang/String;",
3296 param1.object<jstring>());
3301wxString BuildAndroidSettingsString(
void) {
3306 wxArrayString chart_dir_array = ChartData->GetChartDirArrayString();
3308 for (
unsigned int i = 0; i < chart_dir_array.GetCount(); i++) {
3309 result += _T(
"ChartDir:");
3310 result += chart_dir_array[i];
3316 result += _T(
"prefb_lookahead:") +
3317 wxString(g_bLookAhead == 1 ? _T(
"1;") : _T(
"0;"));
3319 _T(
"prefb_quilt:") + wxString(g_bQuiltEnable == 1 ? _T(
"1;") : _T(
"0;"));
3320 result += _T(
"prefb_showgrid:") +
3321 wxString(g_bDisplayGrid == 1 ? _T(
"1;") : _T(
"0;"));
3322 result += _T(
"prefb_showoutlines:") +
3323 wxString(g_bShowOutlines == 1 ? _T(
"1;") : _T(
"0;"));
3324 result += _T(
"prefb_showdepthunits:") +
3325 wxString(g_bShowDepthUnits == 1 ? _T(
"1;") : _T(
"0;"));
3326 result += _T(
"prefb_lockwp:") +
3327 wxString(g_bWayPointPreventDragging == 1 ? _T(
"1;") : _T(
"0;"));
3328 result += _T(
"prefb_confirmdelete:") +
3329 wxString(g_bConfirmObjectDelete == 1 ? _T(
"1;") : _T(
"0;"));
3330 result += _T(
"prefb_expertmode:") +
3331 wxString(g_bUIexpert == 1 ? _T(
"1;") : _T(
"0;"));
3334 result += _T(
"prefb_showlightldesc:") +
3335 wxString(ps52plib->m_bShowLdisText == 1 ? _T(
"1;") : _T(
"0;"));
3336 result += _T(
"prefb_showimptext:") +
3337 wxString(ps52plib->m_bShowS57ImportantTextOnly == 1 ? _T(
"1;")
3339 result += _T(
"prefb_showSCAMIN:") +
3340 wxString(ps52plib->m_bUseSCAMIN == 1 ? _T(
"1;") : _T(
"0;"));
3341 result += _T(
"prefb_showsound:") +
3342 wxString(ps52plib->m_bShowSoundg == 1 ? _T(
"1;") : _T(
"0;"));
3343 result += _T(
"prefb_showATONLabels:") +
3344 wxString(ps52plib->m_bShowAtonText == 1 ? _T(
"1;") : _T(
"0;"));
3347 result += _T(
"prefs_navmode:") +
3348 wxString(g_bCourseUp == 0 ? _T(
"North Up;") : _T(
"Course Up;"));
3349 result += _T(
"prefs_chartInitDir:") + *pInit_Chart_Dir + _T(
";");
3352 double sf = (g_GUIScaleFactor * 10) + 50.;
3353 s.Printf(_T(
"%3.0f;"), sf);
3355 result += _T(
"prefs_UIScaleFactor:") + s;
3357 sf = (g_ChartScaleFactor * 10) + 50.;
3358 s.Printf(_T(
"%3.0f;"), sf);
3360 result += _T(
"prefs_chartScaleFactor:") + s;
3363 wxString nset = _T(
"Base");
3364 switch (ps52plib->GetDisplayCategory()) {
3369 nset = _T(
"Standard;");
3374 case (MARINERS_STANDARD):
3375 nset = _T(
"Mariner Standard;");
3381 result += _T(
"prefs_displaycategory:") + nset;
3383 if (ps52plib->m_nSymbolStyle == PAPER_CHART)
3384 nset = _T(
"Paper Chart;");
3386 nset = _T(
"Simplified;");
3387 result += _T(
"prefs_vectorgraphicsstyle:") + nset;
3389 if (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES)
3390 nset = _T(
"Plain;");
3392 nset = _T(
"Symbolized;");
3393 result += _T(
"prefs_vectorboundarystyle:") + nset;
3395 if (S52_getMarinerParam(S52_MAR_TWO_SHADES) == 1.0)
3399 result += _T(
"prefs_vectorchartcolors:") + nset;
3404 int depthUnit = ps52plib->m_nDepthUnitDisplay;
3407 else if (depthUnit == 2)
3410 s.Printf(_T(
"%4.2f;"), S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) / conv);
3412 result += _T(
"prefs_shallowdepth:") + s;
3414 s.Printf(_T(
"%4.2f;"), S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) / conv);
3416 result += _T(
"prefs_safetydepth:") + s;
3418 s.Printf(_T(
"%4.2f;"), S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) / conv);
3420 result += _T(
"prefs_deepdepth:") + s;
3430 for (
size_t i = 0; i < TheConnectionParams()->Count(); i++) {
3432 if (INTERNAL_GPS == cp->Type) {
3433 result += _T(
"prefb_internalGPS:");
3434 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3436 if (SERIAL == cp->Type) {
3437 if (wxNOT_FOUND != cp->GetPortStr().Find(_T(
"PL2303"))) {
3438 result += _T(
"prefb_PL2303:");
3439 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3440 }
else if (wxNOT_FOUND != cp->GetPortStr().Find(_T(
"dAISy"))) {
3441 result += _T(
"prefb_dAISy:");
3442 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3443 }
else if (wxNOT_FOUND != cp->GetPortStr().Find(_T(
"FT232R"))) {
3444 result += _T(
"prefb_FT232R:");
3445 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3446 }
else if (wxNOT_FOUND != cp->GetPortStr().Find(_T(
"FT231X"))) {
3447 result += _T(
"prefb_FT231X:");
3448 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3449 }
else if (wxNOT_FOUND != cp->GetPortStr().Find(_T(
"USBDP"))) {
3450 result += _T(
"prefb_USBDP:");
3451 result += cp->bEnabled ? _T(
"1;") : _T(
"0;");
3456 wxLogMessage(_T(
"BuildAndroidSettingsString: ") + result);
3461const wxString AUSBNames[] = {
3462 _T(
"AUSBSerial:Prolific_PL2303"), _T(
"AUSBSerial:FTDI_FT232R"),
3463 _T(
"AUSBSerial:FTDI_FT231X"), _T(
"AUSBSerial:dAISy"),
3464 _T(
"AUSBSerial:USBDP"), _T(
"LASTENTRY")};
3465const wxString AUSBPrefs[] = {_T(
"prefb_PL2303"), _T(
"prefb_FT232R"),
3466 _T(
"prefb_FT231X"), _T(
"prefb_dAISy"),
3467 _T(
"prefb_USBDP"), _T(
"LASTENTRY")};
3469int androidApplySettingsString(wxString settings, ArrayOfCDI *pACDI) {
3471 bool bproc_InternalGPS =
false;
3472 bool benable_InternalGPS =
false;
3474 int rr = GENERIC_CHANGED;
3479 wxStringTokenizer tkd(settings, _T(
";"));
3480 while (tkd.HasMoreTokens()) {
3481 wxString token = tkd.GetNextToken();
3483 if (token.StartsWith(_T(
"ChartDir"))) {
3484 wxString dir = token.AfterFirst(
':');
3487 cdi.fullpath = dir.Trim();
3488 cdi.magic_number = ChartData->GetMagicNumberCached(dir.Trim());
3495 if (!ChartData->CompareChartDirArray(*pACDI)) {
3497 rr |= CHANGE_CHARTS;
3498 wxLogMessage(_T(
"Chart Dir List change detected"));
3502 wxStringTokenizer tk(settings, _T(
";"));
3503 while (tk.HasMoreTokens()) {
3504 wxString token = tk.GetNextToken();
3505 wxString val = token.AfterFirst(
':');
3509 if (token.StartsWith(_T(
"prefb_lookahead"))) {
3510 g_bLookAhead = val.IsSameAs(_T(
"1"));
3511 }
else if (token.StartsWith(_T(
"prefb_quilt"))) {
3512 g_bQuiltEnable = val.IsSameAs(_T(
"1"));
3513 }
else if (token.StartsWith(_T(
"prefb_lockwp"))) {
3514 g_bWayPointPreventDragging = val.IsSameAs(_T(
"1"));
3515 }
else if (token.StartsWith(_T(
"prefb_showdepthunits"))) {
3516 g_bShowDepthUnits = val.IsSameAs(_T(
"1"));
3517 }
else if (token.StartsWith(_T(
"prefb_confirmdelete"))) {
3518 g_bConfirmObjectDelete = val.IsSameAs(_T(
"1"));
3519 }
else if (token.StartsWith(_T(
"prefb_showgrid"))) {
3520 g_bDisplayGrid = val.IsSameAs(_T(
"1"));
3521 }
else if (token.StartsWith(_T(
"prefb_showoutlines"))) {
3522 g_bShowOutlines = val.IsSameAs(_T(
"1"));
3523 }
else if (token.StartsWith(_T(
"prefb_expertmode"))) {
3524 g_bUIexpert = val.IsSameAs(_T(
"1"));
3525 }
else if (token.StartsWith(_T(
"prefb_internalGPS"))) {
3526 bproc_InternalGPS =
true;
3527 benable_InternalGPS = val.IsSameAs(_T(
"1"));
3528 }
else if (token.StartsWith(_T(
"prefs_navmode"))) {
3529 g_bCourseUp = val.IsSameAs(_T(
"Course Up"));
3530 }
else if (token.StartsWith(_T(
"prefb_trackOnPause"))) {
3531 g_btrackContinuous = val.IsSameAs(_T(
"1"));
3536 else if (token.StartsWith(_T(
"prefs_UIScaleFactor"))) {
3538 if (val.ToDouble(&a)) g_GUIScaleFactor = wxRound((a / 10.) - 5.);
3541 else if (token.StartsWith(_T(
"prefs_chartScaleFactor"))) {
3543 if (val.ToDouble(&a)) {
3544 g_ChartScaleFactor = wxRound((a / 10.) - 5.);
3545 g_ChartScaleFactorExp =
3546 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
3550 else if (token.StartsWith(_T(
"prefs_chartInitDir"))) {
3551 *pInit_Chart_Dir = val;
3556 int depthUnit = ps52plib->m_nDepthUnitDisplay;
3559 else if (depthUnit == 2)
3562 if (token.StartsWith(_T(
"prefb_showsound"))) {
3563 bool old_val = ps52plib->m_bShowSoundg;
3564 ps52plib->m_bShowSoundg = val.IsSameAs(_T(
"1"));
3565 if (old_val != ps52plib->m_bShowSoundg) rr |= S52_CHANGED;
3566 }
else if (token.StartsWith(_T(
"prefb_showSCAMIN"))) {
3567 bool old_val = ps52plib->m_bUseSCAMIN;
3568 ps52plib->m_bUseSCAMIN = val.IsSameAs(_T(
"1"));
3569 if (old_val != ps52plib->m_bUseSCAMIN) rr |= S52_CHANGED;
3570 }
else if (token.StartsWith(_T(
"prefb_showimptext"))) {
3571 bool old_val = ps52plib->m_bShowS57ImportantTextOnly;
3572 ps52plib->m_bShowS57ImportantTextOnly = val.IsSameAs(_T(
"1"));
3573 if (old_val != ps52plib->m_bShowS57ImportantTextOnly) rr |= S52_CHANGED;
3574 }
else if (token.StartsWith(_T(
"prefb_showlightldesc"))) {
3575 bool old_val = ps52plib->m_bShowLdisText;
3576 ps52plib->m_bShowLdisText = val.IsSameAs(_T(
"1"));
3577 if (old_val != ps52plib->m_bShowLdisText) rr |= S52_CHANGED;
3578 }
else if (token.StartsWith(_T(
"prefb_showATONLabels"))) {
3579 bool old_val = ps52plib->m_bShowAtonText;
3580 ps52plib->m_bShowAtonText = val.IsSameAs(_T(
"1"));
3581 if (old_val != ps52plib->m_bShowAtonText) rr |= S52_CHANGED;
3584 else if (token.StartsWith(_T(
"prefs_displaycategory"))) {
3585 _DisCat old_nset = ps52plib->GetDisplayCategory();
3587 _DisCat nset = DISPLAYBASE;
3588 if (wxNOT_FOUND != val.Lower().Find(_T(
"base")))
3590 else if (wxNOT_FOUND != val.Lower().Find(_T(
"mariner")))
3591 nset = MARINERS_STANDARD;
3592 else if (wxNOT_FOUND != val.Lower().Find(_T(
"standard")))
3594 else if (wxNOT_FOUND != val.Lower().Find(_T(
"all")))
3597 if (nset != old_nset) {
3599 ps52plib->SetDisplayCategory(nset);
3603 else if (token.StartsWith(_T(
"prefs_shallowdepth"))) {
3604 double old_dval = S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR);
3606 if (val.ToDouble(&dval)) {
3607 if (fabs(dval - old_dval) > .001) {
3608 S52_setMarinerParam(S52_MAR_SHALLOW_CONTOUR, dval * conv);
3614 else if (token.StartsWith(_T(
"prefs_safetydepth"))) {
3615 double old_dval = S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
3617 if (val.ToDouble(&dval)) {
3618 if (fabs(dval - old_dval) > .001) {
3619 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, dval * conv);
3625 else if (token.StartsWith(_T(
"prefs_deepdepth"))) {
3626 double old_dval = S52_getMarinerParam(S52_MAR_DEEP_CONTOUR);
3628 if (val.ToDouble(&dval)) {
3629 if (fabs(dval - old_dval) > .001) {
3630 S52_setMarinerParam(S52_MAR_DEEP_CONTOUR, dval * conv);
3636 else if (token.StartsWith(_T(
"prefs_vectorgraphicsstyle"))) {
3637 LUPname old_LUP = ps52plib->m_nSymbolStyle;
3639 if (wxNOT_FOUND != val.Lower().Find(_T(
"paper")))
3640 ps52plib->m_nSymbolStyle = PAPER_CHART;
3641 else if (wxNOT_FOUND != val.Lower().Find(_T(
"simplified")))
3642 ps52plib->m_nSymbolStyle = SIMPLIFIED;
3644 if (old_LUP != ps52plib->m_nSymbolStyle) rr |= S52_CHANGED;
3648 else if (token.StartsWith(_T(
"prefs_vectorboundarystyle"))) {
3649 LUPname old_LUP = ps52plib->m_nBoundaryStyle;
3651 if (wxNOT_FOUND != val.Lower().Find(_T(
"plain")))
3652 ps52plib->m_nBoundaryStyle = PLAIN_BOUNDARIES;
3653 else if (wxNOT_FOUND != val.Lower().Find(_T(
"symbolized")))
3654 ps52plib->m_nBoundaryStyle = SYMBOLIZED_BOUNDARIES;
3656 if (old_LUP != ps52plib->m_nBoundaryStyle) rr |= S52_CHANGED;
3660 else if (token.StartsWith(_T(
"prefs_vectorchartcolors"))) {
3661 double old_dval = S52_getMarinerParam(S52_MAR_TWO_SHADES);
3663 if (wxNOT_FOUND != val.Lower().Find(_T(
"2")))
3664 S52_setMarinerParam(S52_MAR_TWO_SHADES, 1.);
3665 else if (wxNOT_FOUND != val.Lower().Find(_T(
"4")))
3666 S52_setMarinerParam(S52_MAR_TWO_SHADES, 0.);
3668 double new_dval = S52_getMarinerParam(S52_MAR_TWO_SHADES);
3669 if (fabs(new_dval - old_dval) > .1) {
3677 if (bproc_InternalGPS) {
3682 for (
size_t i = 0; i < TheConnectionParams()->Count(); i++) {
3684 if (INTERNAL_GPS == xcp->Type) {
3685 pExistingParams = xcp;
3691 bool b_action =
true;
3692 if (pExistingParams) {
3693 if (pExistingParams->bEnabled == benable_InternalGPS)
3696 cp->bEnabled = benable_InternalGPS;
3697 }
else if (benable_InternalGPS) {
3699 wxString sGPS = _T(
"2;3;;0;0;;0;1;0;0;;0;;1;0;0;0;0");
3702 new_params->bEnabled = benable_InternalGPS;
3703 TheConnectionParams()->Add(new_params);
3707 if (b_action && cp) {
3712 DataStream *pds_existing = g_pMUX->FindStream(cp->GetDSPort());
3713 if (pds_existing) g_pMUX->StopAndRemoveStream(pds_existing);
3716 dsPortType port_type = cp->IOSelect;
3718 makeSerialDataStream(g_pMUX, cp->Type, cp->GetDSPort(),
3719 wxString::Format(wxT(
"%i"), cp->Baudrate),
3720 port_type, cp->Priority, cp->Garmin);
3723 DataStream *dstr =
new DataStream( g_pMUX,
3726 wxString::Format(wxT(
"%i"), cp->Baudrate),
3731 dstr->SetInputFilter(cp->InputSentenceList);
3732 dstr->SetInputFilterType(cp->InputSentenceListType);
3733 dstr->SetOutputFilter(cp->OutputSentenceList);
3734 dstr->SetOutputFilterType(cp->OutputSentenceListType);
3735 dstr->SetChecksumCheck(cp->ChecksumCheck);
3737 g_pMUX->AddStream(dstr);
3739 cp->b_IsSetup =
true;
3746 bool b_newGlobalSettings =
false;
3748 while (wxNOT_FOUND == AUSBPrefs[i].Find(_T(
"LASTENTRY"))) {
3749 wxStringTokenizer tk(settings, _T(
";"));
3750 while (tk.HasMoreTokens()) {
3751 wxString token = tk.GetNextToken();
3752 wxString pref = token.BeforeFirst(
':');
3753 wxString val = token.AfterFirst(
':');
3754 wxString extraString;
3756 bool benabled =
false;
3758 if (pref.IsSameAs(AUSBPrefs[i])) {
3759 wxLogMessage(_T(
"pref: ") + pref);
3760 wxLogMessage(_T(
"val: ") + val);
3762 if (pref.Contains(_T(
"USBDP"))) {
3763 extraString = val.AfterFirst(
':');
3764 wxLogMessage(_T(
"extra: ") + extraString);
3767 wxLogMessage(_T(
"found pref ") + pref);
3773 wxString target = AUSBNames[i] + _T(
"-") + extraString;
3775 for (
unsigned int j = 0; j < TheConnectionParams()->Count(); j++) {
3777 wxLogMessage(_T(
" Checking: ") + target +
" .. " +
3780 if ((SERIAL == xcp->Type) &&
3781 (target.IsSameAs(xcp->GetDSPort().AfterFirst(
':')))) {
3782 pExistingParams = xcp;
3784 benabled = val.BeforeFirst(
':').IsSameAs(_T(
"1"));
3789 bool b_action =
true;
3790 if (pExistingParams) {
3791 wxLogMessage(_T(
"Using existing connection ") + target);
3793 if (pExistingParams->bEnabled == benabled) {
3796 cp->bEnabled = benabled;
3797 }
else if (val.BeforeFirst(
':').IsSameAs(
3802 wxString sSerial = _T(
"0;1;;0;0;");
3803 sSerial += AUSBNames[i];
3804 sSerial += _T(
"-") + extraString;
3805 sSerial += _T(
";4800;1;0;0;;0;;1;0;0;0;0");
3807 wxLogMessage(_T(
"Adding connection ") + sSerial);
3811 new_params->bEnabled =
true;
3812 TheConnectionParams()->Add(new_params);
3814 rr |= NEED_NEW_OPTIONS;
3817 if (b_action && cp) {
3820 rr |= NEED_NEW_OPTIONS;
3823 DataStream *pds_existing = g_pMUX->FindStream(cp->GetDSPort());
3824 if (pds_existing) g_pMUX->StopAndRemoveStream(pds_existing);
3827 dsPortType port_type = cp->IOSelect;
3829 DataStream *dstr =
new DataStream( g_pMUX,
3832 wxString::Format(wxT(
"%i"), cp->Baudrate),
3837 DataStream *dstr = makeSerialDataStream(
3838 g_pMUX, cp->Type, cp->GetDSPort(),
3839 wxString::Format(wxT(
"%i"), cp->Baudrate), port_type,
3840 cp->Priority, cp->Garmin);
3842 dstr->SetInputFilter(cp->InputSentenceList);
3843 dstr->SetInputFilterType(cp->InputSentenceListType);
3844 dstr->SetOutputFilter(cp->OutputSentenceList);
3845 dstr->SetOutputFilterType(cp->OutputSentenceListType);
3846 dstr->SetChecksumCheck(cp->ChecksumCheck);
3848 g_pMUX->AddStream(dstr);
3849 cp->b_IsSetup =
true;
3862bool DoAndroidPreferences(
void) {
3863 wxLogMessage(_T(
"Start DoAndroidPreferences"));
3865 wxString settings = BuildAndroidSettingsString();
3867 wxLogMessage(_T(
"Call InvokeJNIPreferences"));
3868 InvokeJNIPreferences(settings);
3873wxString doAndroidPOST(
const wxString &url, wxString &parms,
int timeoutMsec) {
3875 if (g_androidUtilHandler) {
3876 g_androidUtilHandler->m_eventTimer.Stop();
3877 g_androidUtilHandler->m_done =
false;
3879 androidShowBusyIcon();
3882 stimeout.Printf(_T(
"%d"), timeoutMsec);
3884 callActivityMethod_s3s(
"doHttpPostAsync", url, parms, stimeout);
3886 if (result == _T(
"OK")) {
3887 qDebug() <<
"doHttpPostAsync ResultOK, starting spin loop";
3888 g_androidUtilHandler->m_action = ACTION_POSTASYNC_END;
3889 g_androidUtilHandler->m_eventTimer.Start(500, wxTIMER_CONTINUOUS);
3892 while (!g_androidUtilHandler->m_done) {
3894 wxSafeYield(NULL,
true);
3897 qDebug() <<
"out of spin loop";
3898 g_androidUtilHandler->m_action = ACTION_NONE;
3899 g_androidUtilHandler->m_eventTimer.Stop();
3900 androidHideBusyIcon();
3902 wxString presult = g_androidUtilHandler->GetStringResult();
3906 qDebug() <<
"doHttpPostAsync Result NOT OK";
3907 androidHideBusyIcon();
3911 return wxEmptyString;
3914int validateAndroidWriteLocation(
const wxString &destination) {
3916 wxString val_result =
3917 callActivityMethod_s2s2i(
"validateWriteLocation", destination, _T(
""),
3918 OCPN_ACTION_DOWNLOAD_VALID, 0);
3919 if (val_result.IsSameAs(_T(
"Pending")))
3925int startAndroidFileDownload(
const wxString &url,
const wxString &destination,
3926 wxEvtHandler *evh,
long *dl_id) {
3929 s_bdownloading =
true;
3930 s_requested_url = url;
3931 s_download_evHandler = evh;
3932 s_download_destination = destination;
3934 wxString result = callActivityMethod_s2s(
"downloadFile", url, destination);
3936 androidShowBusyIcon();
3938 if (result.IsSameAs(_T(
"NOK")))
return 1;
3942 wxStringTokenizer tk(result, _T(
";"));
3943 if (tk.HasMoreTokens()) {
3944 wxString token = tk.GetNextToken();
3945 if (token.IsSameAs(_T(
"OK"))) {
3946 token = tk.GetNextToken();
3947 token.ToLong(&dl_ID);
3958int queryAndroidFileDownload(
long dl_ID, wxString *result) {
3961 wxString stat = callActivityMethod_is(
"getDownloadStatus", (
int)dl_ID);
3962 if (result) *result = stat;
3966 if (stat.IsSameAs(_T(
"NOK")))
3972void finishAndroidFileDownload(
void) {
3973 s_bdownloading =
false;
3974 s_requested_url.Clear();
3975 s_download_evHandler = NULL;
3976 s_download_destination.Clear();
3977 androidHideBusyIcon();
3982void cancelAndroidFileDownload(
long dl_ID) {
3983 wxString stat = callActivityMethod_is(
"cancelDownload", (
int)dl_ID);
3986bool AndroidUnzip(wxString &zipFile, wxString &destDir,
int nStrip,
3989 ns.Printf(_T(
"%d"), nStrip);
3992 br.Printf(_T(
"%d"), bRemoveZip);
3994 wxString stat = callActivityMethod_s4s(
"unzipFile", zipFile, destDir, ns, br);
3996 if (wxNOT_FOUND == stat.Find(_T(
"OK")))
return false;
3998 qDebug() <<
"unzip start";
4003 wxSafeYield(NULL,
true);
4005 qDebug() <<
"unzip poll";
4007 wxString result = callActivityMethod_ss(
"getUnzipStatus", _T(
""));
4008 if (wxNOT_FOUND != result.Find(_T(
"DONE"))) bDone =
true;
4010 qDebug() <<
"unzip done";
4015wxString getFontQtStylesheet(wxFont *font) {
4018 wxString classes = _T(
"QWidget ");
4020 wxString qstyle = classes + _T(
"{ font-family: ") + font->GetFaceName() +
4021 _T(
";font-style: ");
4022 switch (font->GetStyle()) {
4023 case wxFONTSTYLE_ITALIC:
4024 qstyle += _T(
"italic;");
4026 case wxFONTSTYLE_NORMAL:
4028 qstyle += _T(
"normal;");
4031 qstyle += _T(
"font-weight: ");
4032 switch (font->GetWeight()) {
4033 case wxFONTWEIGHT_BOLD:
4034 qstyle += _T(
"bold;");
4036 case wxFONTWEIGHT_LIGHT:
4037 qstyle += _T(
"light;");
4039 case wxFONTWEIGHT_NORMAL:
4041 qstyle += _T(
"normal;");
4045 qstyle += _T(
"font-size: ");
4047 fontSize.Printf(_T(
"%dpt }"), font->GetPointSize());
4060bool androidPlaySound(
const wxString soundfile, AndroidSound* sound) {
4061 DEBUG_LOG <<
"androidPlaySound";
4062 std::ostringstream oss;
4064 wxString wxSound(oss.str());
4065 wxString result = callActivityMethod_s2s(
"playSound", soundfile, wxSound.Mid(2));
4070JNIEXPORT jint JNICALL
4071Java_org_opencpn_OCPNNativeLib_onSoundFinished(JNIEnv *env, jobject obj) {
4072 qDebug() <<
"onSoundFinished";
4074 if (s_soundCallBack) {
4075 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
4076 evt.SetId(ID_CMD_SOUND_FINISHED);
4077 if (g_androidUtilHandler) g_androidUtilHandler->AddPendingEvent(evt);
4084wxString androidGetSupplementalLicense(
void) {
4085 wxString result = callActivityMethod_vs(
"getGMAPILicense");
4087 result += AndroidSuppLicense;
4092wxArrayString androidTraverseDir(wxString dir, wxString filespec) {
4093 wxArrayString result;
4094 if (g_Android_SDK_Version != 17)
4098 callActivityMethod_s2s(
"getAllFilesWithFilespec", dir, filespec);
4100 wxStringTokenizer tk(ir, _T(
";"));
4101 while (tk.HasMoreTokens()) {
4102 result.Add(tk.GetNextToken());
4108void androidEnableOptionsMenu(
bool bEnable) {
4109 callActivityMethod_is(
"enableOptionsMenu", bEnable ? 1 : 0);
4115QString qtStyleSheetDialog;
4116QString qtStyleSheetListBook;
4117QString qtStyleSheetScrollbars;
4124QString qtStyleSheetDialogProto =
4128 border: 1px solid #999999;\
4129 background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #E6E6E6, stop:1 #EEEEEE);\
4131QSlider::groove:disabled\
4133 background: #efefef;\
4138 background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #7cb0e9, stop:1 #7cb0e9);\
4139 border: 1px solid #5c5c5c;\
4140 border-radius: 3px;\
4145QSlider::handle:disabled\
4147 background: #D3D0CD;\
4150QScrollBar:horizontal {\
4151 border: 0px solid grey;\
4152 background-color: transparent;\
4154 margin: 0px 1px 0 1px;\
4156QScrollBar::handle:horizontal {\
4157 background-color: rgb(150, 150, 150);\
4160QScrollBar::add-line:horizontal {\
4161 border: 0px solid grey;\
4162 background: transparent;\
4164 subcontrol-position: right;\
4165 subcontrol-origin: margin;\
4168QScrollBar::sub-line:horizontal {\
4169 border: 0px solid grey;\
4170 background: transparent;\
4172 subcontrol-position: left;\
4173 subcontrol-origin: margin;\
4176QScrollBar:vertical {\
4177 border: 0px solid grey;\
4178 background-color: transparent;\
4180 margin: 1px 0px 1px 0px;\
4182QScrollBar::handle:vertical {\
4183 background-color: rgb(150, 150, 150);\
4186QScrollBar::add-line:vertical {\
4187 border: 0px solid grey;\
4188 background: transparent;\
4190 subcontrol-position: top;\
4191 subcontrol-origin: margin;\
4194QScrollBar::sub-line:vertical {\
4195 border: 0px solid grey;\
4196 background: transparent;\
4198 subcontrol-position: bottom;\
4199 subcontrol-origin: margin;\
4202QTreeWidget QScrollBar:vertical {\
4203 border: 0px solid grey;\
4204 background-color: rgb(240, 240, 240);\
4206 margin: 1px 0px 1px 0px;\
4208QTreeWidget QScrollBar::handle:vertical {\
4209 background-color: rgb(200, 200, 200);\
4211 border-radius: 10px;\
4213QTreeWidget QScrollBar::add-line:vertical {\
4214 border: 0px solid grey;\
4215 background: #32CC99;\
4217 subcontrol-position: top;\
4218 subcontrol-origin: margin;\
4221QTreeWidget QScrollBar::sub-line:vertical {\
4222 border: 0px solid grey;\
4223 background: #32CC99;\
4225 subcontrol-position: bottom;\
4226 subcontrol-origin: margin;\
4229QTreeWidget QScrollBar:horizontal {\
4230 border: 0px solid grey;\
4231 background-color: rgb(240, 240, 240);\
4233 margin: 0px 1px 0 1px;\
4235QTreeWidget QScrollBar::handle:horizontal {\
4236 background-color: rgb(200, 200, 200);\
4238 border-radius: 10px;\
4240QTreeWidget QScrollBar::add-line:horizontal {\
4241 border: 0px solid grey;\
4242 background: #32CC99;\
4244 subcontrol-position: right;\
4245 subcontrol-origin: margin;\
4248QTreeWidget QScrollBar::sub-line:horizontal {\
4249 border: 0px solid grey;\
4250 background: #32CC99;\
4252 subcontrol-position: left;\
4253 subcontrol-origin: margin;\
4256#OCPNCheckedListCtrl QScrollBar::vertical {\
4257 border: 0px solid grey;\
4258 background-color: rgb(240, 240, 240);\
4260 margin: 1px 0px 1px 0px;\
4262#OCPNCheckedListCtrl QScrollBar::handle:vertical {\
4263 background-color: rgb(180, 180, 180);\
4265 border-radius: 6px;\
4267#OCPNCheckedListCtrl QScrollBar::add-line:vertical {\
4268 border: 0px solid grey;\
4269 background: #32CC99;\
4271 subcontrol-position: top;\
4272 subcontrol-origin: margin;\
4275#OCPNCheckedListCtrl QScrollBar::sub-line:vertical {\
4276 border: 0px solid grey;\
4277 background: #32CC99;\
4279 subcontrol-position: bottom;\
4280 subcontrol-origin: margin;\
4283QString qtStyleSheetScrollbarsProto =
4285QScrollBar:horizontal {\
4286 border: 0px solid grey;\
4287 background-color: transparent;\
4289 margin: 0px 1px 0 1px;\
4291QScrollBar::handle:horizontal {\
4292 background-color: #7cb0e9;\
4295QScrollBar::add-line:horizontal {\
4296 border: 0px solid grey;\
4297 background: transparent;\
4299 subcontrol-position: right;\
4300 subcontrol-origin: margin;\
4303QScrollBar::sub-line:horizontal {\
4304 border: 0px solid grey;\
4305 background: transparent;\
4307 subcontrol-position: left;\
4308 subcontrol-origin: margin;\
4311QScrollBar:vertical {\
4312 border: 0px solid grey;\
4313 background-color: transparent;\
4315 margin: 1px 0px 1px 0px;\
4317QScrollBar::handle:vertical {\
4318 background-color: #7cb0e9;\
4321QScrollBar::add-line:vertical {\
4322 border: 0px solid grey;\
4323 background: transparent;\
4325 subcontrol-position: top;\
4326 subcontrol-origin: margin;\
4329QScrollBar::sub-line:vertical {\
4330 border: 0px solid grey;\
4331 background: transparent;\
4333 subcontrol-position: bottom;\
4334 subcontrol-origin: margin;\
4337std::string prepareStyleIcon(wxString icon_file,
int size) {
4338 wxString data_locn = g_Platform->GetSharedDataDir();
4339 data_locn.Append(_T(
"styles/"));
4341 wxString file = data_locn + icon_file;
4343 wxImage Image(file, wxBITMAP_TYPE_PNG);
4344 wxImage scaledImage = Image.Scale(size, size, wxIMAGE_QUALITY_HIGH);
4346 wxString save_file = g_Platform->GetPrivateDataDir() + _T(
"/") + icon_file;
4347 scaledImage.SaveFile(save_file, wxBITMAP_TYPE_PNG);
4349 wxCharBuffer buf = save_file.ToUTF8();
4350 std::string ret(buf);
4354QString prepareAndroidSliderStyleSheet(
int sliderWidth) {
4355 QString qtStyleSheetSlider;
4361 int slider_handle_width =
4362 wxMax(g_Platform->GetDisplayDPmm() * 6, sliderWidth / 5);
4367 "QSlider::groove { border: 1px solid #999999; background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #E6E6E6, stop:1 #EEEEEE); } \
4368 QSlider::groove:disabled { background: #efefef; } \
4369 QSlider::handle { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #7cb0e9, stop:1 #7cb0e9); border: 1px solid #5c5c5c; \
4370 border-radius: 3px; width: %dpx; height: 45px; } \
4371 QSlider::handle:disabled { background: #D3D0CD;}",
4372 slider_handle_width);
4374 qtStyleSheetSlider.append(sb);
4376 return qtStyleSheetSlider;
4379void prepareAndroidStyleSheets() {
4381 qtStyleSheetDialog.clear();
4382 qtStyleSheetDialog.append(qtStyleSheetDialogProto);
4386 int slider_handle_width = g_Platform->GetDisplayDPmm() * 6;
4391 "QSlider::groove { border: 1px solid #999999; background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #E6E6E6, stop:1 #EEEEEE); } \
4392 QSlider::groove:disabled { background: #efefef; } \
4393 QSlider::handle { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #7cb0e9, stop:1 #7cb0e9); border: 1px solid #5c5c5c; \
4394 border-radius: 3px; width: %dpx; height: 45px; } \
4395 QSlider::handle:disabled { background: #D3D0CD;}",
4396 slider_handle_width);
4398 qtStyleSheetDialog.append(sb);
4401 int cbSize = 30 * getAndroidDisplayDensity();
4406 std::string cbs = prepareStyleIcon(_T(
"chek_full.png"), cbSize);
4408 std::string ucbs = prepareStyleIcon(_T(
"chek_empty.png"), cbSize);
4410 snprintf(cb,
sizeof(cb),
4411 "QCheckBox { spacing: 25px;}\
4412 QCheckBox::indicator { width: %dpx; height: %dpx;}\
4413 QCheckBox::indicator:checked {image: url(%s);}\
4414 QCheckBox::indicator:unchecked {image: url(%s);}",
4415 cbSize, cbSize, cbs.c_str(), ucbs.c_str());
4417 qtStyleSheetDialog.append(cb);
4420 qtStyleSheetListBook.clear();
4423 int tbbSize = 50 * getAndroidDisplayDensity();
4426 std::string tbbl = prepareStyleIcon(_T(
"tabbar_button_left.png"), tbbSize);
4427 std::string tbbr = prepareStyleIcon(_T(
"tabbar_button_right.png"), tbbSize);
4429 snprintf(tbb,
sizeof(tbb),
4430 "QTabBar::scroller { width: %dpx; }\
4431 QTabBar QToolButton::right-arrow { image: url(%s); }\
4432 QTabBar QToolButton::left-arrow { image: url(%s); }",
4433 tbbSize, tbbr.c_str(), tbbl.c_str());
4435 qtStyleSheetListBook.append(tbb);
4438 qtStyleSheetScrollbars.clear();
4439 qtStyleSheetScrollbars.append(qtStyleSheetScrollbarsProto);
4442void setChoiceStyleSheet(wxChoice *win,
int refDim) {
4445 float fontDimFloat = ((float)refDim) * 0.5;
4446 int fontDim = (int)fontDimFloat;
4447 int pixRadius = refDim / 4;
4449 QString styleString;
4453 snprintf(sb,
sizeof(sb),
4454 "QComboBox { font-size: %dpx; font-weight: bold; min-height: %dpx; "
4455 "color: rgb(0,0,0); background-color: rgb(250,250,250); }",
4457 styleString.append(sb);
4460 snprintf(sb,
sizeof(sb),
4461 "QComboBox QListView::item { color: rgb(0,0,0); background-color: "
4462 "rgb(95, 163, 237); }");
4463 styleString.append(sb);
4466 snprintf(sb,
sizeof(sb),
4467 "QComboBox QAbstractItemView { font-size: %dpx; font-weight: bold;}",
4469 styleString.append(sb);
4473 snprintf(sb,
sizeof(sb),
4474 "QComboBox QAbstractItemView::item { min-height: %dpx; border: "
4475 "10px outset darkgray; border-radius: %dpx; }",
4477 styleString.append(sb);
4481 win->GetHandle()->setView(
new QListView());
4482 win->GetHandle()->setStyleSheet(styleString);
4485void setMenuStyleSheet(wxMenu *win,
const wxFont &font) {
4488 int points = font.GetPointSize();
4489 int fontPix = points / g_Platform->getFontPointsperPixel();
4493 QString styleString;
4496 snprintf(sb,
sizeof(sb),
"QMenu { font: bold %dpx; }", fontPix);
4497 styleString.append(sb);
4499 snprintf(sb,
sizeof(sb),
4500 "QMenu::separator { height: 4px; background: lightblue; "
4501 "margin-left: 10px; margin-right: 5px; }");
4502 styleString.append(sb);
4506 win->GetHandle()->setStyleSheet(styleString);
4509QString getAdjustedDialogStyleSheet() {
return qtStyleSheetDialog; }
4511QString getListBookStyleSheet() {
return qtStyleSheetListBook; }
4513QString getScrollBarsStyleSheet() {
return qtStyleSheetScrollbars; }
4516wxBitmap loadAndroidSVG(
const wxString filename,
unsigned int width,
4517 unsigned int height) {
4518 wxCharBuffer abuf = filename.ToUTF8();
4520 std::string s(abuf.data());
4523 qDebug() <<
"loadAndroidSVG FAIL";
4527 wxString save_file_dir =
4528 g_Platform->GetPrivateDataDir() + _T(
"/") + _T(
"icons");
4529 if (!wxDirExists(save_file_dir)) wxMkdir(save_file_dir);
4531 wxFileName fsvg(filename);
4532 wxFileName fn(save_file_dir + _T(
"/") + fsvg.GetFullName());
4533 fn.SetExt(_T(
"png"));
4546 wxString val = callActivityMethod_s2s2i(
"buildSVGIcon", filename,
4547 fn.GetFullPath(), width, height);
4548 if (val == _T(
"OK")) {
4551 return wxBitmap(fn.GetFullPath(), wxBITMAP_TYPE_PNG);
4553 return wxBitmap(width, height);
4557void androidTestCPP() { callActivityMethod_vs(
"callFromCpp"); }
4559unsigned int androidColorPicker(
unsigned int initialColor) {
4560 if (g_androidUtilHandler) {
4561 g_androidUtilHandler->m_eventTimer.Stop();
4562 g_androidUtilHandler->m_done =
false;
4564 wxString val = callActivityMethod_is(
"doColorPickerDialog", initialColor);
4566 if (val == _T(
"OK")) {
4568 g_androidUtilHandler->m_action = ACTION_COLORDIALOG_END;
4569 g_androidUtilHandler->m_eventTimer.Start(1000, wxTIMER_CONTINUOUS);
4572 while (!g_androidUtilHandler->m_done) {
4574 wxSafeYield(NULL,
true);
4578 g_androidUtilHandler->m_action = ACTION_NONE;
4579 g_androidUtilHandler->m_eventTimer.Stop();
4581 wxString tresult = g_androidUtilHandler->GetStringResult();
4583 if (tresult.StartsWith(_T(
"cancel:"))) {
4585 return initialColor;
4586 }
else if (tresult.StartsWith(_T(
"color:"))) {
4587 wxString color = tresult.AfterFirst(
':');
4599 qDebug() <<
"Result NOT OK";
4605bool AndroidSecureCopyFile(wxString in, wxString out) {
4608 wxString result = callActivityMethod_s2s(
"SecureFileCopy", in, out);
4610 if (wxNOT_FOUND == result.Find(_T(
"OK"))) bret =
false;
4615int doAndroidPersistState() {
4616 qDebug() <<
"doAndroidPersistState() starting...";
4617 wxLogMessage(_T(
"doAndroidPersistState() starting..."));
4622 if (g_pAISTargetList) {
4623 wxAuiPaneInfo &pane = g_pauimgr->GetPane(g_pAISTargetList);
4624 g_AisTargetList_perspective = g_pauimgr->SavePaneInfo(pane);
4625 g_pauimgr->DetachPane(g_pAISTargetList);
4627 pConfig->SetPath(_T (
"/AUI" ));
4628 pConfig->Write(_T (
"AUIPerspective" ), g_pauimgr->SavePerspective());
4633 PluginLoader::getInstance()->DeactivateAllPlugIns();
4646 if (g_bAutoAnchorMark) {
4647 bool watching_anchor =
false;
4648 if (pAnchorWatchPoint1)
4649 watching_anchor = (pAnchorWatchPoint1->GetIconName().StartsWith(
4651 if (pAnchorWatchPoint2)
4652 watching_anchor |= (pAnchorWatchPoint2->GetIconName().StartsWith(
4655 wxDateTime now = wxDateTime::Now();
4656 wxTimeSpan uptime = now.Subtract(g_start_time);
4658 if (!watching_anchor && (g_bCruising) && (gSog < 0.5) &&
4659 (uptime.IsLongerThan(wxTimeSpan(0, 30, 0, 0))))
4664 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
4667 if (pr->GetName().StartsWith(_T(
"Anchorage"))) {
4668 double a = gLat - pr->m_lat;
4669 double b = gLon - pr->m_lon;
4670 double l = sqrt((a * a) + (b * b));
4673 if ((l * 60. * 1852.) < (.25 * 1852.)) {
4674 pConfig->DeleteWayPoint(pr);
4675 pSelect->DeleteSelectablePoint(pr, SELTYPE_ROUTEPOINT);
4681 node = node->GetNext();
4684 wxString name = now.Format();
4685 name.Prepend(_(
"Anchorage created "));
4687 new RoutePoint(gLat, gLon, _T(
"anchorage"), name, _T(
""));
4688 pWP->m_bShowName =
false;
4689 pWP->m_bIsolatedMark =
true;
4691 pConfig->AddNewWayPoint(pWP, -1);
4695 if (gFrame->GetPrimaryCanvas()->GetpCurrentStack()) {
4696 g_restore_stackindex =
4697 gFrame->GetPrimaryCanvas()->GetpCurrentStack()->CurrentStackEntry;
4698 g_restore_dbindex = gFrame->GetPrimaryCanvas()
4699 ->GetpCurrentStack()
4700 ->GetCurrentEntrydbIndex();
4701 if (gFrame->GetPrimaryCanvas() &&
4702 gFrame->GetPrimaryCanvas()->GetQuiltMode())
4704 gFrame->GetPrimaryCanvas()->GetQuiltReferenceChartIndex();
4707 if (g_MainToolbar) {
4708 wxPoint tbp = g_MainToolbar->GetPosition();
4709 wxPoint tbp_incanvas = gFrame->GetPrimaryCanvas()->ScreenToClient(tbp);
4710 g_maintoolbar_x = tbp_incanvas.x;
4711 g_maintoolbar_y = tbp_incanvas.y;
4712 g_maintoolbar_orient = g_MainToolbar->GetOrient();
4715 if (g_iENCToolbar) {
4716 wxPoint locn = g_iENCToolbar->GetPosition();
4717 wxPoint tbp_incanvas = gFrame->GetPrimaryCanvas()->ScreenToClient(locn);
4718 g_iENCToolbarPosY = tbp_incanvas.y;
4719 g_iENCToolbarPosX = tbp_incanvas.x;
4722 pConfig->UpdateSettings();
4723 pConfig->UpdateNavObj();
4725 pConfig->m_pNavObjectChangesSet->reset();
4729 pConfig->DeleteGroup(_T (
"/Routes" ));
4730 pConfig->DeleteGroup(_T (
"/Marks" ));
4743 if (ChartData) ChartData->PurgeCachePlugins();
4745 PluginLoader::getInstance()->UnLoadAllPlugIns();
4747 delete g_pi_manager;
4748 g_pi_manager = NULL;
4751 wxLogMessage(_T(
"doAndroidPersistState() finished cleanly."));
4752 qDebug() <<
"doAndroidPersistState() finished cleanly.";
4754 wxLogMessage(_T(
"Closing logfile, Terminating App."));
4756 wxLog::FlushActive();
4757 g_Platform->CloseLogFile();
4763JNIEXPORT
int JNICALL
4764Java_org_opencpn_OCPNNativeLib_ScheduleCleanExit(JNIEnv *env, jobject obj) {
4765 qDebug() <<
"Java_org_opencpn_OCPNNativeLib_ScheduleCleanExit";
4766 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
4767 evt.SetId(SCHEDULED_EVENT_CLEAN_EXIT);
4768 if (g_androidUtilHandler) {
4769 g_androidUtilHandler->AddPendingEvent(evt);
4776void CheckMigrateCharts()
4778 qDebug() <<
"CheckMigrateCharts";
4779 if (g_Android_SDK_Version < 30)
4783 pInit_Chart_Dir->Clear();
4786 wxArrayString chartDirs = GetConfigChartDirectories();
4787 wxArrayString migrateDirs;
4788 qDebug() << chartDirs.GetCount();
4790 for (
unsigned int i=0; i < chartDirs.GetCount(); i++){
4791 qDebug() << chartDirs[i].mb_str();
4794 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs0) )
4797 else if (!g_androidGetFilesDirs1.StartsWith(
"?")){
4798 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs1) )
4802 migrateDirs.Add(chartDirs[i]);
4806 if (!migrateDirs.GetCount())
4812 g_migrateDialog->SetSize( gFrame->GetSize());
4813 g_migrateDialog->Centre();
4814 g_migrateDialog->Raise();
4815 g_migrateDialog->ShowModal();
4820wxString androidGetDownloadDirectory()
4822 return g_androidDownloadDirectory;
4827wxString WrapText(wxWindow *win,
const wxString& text,
int widthMax)
4834 Wrap(win, text, widthMax);
4836 wxString
const& GetWrapped()
const {
return m_wrapped; }
4838 virtual void OnOutputLine(
const wxString& line)
4842 virtual void OnNewLine()
4850 return wrapper.GetWrapped();
4859EVT_BUTTON(ID_MIGRATE_CANCEL, MigrateAssistantDialog::OnMigrateCancelClick)
4860EVT_BUTTON(ID_MIGRATE_OK, MigrateAssistantDialog::OnMigrateOKClick)
4861EVT_BUTTON(ID_MIGRATE_START, MigrateAssistantDialog::OnMigrateClick)
4862EVT_BUTTON(ID_MIGRATE_CONTINUE, MigrateAssistantDialog::OnMigrate1Click)
4863EVT_TIMER(MIGRATION_STATUS_TIMER, MigrateAssistantDialog::onTimerEvent)
4867 wxWindowID
id, const wxString& caption,
4868 const wxPoint& pos, const wxSize& size,
4870 : wxDialog(parent,
id, caption, pos, size,
4871 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
4874 m_permissionResult =
"";
4877 m_bskipScan = bskipScan;
4879 m_statusTimer.SetOwner(
this, MIGRATION_STATUS_TIMER);
4881 wxFont *qFont = OCPNGetFont(_(
"Dialog"), 10);
4885 GetSizer()->SetSizeHints(
this);
4889MigrateAssistantDialog::~MigrateAssistantDialog(
void) {
4894void MigrateAssistantDialog::CreateControls(
void) {
4895 wxBoxSizer* mainSizer =
new wxBoxSizer(wxVERTICAL);
4896 SetSizer(mainSizer);
4898 wxStaticBox* mmsiBox =
4899 new wxStaticBox(
this, wxID_ANY, _(
"OpenCPN for Android Migration Assistant"));
4901 wxStaticBoxSizer* infoSizer =
new wxStaticBoxSizer(mmsiBox, wxVERTICAL);
4902 mainSizer->Add(infoSizer, 0, wxEXPAND | wxALL, 5);
4907 wxArrayString chartDirs = GetConfigChartDirectories();
4909 for (
unsigned int i=0; i < chartDirs.GetCount(); i++){
4911 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs0) )
4914 else if (!g_androidGetFilesDirs1.StartsWith(
"?")){
4915 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs1) )
4919 m_migrateDirs.Add(chartDirs[i]);
4924 if (m_migrateDirs.GetCount()){
4925 wxString infoText1(_(
"OpenCPN has detected chart folders in your configuration file that cannot be accessed on this version of Android"));
4927 wxString infoText1w = WrapText(
this, infoText1, gFrame->GetSize().x * 95 / 100);
4929 m_infoText =
new wxStaticText(
this, wxID_STATIC, infoText1w);
4931 infoSizer->AddSpacer( 1 * GetCharWidth());
4932 infoSizer->Add(m_infoText, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 10);
4933 infoSizer->AddSpacer( 1 * GetCharWidth());
4937 for (
unsigned int i=0; i < m_migrateDirs.GetCount(); i++){
4938 dirsMsg += wxString(
" ");
4939 dirsMsg += m_migrateDirs[i];
4940 dirsMsg += wxString(
"\n");
4944 m_infoDirs =
new wxStaticText(
this, wxID_STATIC, dirsMsg);
4946 infoSizer->Add(m_infoDirs, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 10);
4948 wxString migrateMsg1 = _(
"OpenCPN can copy these chart folders to a suitable location, if desired.");
4949 migrateMsg1 +=
"\n\n";
4950 migrateMsg1 += _(
"To proceed with chart folder migration, choose the chart source folder, and follow the instructions given.");
4952 wxString migrateMsg1w = WrapText(
this, migrateMsg1, gFrame->GetSize().x * 95/ 100);
4954 m_migrateStep1 =
new wxStaticText(
this, wxID_STATIC, migrateMsg1w);
4955 infoSizer->Add(m_migrateStep1, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 10);
4960 wxString migrateMsg1 = _(
"Some chart folders may be inaccessible to OpenCPN on this version of Android. ");
4961 migrateMsg1 += _(
"OpenCPN can copy these chart folders to a suitable location, if desired.");
4962 migrateMsg1 +=
"\n\n";
4963 migrateMsg1 += _(
"To proceed with chart folder migration, choose the chart source folder, and follow the instructions given.");
4965 wxString migrateMsg1w = WrapText(
this, migrateMsg1, gFrame->GetSize().x * 9 / 10);
4967 m_migrateStep1 =
new wxStaticText(
this, wxID_STATIC, migrateMsg1w);
4968 infoSizer->Add(m_migrateStep1, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 10);
4971 mainSizer->AddSpacer( 1 * GetCharWidth());
4974 if (!g_androidGetFilesDirs1.StartsWith(
"?")){
4976 wxStaticBoxSizer* sourceSizer =
new wxStaticBoxSizer(
4977 new wxStaticBox(
this, wxID_ANY, _(
"Migrate destination")), wxVERTICAL);
4978 mainSizer->Add(sourceSizer, 0, wxEXPAND | wxALL, 5);
4979 mainSizer->AddSpacer( 2 * GetCharWidth());
4981 m_radioInternal =
new wxRadioButton (
this, wxID_ANY, _(
"OpenCPN Internal Storage"),wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
4982 sourceSizer->Add( m_radioInternal, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
4984 m_radioSDCard =
new wxRadioButton (
this, wxID_ANY, _(
"OpenCPN SDCard Storage"),wxDefaultPosition, wxDefaultSize);
4985 sourceSizer->Add( m_radioSDCard, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
4987 m_radioInternal->SetValue(
true );
4992 m_migrateButton =
new wxButton(
this, ID_MIGRATE_START, _(
"Choose chart source folder."));
4993 mainSizer->Add(m_migrateButton, 0, wxEXPAND | wxALL, 5);
4997 statusSizer =
new wxStaticBoxSizer(
4998 new wxStaticBox(
this, wxID_ANY, _(
"Status")), wxVERTICAL);
4999 mainSizer->Add(statusSizer, 0, wxEXPAND | wxALL, 5);
5003 wxSize(gFrame->GetSize().x * 8 / 10, gFrame->GetCharHeight() * 2));
5004 statusSizer->Add(m_ipGauge, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5);
5006 mainSizer->AddSpacer( 1 * GetCharWidth());
5008 m_statusText =
new wxStaticText(
this, wxID_STATIC, m_Status);
5009 statusSizer->Add(m_statusText, 0, wxEXPAND | wxALL, 5);
5011 GetSizer()->Hide(statusSizer);
5013 wxBoxSizer* btnSizer =
new wxBoxSizer(wxHORIZONTAL);
5014 mainSizer->Add(btnSizer, 0, wxALIGN_RIGHT | wxALL, 5);
5015 m_CancelButton =
new wxButton(
this, ID_MIGRATE_CANCEL, _(
"Cancel"));
5016 m_CancelButton->SetDefault();
5017 btnSizer->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
5019 m_OKButton =
new wxButton(
this, ID_MIGRATE_OK, _(
"OK"));
5020 btnSizer->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
5026void MigrateAssistantDialog::OnMigrateCancelClick(wxCommandEvent& event) {
5028 m_statusTimer.Stop();
5029 callActivityMethod_vs(
"cancelMigration");
5031 EndModal(wxID_CANCEL);
5034void MigrateAssistantDialog::OnMigrateOKClick(wxCommandEvent& event) {
5038void MigrateAssistantDialog::OnMigrateClick(wxCommandEvent& event)
5041 wxString clickText1(_(
"On the next page, find and choose the root folder containing chart files to migrate\n\n\
5042Example: /storage/emulated/0/Charts\n\n"));
5043 clickText1 += _(
"This entire folder will be migrated.\n");
5044 clickText1 += _(
"Proceed?");
5046 if (wxID_OK == OCPNMessageBox(
5047 NULL, clickText1, _(
"OpenCPN for Android Migration Assistant"), wxOK | wxCANCEL )){
5049 if(m_infoText) m_infoText->Hide();
5050 m_migrateStep1->Hide();
5051 GetSizer()->Show(statusSizer);
5054 if (g_androidUtilHandler) {
5056 m_Status = _(
"Waiting for permission grant....");
5057 setStatus( m_Status );
5059 g_androidUtilHandler->m_eventTimer.Stop();
5060 g_androidUtilHandler->m_migratePermissionSetDone =
false;
5062 wxString activityResult;
5063 activityResult = callActivityMethod_vs(
"migrateSetup");
5065 if (activityResult == _T(
"OK")) {
5067 g_androidUtilHandler->m_action = ACTION_SAF_PERMISSION_END;
5068 g_androidUtilHandler->m_eventTimer.Start(1000, wxTIMER_CONTINUOUS);
5074void MigrateAssistantDialog::OnMigrate1Click(wxCommandEvent& event) {
5080 m_migrateDestinationFolder = g_androidGetFilesDirs0 +
"/Charts";
5082 m_migrateDestinationFolder = g_androidGetFilesDirs1 +
"/Charts";
5084 qDebug() <<
"m_migrateSourceFolder" << m_migrateSourceFolder.mb_str();
5085 qDebug() <<
"m_migrateDestinationFolder" << m_migrateDestinationFolder.mb_str();
5087 wxString activityResult;
5088 activityResult = callActivityMethod_s2s(
"migrateFolder", m_migrateSourceFolder, m_migrateDestinationFolder);
5090 m_Status = _(
"Migration started...");
5091 setStatus( m_Status );
5093 m_statusTimer.Start(500, wxTIMER_CONTINUOUS);
5100void MigrateAssistantDialog::onPermissionGranted( wxString result ) {
5101 m_permissionResult = result;
5102 qDebug() <<
"onPermissionGranted " << result.mb_str();
5103 if(result.StartsWith(
"file")){
5104 m_migrateSourceFolder = result.Mid(5);
5106 m_Status = _(
"Permission granted to ");
5107 m_Status += m_migrateSourceFolder;
5108 setStatus( m_Status );
5111 m_migrateButton->Hide();
5116 m_bsdcard = m_radioSDCard->GetValue();
5118 wxString clickText2(_(
"OpenCPN has obtained temporary permission to access the selected chart folders."));
5119 clickText2 +=
"\n\n";
5120 clickText2 += _(
"Chart migration is ready to proceed.");
5121 clickText2 +=
"\n\n";
5122 clickText2 += _(
"Source: ");
5123 clickText2 += m_migrateSourceFolder;
5124 clickText2 +=
"\n\n";
5126 clickText2 += _(
"Destination: OpenCPN Internal Storage");
5128 clickText2 += _(
"Destination: OpenCPN SDCard Storage");
5129 clickText2 +=
"\n\n";
5130 clickText2 += _(
"Migrate charts now?");
5134 if (wxID_OK == OCPNMessageBox(
5135 NULL, clickText2, _(
"OpenCPN for Android Migration Assistant"), wxOK | wxCANCEL )){
5137 wxCommandEvent evt(wxEVT_BUTTON);
5138 evt.SetId(ID_MIGRATE_CONTINUE);
5139 AddPendingEvent(evt);
5143 setStatus( m_Status );
5145 m_migrateButton->Show();
5151 setStatus( m_Status );
5156void MigrateAssistantDialog::onTimerEvent(wxTimerEvent &event)
5159 qDebug() <<
"Migration: onTimerEvent";
5161 m_Status = callActivityMethod_vs(
"getMigrateStatus");
5162 setStatus( m_Status );
5164 if (m_Status.StartsWith(
"Counting"))
5167 if (m_Status.StartsWith(
"Migrating")){
5168 wxString prog = m_Status.Mid(10);
5170 wxString np = prog.BeforeFirst(
'/');
5172 wxString np1 = prog.AfterFirst(
'/');
5173 wxString np2 = np1.BeforeFirst(
';');
5179 if (m_ipGauge->GetRange() != n)
5180 m_ipGauge->SetRange( n );
5181 m_ipGauge->SetValue( i );
5188 if (m_Status.Contains(
"Migration complete")){
5189 m_statusTimer.Stop();
5191 wxString clickText3(_(
"Chart migration is finished."));
5192 clickText3 +=
"\n\n";
5193 clickText3 += _(
"Migrated chart folders are now accessible to OpenCPN.");
5195 clickText3 += _(
"You may need to adjust your chart folders further, to accommodate individual chart groups");
5196 clickText3 +=
"\n\n";
5197 clickText3 += _(
"OpenCPN will now restart to apply changes.");
5199 if (wxID_OK == OCPNMessageBox(
5200 NULL, clickText3, _(
"OpenCPN for Android Migration Assistant"), wxOK )){
5209wxArrayString GetConfigChartDirectories()
5212 pConfig->SetPath(_T (
"/ChartDirectories" ));
5213 int iDirMax = pConfig->GetNumberOfEntries();
5217 bool bCont = pConfig->GetFirstEntry(str, dummy);
5219 pConfig->Read(str, &val);
5220 rv.Add(val.BeforeFirst(
'^'));
5221 bCont = pConfig->GetNextEntry(str, dummy);
5230void MigrateAssistantDialog::FinishMigration()
5232 m_Status = _(
"Finishing migration");
5233 setStatus( m_Status );
5237 qDebug() <<
"m_migrateSourceFolder " << m_migrateSourceFolder.mb_str();
5238 qDebug() <<
"m_migrateDestinationFolder " << m_migrateDestinationFolder.mb_str();
5245 wxArrayString finalArray;
5246 wxArrayString chartDirs = GetConfigChartDirectories();
5247 for (
unsigned int i=0; i < chartDirs.GetCount(); i++){
5253 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs0) )
5256 else if (!g_androidGetFilesDirs1.StartsWith(
"?")){
5257 if ( chartDirs[i].StartsWith(g_androidGetFilesDirs1) )
5263 if(!chartDirs[i].StartsWith(m_migrateSourceFolder))
5270 finalArray.Add(chartDirs[i]);
5275 finalArray.Add(m_migrateDestinationFolder +
"/MigratedCharts");
5284 wxString migratedFolder = m_migrateDestinationFolder +
"/MigratedCharts/";
5294 wxFileName fn(m_migrateSourceFolder);
5295 migratedFolder += fn.GetName();
5296 qDebug() <<
"migratedFolder " << migratedFolder.mb_str();
5298 wxDir migratedDir(migratedFolder +
"/");
5299 if (migratedDir.HasFiles()){
5300 qDebug() <<
"Add A";
5301 finalArray.Add(migratedFolder);
5304 qDebug() <<
"Add CSD";
5306 if (migratedDir.HasSubDirs())
5308 qDebug() <<
"Add SD";
5309 wxArrayString children;
5312 if ((dir = opendir (migratedFolder.c_str())) != NULL) {
5313 while ((ent = readdir (dir)) != NULL) {
5314 wxString sent(ent->d_name);
5315 qDebug() <<
"sent: " << sent.mb_str();
5316 if (!sent.StartsWith(
'.')){
5317 wxString dirToAdd = migratedFolder +
"/" + sent;
5318 children.Add( wxString(dirToAdd));
5324 for (
unsigned int j=0 ; j < children.GetCount() ; j++){
5325 qDebug() <<
"Child: " << children[j].mb_str();
5326 if(wxFileName::DirExists(children[j])){
5327 qDebug() <<
"ChildDir: " << children[j].mb_str();
5328 qDebug() <<
"Add B";
5329 finalArray.Add(children[j]);
5336 for (
unsigned int j=0 ; j < finalArray.GetCount() ; j++){
5337 qDebug() <<
"finalEntry: " << finalArray[j].mb_str();
5342 wxRemoveFile(ChartListFileName);
5344 pConfig->SetPath(_T (
"/ChartDirectories" ));
5345 pConfig->DeleteGroup(_T (
"/ChartDirectories" ));
5347 pConfig->SetPath(_T (
"/ChartDirectories" ));
5348 for (
int iDir = 0; iDir < finalArray.GetCount(); iDir++) {
5349 wxString dirn = finalArray[iDir];
5350 dirn.Append(_T(
"^"));
5353 str_buf.Printf(_T (
"ChartDir%d" ), iDir + 1);
5354 pConfig->Write(str_buf, dirn);
5359 callActivityMethod_vs(
"restartOCPNAfterMigrate");
5364 EVT_TIMER( 4356, InProgressIndicator::OnTimer )
5371 InProgressIndicator::InProgressIndicator(wxWindow* parent, wxWindowID
id,
int range,
5372 const wxPoint& pos,
const wxSize& size,
5373 long style,
const wxValidator& validator,
const wxString& name)
5375 wxGauge::Create(parent,
id, range, pos, size, style, validator, name);
5377 m_timer.SetOwner(
this, 4356 );
5384InProgressIndicator::~InProgressIndicator()
5389void InProgressIndicator::OnTimer(wxTimerEvent &evt)
5396void InProgressIndicator::Start()
5399 m_timer.Start( 50 );
5403void InProgressIndicator::Stop()