Improve the error scenarios when loading the KML files and its dependencies.

- If the KML folder does not exist (like the first time), prompt the user to choose a new KML folder.
- Move the KML folder in the JSON settings embedded in the state file because Windows cannot open the state file with KML url longer than 256 byte.
- Prevent to auto save before launching the "Open...", "Save As...", "Load Object...", "Save Object...", etc...
This commit is contained in:
dgis 2020-08-30 23:29:45 +02:00
parent c5d135d73f
commit 85d8a6bb3e
8 changed files with 551 additions and 388 deletions

View file

@ -63,6 +63,14 @@ LINKS
CHANGES
Version 1.9 (2020-09-XX)
- If the KML folder does not exist (like the first time), prompt the user to choose a new KML folder.
- If the memory card file for the port 2 cannot be found, prompt the user to choose a new memory card file.
- Move the KML folder in the JSON settings embedded in the state file because Windows cannot open the state file with KML url longer than 256 byte.
- Prevent to auto save before launching the "Open...", "Save As...", "Load Object...", "Save Object...", etc...
Version 1.8 (2020-05-24)
- Intercept the ESC keyboard key to allow the use of the BACK soft key.
@ -197,15 +205,6 @@ The Eric's Real scripts ("real*.kml" and "real*.bmp/png") are embedded in this a
TODO
- Android 11 new storage issues :-(
- Move the KML folder in the JSON settings embedded in the state file because Windows cannot open the state file with KML url longer than 256 byte.
* Need to set szEmuDirectory (and may be szRomDirectory for Emu48 only) in onFileNew() before NewDocument().
* If the JSON settings contains the KML folder, we need to set szEmuDirectory (and may be szRomDirectory for Emu48 only) in onFileOpen() before OpenDocument().
Else if NO JSON settings contains the KML folder, we can extract the variable szCurrentKml after OpenDocument().
If szCurrentKml is using the old format, we remove the KML folder part in the variable szCurrentKml and set this KML folder in the JSON setting.
Else if szCurrentKml does not contain the KML folder part, we should prompt the user to select the KML folder (It should solve the next issue).
* Need to change the variable szCurrentKml before saving (in onFileSave()/onFileSaveAs() before SaveDocument()).
* onViewScript should be change too!
- If the KML folder does not exist (like the first time), prompt the user to choose a new KML folder.
- ANR in NativeLib.buttonUp(), should make Win32::InvalidateRect() asynchronous (may be the cause of the lag and freeze).
- Add the name of the file in the toast "State saved".
- Bug: In Xiaomi mi A3 under Android10, the haptic feedback does not work (add an intensity setting).

View file

@ -35,6 +35,7 @@ TCHAR szKmlLog[10240];
TCHAR szKmlLogBackup[10240];
TCHAR szKmlTitle[10240];
BOOL securityExceptionOccured;
BOOL kmlFileNotFound = FALSE;
BOOL settingsPort2en;
BOOL settingsPort2wr;
BOOL soundAvailable = FALSE;
@ -192,32 +193,21 @@ void sendMenuItemCommand(int menuItem) {
TCHAR lastKMLFilename[MAX_PATH];
BOOL getFirstKMLFilenameForType(BYTE chipsetType, TCHAR * firstKMLFilename, size_t firstKMLFilenameSize) {
if(firstKMLFilename) {
BOOL getFirstKMLFilenameForType(BYTE chipsetType) {
JNIEnv *jniEnv = getJNIEnvironment();
if(jniEnv) {
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
if(mainActivityClass) {
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "getFirstKMLFilenameForType", "(C)Ljava/lang/String;");
jobject resultString = (*jniEnv)->CallObjectMethod(jniEnv, mainActivity, midStr, (char)chipsetType);
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "getFirstKMLFilenameForType", "(C)I");
int result = (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, (char)chipsetType);
(*jniEnv)->DeleteLocalRef(jniEnv, mainActivityClass);
if (resultString) {
const char *strReturn = (*jniEnv)->GetStringUTFChars(jniEnv, resultString, 0);
if(_tcscmp(lastKMLFilename, strReturn) == 0) {
(*jniEnv)->ReleaseStringUTFChars(jniEnv, resultString, strReturn);
return FALSE;
}
_tcscpy(lastKMLFilename, strReturn);
_tcsncpy(firstKMLFilename, strReturn, firstKMLFilenameSize);
(*jniEnv)->ReleaseStringUTFChars(jniEnv, resultString, strReturn);
return TRUE;
}
}
return result ? TRUE : FALSE;
}
}
return FALSE;
}
void clipboardCopyText(const TCHAR * text) {
JNIEnv *jniEnv = getJNIEnvironment();
if(jniEnv) {
@ -468,6 +458,29 @@ JNIEXPORT jstring JNICALL Java_org_emulator_calculator_NativeLib_getKMLTitle(JNI
return result;
}
JNIEXPORT jstring JNICALL Java_org_emulator_calculator_NativeLib_getCurrentKml(JNIEnv *env, jobject thisz) {
jstring result = (*env)->NewStringUTF(env, szCurrentKml);
return result;
}
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setCurrentKml(JNIEnv *env, jobject thisz, jstring currentKml) {
const char *currentKmlUTF8 = (*env)->GetStringUTFChars(env, currentKml, NULL);
_tcscpy(szCurrentKml, currentKmlUTF8);
(*env)->ReleaseStringUTFChars(env, currentKml, currentKmlUTF8);
}
JNIEXPORT jstring JNICALL Java_org_emulator_calculator_NativeLib_getEmuDirectory(JNIEnv *env, jobject thisz) {
jstring result = (*env)->NewStringUTF(env, szEmuDirectory);
return result;
}
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setEmuDirectory(JNIEnv *env, jobject thisz, jstring emuDirectory) {
const char *emuDirectoryUTF8 = (*env)->GetStringUTFChars(env, emuDirectory, NULL);
_tcscpy(szEmuDirectory, emuDirectoryUTF8);
_tcscpy(szRomDirectory, emuDirectoryUTF8);
(*env)->ReleaseStringUTFChars(env, emuDirectory, emuDirectoryUTF8);
}
JNIEXPORT jboolean JNICALL Java_org_emulator_calculator_NativeLib_getPort1Plugged(JNIEnv *env, jobject thisz) {
return (jboolean) ((Chipset.cards_status & PORT1_PRESENT) != 0);
}
@ -503,23 +516,20 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileNew(JNIEnv *
(*env)->ReleaseStringUTFChars(env, kmlFilename, filenameUTF8);
TCHAR * documentScheme = _T("document:");
TCHAR * urlSchemeFound = _tcsstr(szChosenCurrentKml, documentScheme);
if(urlSchemeFound) {
TCHAR * documentSchemeFound = _tcsstr(szChosenCurrentKml, documentScheme);
if(kmlFolder) {
const char *kmlFolderUTF8 = (*env)->GetStringUTFChars(env, kmlFolder, NULL);
// The folder URL is separated from the script filename and comes from the JSON settings in the state file.
_tcscpy(szEmuDirectory, kmlFolderUTF8);
_tcscpy(szRomDirectory, kmlFolderUTF8);
(*env)->ReleaseStringUTFChars(env, kmlFolder, kmlFolderUTF8);
} else {
} else if(documentSchemeFound) {
// Keep the compatibility by allowing to put the KML folder combined with the KML script filename with a document: scheme.
_tcscpy(szEmuDirectory, szChosenCurrentKml + _tcslen(documentScheme) * sizeof(TCHAR));
TCHAR * filename = _tcschr(szEmuDirectory, _T('|'));
if(filename) {
if(filename)
*filename = _T('\0');
}
_tcscpy(szRomDirectory, szEmuDirectory);
}
} else {
_tcscpy(szEmuDirectory, "assets/calculators/");
_tcscpy(szRomDirectory, "assets/calculators/");
@ -554,15 +564,23 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileOpen(JNIEnv
_tcscpy(szBufferFilename, stateFilenameUTF8);
(*env)->ReleaseStringUTFChars(env, stateFilename, stateFilenameUTF8);
chooseCurrentKmlMode = ChooseKmlMode_FILE_OPEN;
if(kmlFolder) {
const char *kmlFolderUTF8 = (*env)->GetStringUTFChars(env, kmlFolder, NULL);
// The folder URL is separated from the script filename (not in the document: URL) and comes from the JSON settings in the state file.
_tcscpy(szEmuDirectory, kmlFolderUTF8);
_tcscpy(szRomDirectory, kmlFolderUTF8);
(*env)->ReleaseStringUTFChars(env, kmlFolder, kmlFolderUTF8);
chooseCurrentKmlMode = ChooseKmlMode_FILE_OPEN_WITH_FOLDER;
} else {
// We are loading a KML script from the embedded asset folder inside the Android App.
// We directly set the variable "szEmuDirectory"/"szRomDirectory" and "szCurrentAssetDirectory" with the KML folder
// which contain the script and its dependencies like the includes, the images and the ROMs.
_tcscpy(szEmuDirectory, "assets/calculators/");
_tcscpy(szRomDirectory, "assets/calculators/");
}
chooseCurrentKmlMode = ChooseKmlMode_FILE_OPEN;
kmlFileNotFound = FALSE;
lastKMLFilename[0] = '\0';
BOOL result = OpenDocument(szBufferFilename);
if (result) {
@ -580,6 +598,10 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileOpen(JNIEnv
securityExceptionOccured = FALSE;
result = -2;
}
if(kmlFileNotFound) {
kmlFileNotFound = FALSE;
result = -3;
}
return result;
}
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileSave(JNIEnv *env, jobject thisz) {
@ -707,16 +729,6 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onObjectLoad(JNIEn
return TRUE;
}
JNIEXPORT jstring JNICALL Java_org_emulator_calculator_NativeLib_getCurrentKml(JNIEnv *env, jobject thisz) {
jstring result = (*env)->NewStringUTF(env, szCurrentKml);
return result;
}
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setCurrentKml(JNIEnv *env, jobject thisz, jstring currentKml) {
const char *currentKmlUTF8 = (*env)->GetStringUTFChars(env, currentKml, NULL);
_tcscpy(szCurrentKml, currentKmlUTF8);
(*env)->ReleaseStringUTFChars(env, currentKml, currentKmlUTF8);
}
JNIEXPORT jobjectArray JNICALL Java_org_emulator_calculator_NativeLib_getObjectsToSave(JNIEnv *env, jobject thisz) {
return 0;
}
@ -724,7 +736,6 @@ JNIEXPORT jobjectArray JNICALL Java_org_emulator_calculator_NativeLib_getObjects
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onObjectSave(JNIEnv *env, jobject thisz, jstring filename, jbooleanArray objectsToSaveItemChecked) {
const char *filenameUTF8 = (*env)->GetStringUTFChars(env, filename , NULL) ;
//OnObjectSave();
if (nState != SM_RUN)
{
@ -880,21 +891,27 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEn
// make a copy of the current KML script file name
lstrcpyn(szKmlFile,szCurrentKml,ARRAYSIZEOF(szKmlFile));
const char *filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename , NULL) ;
const char * filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename , NULL) ;
_tcscpy(szCurrentKml, filenameUTF8);
(*env)->ReleaseStringUTFChars(env, kmlFilename, filenameUTF8);
const char *kmlFolderUTF8 = (*env)->GetStringUTFChars(env, kmlFolder, NULL);
if(kmlFolderUTF8) {
if(kmlFolder) {
const char * kmlFolderUTF8 = (*env)->GetStringUTFChars(env, kmlFolder, NULL);
// The folder URL is separated from the script filename and comes from the JSON settings in the state file.
_tcscpy(szEmuDirectory, kmlFolderUTF8);
_tcscpy(szRomDirectory, kmlFolderUTF8);
(*env)->ReleaseStringUTFChars(env, kmlFolder, kmlFolderUTF8);
} else {
// We are loading a KML script from the embedded asset folder inside the Android App.
// We directly set the variable "szEmuDirectory"/"szRomDirectory" and "szCurrentAssetDirectory" with the KML folder
// which contain the script and its dependencies like the includes, the images and the ROMs.
_tcscpy(szEmuDirectory, "assets/calculators/");
_tcscpy(szRomDirectory, "assets/calculators/");
}
chooseCurrentKmlMode = ChooseKmlMode_CHANGE_KML;
BOOL bSucc = InitKML(szCurrentKml,FALSE);
BOOL bSucc = InitKML(szCurrentKml, FALSE);
if(!bSucc) {
// restore KML script file name
@ -903,13 +920,13 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEn
_tcsncpy(szKmlLogBackup, szKmlLog, sizeof(szKmlLog) / sizeof(TCHAR));
// try to restore old KML script
bSucc = InitKML(szCurrentKml,FALSE);
bSucc = InitKML(szCurrentKml, FALSE);
_tcsncpy(szKmlLog, szKmlLogBackup, sizeof(szKmlLog) / sizeof(TCHAR));
}
chooseCurrentKmlMode = ChooseKmlMode_UNKNOWN;
if (bSucc) {
if(bSucc) {
if(hLcdDC && hLcdDC->selectedBitmap) {
hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight = -abs(hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight);
}

View file

@ -41,6 +41,7 @@ size_t assetsPrefixLength;
const TCHAR * contentScheme = _T("content://");
size_t contentSchemeLength;
const TCHAR * documentScheme = _T("document:");
size_t documentSchemeLength;
TCHAR szFilePathTmp[MAX_PATH];
@ -64,6 +65,7 @@ void win32Init() {
assetsPrefixLength = _tcslen(assetsPrefix);
contentSchemeLength = _tcslen(contentScheme);
documentSchemeLength = _tcslen(documentScheme);
}
int abs (int i) {
@ -120,12 +122,13 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
}
#endif
TCHAR * foundDocumentScheme = _tcsstr(lpFileName, documentScheme);
TCHAR * urlContentSchemeFound = _tcsstr(lpFileName, contentScheme);
BOOL foundDocumentScheme = _tcsncmp(lpFileName, documentScheme, documentSchemeLength) == 0;
BOOL urlContentSchemeFound = _tcsncmp(lpFileName, contentScheme, contentSchemeLength) == 0;
if(chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN || chooseCurrentKmlMode == ChooseKmlMode_CHANGE_KML) {
if(chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN /*|| chooseCurrentKmlMode == ChooseKmlMode_CHANGE_KML*/) {
// A E48 state file can contain a path to the KML script.
if(foundDocumentScheme) {
// Keep for compatibility:
// When the state file is created or saved with this Android version,
// an URL like: document:content://<KMLFolderURL>|content://<KMLFileURL>
// is created and saved in the state file.
@ -147,44 +150,13 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
#endif
SetCurrentDirectory(szFilePathTmp);
}
} else {
TCHAR * fileExtension = _tcsrchr(lpFileName, _T('.'));
if (fileExtension &&
((fileExtension[1] == 'K' && fileExtension[2] == 'M' && fileExtension[3] == 'L') ||
(fileExtension[1] == 'k' && fileExtension[2] == 'm' && fileExtension[3] == 'l')
)) {
if(lpFileName[0] == '/') {
// We are loading a standard KML script from the folder inside the filesystem.
// We directly set the variable "szEmuDirectory"/"szRomDirectory" and "szCurrentAssetDirectory" with the KML folder
// which contain the script and its dependencies like the includes, the images and the ROMs.
// Deprecated, not supported by Android >= 10.
_tcscpy(szEmuDirectory, lpFileName);
TCHAR * filename = _tcsrchr(szEmuDirectory, _T('/'));
if(filename) {
*filename = _T('\0');
}
#if EMUXX == 48
_tcscpy(szRomDirectory, szEmuDirectory);
#endif
SetCurrentDirectory(szEmuDirectory);
} else {
// We are loading a KML script from the embedded asset folder inside the Android App.
// We directly set the variable "szEmuDirectory"/"szRomDirectory" and "szCurrentAssetDirectory" with the KML folder
// which contain the script and its dependencies like the includes, the images and the ROMs.
_tcscpy(szEmuDirectory, "assets/calculators/");
#if EMUXX == 48
_tcscpy(szRomDirectory, "assets/calculators/");
#endif
SetCurrentDirectory(szEmuDirectory);
}
}
}
}
if(!forceNormalFile
&& (szCurrentAssetDirectory || _tcsncmp(lpFileName, assetsPrefix, assetsPrefixLength) == 0)
&& foundDocumentScheme == NULL
&& urlContentSchemeFound == NULL) {
&& !foundDocumentScheme
&& !urlContentSchemeFound) {
// Loading a file from the Android asset folders (embedded in the app)
TCHAR szFileName[MAX_PATH];
AAsset * asset = NULL;
@ -236,9 +208,8 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
// Case of an absolute file with the scheme "content://".
fd = openFileFromContentResolver(lpFileName, dwDesiredAccess);
useOpenFileFromContentResolver = TRUE;
if(fd < 0) {
if(fd == -2) {
FILE_LOGD("CreateFile() openFileFromContentResolver() %d", errno);
if(fd == -2)
securityExceptionOccured = TRUE;
}
} else if(szCurrentContentDirectory) {
@ -2920,21 +2891,17 @@ PIDLIST_ABSOLUTE SHBrowseForFolderA(LPBROWSEINFOA lpbi) {
#define IDD_USERCODE 121
#endif
INT_PTR DialogBoxParam(HINSTANCE hInstance, LPCTSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) {
//TODO
if(lpTemplateName == MAKEINTRESOURCE(IDD_CHOOSEKML)) {
if(chooseCurrentKmlMode == ChooseKmlMode_UNKNOWN) {
} else if(chooseCurrentKmlMode == ChooseKmlMode_FILE_NEW) {
lstrcpy(szCurrentKml, szChosenCurrentKml);
} else if(chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN) {
} else if(chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN || chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN_WITH_FOLDER) {
// We are here because we open a state file and the embedded KML path is not reachable.
// So, we try to find a correct KML file in the current Custom KML scripts folder.
if(!getFirstKMLFilenameForType(Chipset.type, szCurrentKml, sizeof(szCurrentKml) / sizeof(szCurrentKml[0]))) {
showAlert(_T("Cannot find the KML template file, sorry."), 0);
if(!getFirstKMLFilenameForType(Chipset.type)) {
kmlFileNotFound = TRUE;
return -1;
}
// else {
// showAlert(_T("Cannot find the KML template file, so, try another one."), 0); //TODO is it right?
// }
}
} else if(lpTemplateName == MAKEINTRESOURCE(IDD_KMLLOG)) {
lpDialogFunc(NULL, WM_INITDIALOG, 0, 0);
@ -3149,3 +3116,4 @@ int win32_select(int __fd_count, fd_set* __read_fds, fd_set* __write_fds, fd_set
}
return select(__fd_count, __read_fds, __write_fds, __exception_fds, __timeout);
}

View file

@ -1222,7 +1222,8 @@ enum ChooseKmlMode {
ChooseKmlMode_UNKNOWN,
ChooseKmlMode_FILE_NEW,
ChooseKmlMode_FILE_OPEN,
ChooseKmlMode_CHANGE_KML
ChooseKmlMode_FILE_OPEN_WITH_FOLDER,
ChooseKmlMode_CHANGE_KML //TODO To remove
};
extern enum ChooseKmlMode chooseCurrentKmlMode;
enum DialogBoxMode {
@ -1236,13 +1237,14 @@ enum DialogBoxMode {
};
extern enum DialogBoxMode currentDialogBoxMode;
extern BOOL securityExceptionOccured;
extern BOOL kmlFileNotFound;
#define MAX_LABEL_SIZE 5000
extern TCHAR labels[MAX_LABEL_SIZE];
#define MAX_ITEMDATA 100
extern int selItemDataIndex[MAX_ITEMDATA];
extern int selItemDataCount;
extern TCHAR getSaveObjectFilenameResult[MAX_PATH];
BOOL getFirstKMLFilenameForType(BYTE chipsetType, TCHAR * firstKMLFilename, size_t firstKMLFilenameSize);
BOOL getFirstKMLFilenameForType(BYTE chipsetType);
void clipboardCopyText(const TCHAR * text);
const TCHAR * clipboardPasteText();
void performHapticFeedback();

View file

@ -46,6 +46,10 @@ public class NativeLib {
public static native boolean isBackup();
public static native String getKMLLog();
public static native String getKMLTitle();
public static native String getCurrentKml();
public static native void setCurrentKml(String currentKml);
public static native String getEmuDirectory();
public static native void setEmuDirectory(String emuDirectory);
public static native boolean getPort1Plugged();
public static native boolean getPort1Writable();
public static native boolean getSoundEnabled();
@ -58,8 +62,6 @@ public class NativeLib {
public static native int onFileSaveAs(String newFilename);
public static native int onFileClose();
public static native int onObjectLoad(String filename);
public static native String getCurrentKml();
public static native void setCurrentKml(String currentKml);
public static native String[] getObjectsToSave();
public static native int onObjectSave(String filename, boolean[] objectsToSaveItemChecked);

View file

@ -44,7 +44,11 @@ import javax.microedition.khronos.egl.EGLDisplay;
public class Utils {
public static void showAlert(Context context, String text) {
Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
showAlert(context, text, false);
}
public static void showAlert(Context context, String text, boolean lengthLong) {
Toast toast = Toast.makeText(context, text, lengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
//View view = toast.getView();
//view.setBackgroundColor(0x80000000);
toast.show();

View file

@ -51,6 +51,7 @@ import androidx.core.content.FileProvider;
import androidx.core.view.GravityCompat;
import androidx.documentfile.provider.DocumentFile;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import com.google.android.material.navigation.NavigationView;
@ -108,15 +109,23 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public static final int INTENT_PICK_KML_FOLDER_FOR_NEW_FILE = 7;
public static final int INTENT_PICK_KML_FOLDER_FOR_CHANGING = 8;
public static final int INTENT_PICK_KML_FOLDER_FOR_SECURITY = 10;
public static final int INTENT_CREATE_RAM_CARD = 11;
public static final int INTENT_MACRO_LOAD = 12;
public static final int INTENT_MACRO_SAVE = 13;
public static final int INTENT_PICK_KML_FOLDER_FOR_KML_NOT_FOUND = 11;
public static final int INTENT_CREATE_RAM_CARD = 12;
public static final int INTENT_MACRO_LOAD = 13;
public static final int INTENT_MACRO_SAVE = 14;
public static String intentPickKmlFolderForUrlToOpen;
public String urlToOpenInIntentPort2Load;
public String kmlScriptFolderInIntentPort2Load;
private String kmlMimeType = "application/vnd.google-earth.kml+xml";
private boolean kmlFolderUseDefault = true;
private String kmlFolderURL = "";
private boolean kmlFolderChange = true;
private boolean saveWhenLaunchingActivity = true;
private int selectedRAMSize = -1;
private boolean[] objectsToSaveItemChecked = null;
@ -207,9 +216,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
documentToOpenUri = intent.getData();
if (documentToOpenUri != null) {
String scheme = documentToOpenUri.getScheme();
if(scheme != null && scheme.compareTo("file") == 0) {
if(scheme != null && scheme.compareTo("file") == 0)
documentToOpenUrl = null;
} else
else
documentToOpenUrl = documentToOpenUri.toString();
}
} else if (action.equals(Intent.ACTION_SEND)) {
@ -223,11 +232,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if(documentToOpenUrl != null && documentToOpenUrl.length() > 0)
try {
if(onFileOpen(documentToOpenUrl) != 0) {
saveLastDocument(documentToOpenUrl);
if(intent != null && documentToOpenUri != null)
Utils.makeUriPersistable(this, intent, documentToOpenUri);
}
// FileOpen auto-open.
onFileOpen(documentToOpenUrl, intent, null);
} catch (Exception e) {
if(debug) Log.e(TAG, e.getMessage());
}
@ -272,13 +278,12 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override
protected void onStop() {
//TODO We cannot make the difference between going to the settings or loading/saving a file and a real app stop/kill!
// -> Maybe by settings some flags when loading/saving
if(saveWhenLaunchingActivity) {
settings.putStringSet("MRU", mruLinkedHashMap.keySet());
if(lcdOverlappingView != null)
if (lcdOverlappingView != null)
lcdOverlappingView.saveViewLayout();
if(NativeLib.isDocumentAvailable() && settings.getBoolean("settings_autosave", true)) {
if (NativeLib.isDocumentAvailable() && settings.getBoolean("settings_autosave", true)) {
String currentFilename = NativeLib.getCurrentFilename();
if (currentFilename != null && currentFilename.length() > 0)
onFileSave();
@ -287,6 +292,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
settings.saveApplicationSettings();
clearFolderCache();
}
super.onStop();
}
@ -393,13 +399,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
mruLinkedHashMap.get(url);
ensureDocumentSaved(() -> {
if(onFileOpen(url) != 0) {
saveLastDocument(url);
} else {
// We should remove this file from the MRU list because it might be deleted or the permissions does not allow to reach it anymore.
mruLinkedHashMap.remove(url);
navigationView.post(this::updateMRU);
}
// FileOpen from MRU.
onFileOpen(url, null, null);
});
}
@ -408,6 +409,14 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
return true;
}
private void removeMRU(String url) {
// We should remove this file from the MRU list because it might be deleted or the permissions does not allow to reach it anymore.
if(mruLinkedHashMap.containsKey(url)) {
mruLinkedHashMap.remove(url);
navigationView.post(this::updateMRU);
}
}
private void updateNavigationDrawerItems() {
Menu menu = navigationView.getMenu();
boolean isBackup = NativeLib.isBackup();
@ -437,7 +446,34 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
menu.findItem(R.id.nav_macro_stop).setEnabled(uRun && nMacroState != 0 /* MACRO_OFF */);
}
class KMLScriptItem {
private void loadKMLFolder() {
kmlFolderUseDefault = settings.getBoolean("settings_kml_default", true);
if (!kmlFolderUseDefault) {
kmlFolderURL = settings.getString("settings_kml_folder", "");
// https://github.com/googlesamples/android-DirectorySelection
// https://stackoverflow.com/questions/44185477/intent-action-open-document-tree-doesnt-seem-to-return-a-real-path-to-drive/44185706
// https://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-android-5-0-lollipop
}
kmlFolderChange = true;
}
private void changeKMLFolder(String url) {
if(url == null || url.startsWith("assets/")) {
if(!kmlFolderUseDefault)
kmlFolderChange = true;
kmlFolderUseDefault = true;
settings.putBoolean("settings_kml_default", true);
} else {
if(kmlFolderUseDefault || !url.equals(kmlFolderURL))
kmlFolderChange = true;
kmlFolderUseDefault = false;
kmlFolderURL = url;
settings.putBoolean("settings_kml_default", false);
settings.putString("settings_kml_folder", kmlFolderURL);
}
}
static class KMLScriptItem {
public String filename;
public String folder;
public String title;
@ -565,8 +601,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if (inGlobal) {
if (mLine.indexOf("End") == 0) {
KMLScriptItem newKMLScriptItem = new KMLScriptItem();
//newKMLScriptItem.filename = kmlFolderUseDefault ? calculatorFilename : "document:" + kmlFolderURL + "|" + calculatorFilename;
newKMLScriptItem.filename = "document:|" + calculatorFilename;
newKMLScriptItem.filename = documentFile.getName();
newKMLScriptItem.folder = kmlFolderURL;
newKMLScriptItem.title = title;
newKMLScriptItem.model = model;
@ -672,9 +707,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
showCalculatorView(true);
displayFilename("");
showKMLLog();
if(kmlScriptFolder != null) {
// Note: kmlScriptFolder should be equal to kmlFolderURL!
// We keep the global settings_kml_folder distinct from embedded settings_kml_folder_embedded.
settings.putString("settings_kml_folder_embedded", kmlScriptFolder);
}
suggestToSaveNewFile();
} else
showKMLLogForce();
@ -695,6 +732,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.filename) + "-state.e48");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_GETOPENFILENAME);
});
}
@ -734,6 +772,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
break;
}
intent.putExtra(Intent.EXTRA_TITLE, filename);
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_GETSAVEFILENAME);
}
private void OnFileClose() {
@ -785,6 +824,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.filename) + "-object.hp");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_OBJECT_LOAD);
}
@ -808,6 +848,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.filename) + "-object.hp");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_OBJECT_SAVE);
}
private void OnViewCopyFullscreen() {
@ -932,6 +973,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
.setTitle(getResources().getString(R.string.pick_calculator))
.setItems(kmlScriptTitles, (dialog, which) -> {
if(which == lastIndex) {
// [Select a Custom KML script folder...]
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // < API 21
new AlertDialog.Builder(MainActivity.this)
.setTitle(getString(R.string.message_kml_folder_selection_need_api_lollipop))
@ -940,17 +982,18 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}).show();
} else {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
saveWhenLaunchingActivity = false;
startActivityForResult(intent, changeKML ? INTENT_PICK_KML_FOLDER_FOR_CHANGING : INTENT_PICK_KML_FOLDER_FOR_NEW_FILE);
}
} else if(which == lastIndex + 1) {
// Reset to default KML folder
settings.putBoolean("settings_kml_default", true);
updateFromPreferences("settings_kml", true);
// [Default KML script folder]
changeKMLFolder(null);
if(changeKML)
OnViewScript();
else
OnFileNew();
} else {
// We choose a calculator name from the list.
KMLScriptItem scriptItem = kmlScriptsForCurrentModel.get(which);
if(changeKML) {
// We only change the KML script here.
@ -1009,6 +1052,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
break;
}
intent.putExtra(Intent.EXTRA_TITLE, "shared-" + sizeTitle + ".bin");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_CREATE_RAM_CARD);
}).show();
}
@ -1018,6 +1062,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.filename) + "-macro.mac");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_MACRO_SAVE);
}
@ -1026,6 +1071,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.filename) + "-macro.mac");
saveWhenLaunchingActivity = false;
startActivityForResult(intent, INTENT_MACRO_LOAD);
}
@ -1054,20 +1100,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
switch (requestCode) {
case INTENT_GETOPENFILENAME: {
if(debug) Log.d(TAG, "onActivityResult INTENT_GETOPENFILENAME " + url);
int openResult = onFileOpen(url);
if (openResult > 0) {
saveLastDocument(url);
Utils.makeUriPersistable(this, data, uri);
} else if(openResult == -2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // >= API 21
// For security reason, you must select the folder where are the KML and ROM files and then, reopen this file!
new AlertDialog.Builder(this)
.setTitle(getString(R.string.message_open_security))
.setMessage(getString(R.string.message_open_security_description))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY);
}).show();
}
// FileOpen from the "Open..." menu.
onFileOpen(url, data, null);
break;
}
case INTENT_GETSAVEFILENAME: {
@ -1093,13 +1127,26 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
NativeLib.onObjectSave(url, null);
break;
}
case INTENT_PORT2LOAD: {
if(debug) Log.d(TAG, "onActivityResult INTENT_PORT2LOAD " + url);
//TODO Duplicate code in SettingsFragment!
settings.putString("settings_port2load", url);
Utils.makeUriPersistable(this, data, uri);
if(urlToOpenInIntentPort2Load != null) {
onFileOpenNative(urlToOpenInIntentPort2Load, kmlScriptFolderInIntentPort2Load);
urlToOpenInIntentPort2Load = null;
kmlScriptFolderInIntentPort2Load = null;
}
break;
}
case INTENT_PICK_KML_FOLDER_FOR_NEW_FILE:
case INTENT_PICK_KML_FOLDER_FOR_CHANGING:
case INTENT_PICK_KML_FOLDER_FOR_SECURITY: {
if(debug) Log.d(TAG, "onActivityResult INTENT_PICK_KML_FOLDER " + url);
settings.putBoolean("settings_kml_default", false);
settings.putString("settings_kml_folder", url);
updateFromPreferences("settings_kml", true);
case INTENT_PICK_KML_FOLDER_FOR_SECURITY:
case INTENT_PICK_KML_FOLDER_FOR_KML_NOT_FOUND:
{
if(debug) Log.d(TAG, "onActivityResult INTENT_PICK_KML_FOLDER_X " + url);
changeKMLFolder(url);
Utils.makeUriPersistableReadOnly(this, data, uri);
switch (requestCode) {
@ -1110,6 +1157,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
OnViewScript();
break;
case INTENT_PICK_KML_FOLDER_FOR_SECURITY:
case INTENT_PICK_KML_FOLDER_FOR_KML_NOT_FOUND:
if(intentPickKmlFolderForUrlToOpen != null)
onFileOpen(intentPickKmlFolderForUrlToOpen, null, url);
else
new AlertDialog.Builder(this)
.setTitle(getString(R.string.message_open_security_retry))
.setMessage(getString(R.string.message_open_security_retry_description))
@ -1159,7 +1210,12 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
break;
}
}
} else {
// resultCode == Activity.RESULT_CANCELED
urlToOpenInIntentPort2Load = null;
kmlScriptFolderInIntentPort2Load = null;
}
saveWhenLaunchingActivity = true;
fileSaveAsCallback = null;
super.onActivityResult(requestCode, resultCode, data);
}
@ -1186,59 +1242,159 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
}
private int onFileOpen(String url) {
private void onFileOpen(String url, Intent intent, String openWithKMLScriptFolder) {
// Eventually, close the previous state file
NativeLib.onFileClose();
showCalculatorView(false);
displayFilename("");
intentPickKmlFolderForUrlToOpen = null;
// Pre-Load the embedded settings from the end of the classic state file
settings.setIsDefaultSettings(false);
settings.clearEmbeddedStateSettings();
settings.loadFromStateFile(this, url);
String kmlScriptFolder = settings.getString("settings_kml_folder_embedded", null);
if(intent != null)
// Make this file persistable to allow a next access to this same file.
Utils.makeUriPersistable(this, intent, Uri.parse(url));
// Update the Emu VM with the new settings
String kmlScriptFolder = null;
String embeddedKMLScriptFolder = settings.getString("settings_kml_folder_embedded", null);
if(openWithKMLScriptFolder != null)
kmlScriptFolder = openWithKMLScriptFolder;
else
kmlScriptFolder = embeddedKMLScriptFolder;
if(kmlScriptFolder != null && !kmlScriptFolder.startsWith("assets/")) {
// Change the default KMLFolder to allow getFirstKMLFilenameForType() to find in the specific folder!
Uri kmlFolderUri = Uri.parse(kmlScriptFolder);
DocumentFile kmlFolderDocumentFile = DocumentFile.fromTreeUri(this, kmlFolderUri);
if(kmlFolderDocumentFile != null && kmlFolderDocumentFile.exists())
changeKMLFolder(kmlScriptFolder);
}
if(settings.getBoolean("settings_port2en", false)) {
// Check if the access to the port2 shared file is still possible.
String port2Url = settings.getString("settings_port2load", "");
if(port2Url != null && port2Url.length() > 0) {
Uri port2Uri = Uri.parse(port2Url);
DocumentFile port2DocumentFile = DocumentFile.fromSingleUri(this, port2Uri);
if (port2DocumentFile == null || !port2DocumentFile.exists()) {
//showAlert("Cannot access to the port 2 file!");
String port2Filename = getFilenameFromURL(port2Url);
String finalKmlScriptFolder = kmlScriptFolder;
new AlertDialog.Builder(this)
.setTitle(getString(R.string.message_open_port2_file_not_found))
.setMessage(String.format(Locale.US, getString(R.string.message_open_port2_file_not_found_description), port2Filename))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
urlToOpenInIntentPort2Load = url;
kmlScriptFolderInIntentPort2Load = finalKmlScriptFolder;
Intent intentPort2 = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intentPort2.addCategory(Intent.CATEGORY_OPENABLE);
intentPort2.setType("*/*");
intentPort2.putExtra(Intent.EXTRA_TITLE, "shared.bin");
saveWhenLaunchingActivity = false;
startActivityForResult(intentPort2, MainActivity.INTENT_PORT2LOAD);
}).setNegativeButton(android.R.string.cancel, (dialog, which) -> {
// Deactivate the port2 because it is not reachable.
settings.putBoolean("settings_port2en", false);
onFileOpenNative(url, finalKmlScriptFolder);
}).show();
return;
}
}
}
onFileOpenNative(url, kmlScriptFolder);
}
private void onFileOpenNative(String url, String kmlScriptFolder) {
// Update the Emu VM with the new settings.
updateFromPreferences(null, false);
// Load the genuine state file
int result = NativeLib.onFileOpen(url, kmlScriptFolder);
if(result > 0) {
setPort1Settings(NativeLib.getPort1Plugged(), NativeLib.getPort1Writable()); //TODO is it in the true state file or in settings?
// Copy the port1 settings from the state file to the settings (for the UI).
setPort1Settings(NativeLib.getPort1Plugged(), NativeLib.getPort1Writable());
// State file successfully opened.
if(kmlScriptFolder == null) {
// Needed for compatibility:
// The KML folder is not in the JSON settings embedded in the state file,
// so, we need to extract it and change the variable szCurrentKml
// so, we need to extract it and change the variable szCurrentKml.
String currentKml = NativeLib.getCurrentKml();
Pattern patternKMLDocumentURL = Pattern.compile("document:([^|]*)\\|(.+)");
Pattern patternKMLDocumentURL = Pattern.compile("document:([^|]+)\\|(.+)");
Matcher m = patternKMLDocumentURL.matcher(currentKml);
if (m.find() && m.groupCount() == 2) {
kmlScriptFolder = m.group(1);
String kmlScriptFilename = m.group(2);
if(kmlScriptFolder != null && kmlScriptFolder.length() > 0) {
settings.putString("settings_kml_folder_embedded", kmlScriptFolder);
NativeLib.setCurrentKml("document:|" + kmlScriptFilename);
String kmlScriptFolderInDocument = m.group(1);
String kmlScriptFilenameInDocument = m.group(2);
kmlScriptFolder = kmlScriptFolderInDocument;
NativeLib.setCurrentKml(kmlScriptFilenameInDocument);
} else {
//TODO We should prompt the user to choose the KML folder?
// It should not happen here with custom KML folder because result should be 0!
// Should not happen... But in case.
kmlScriptFolder = NativeLib.getEmuDirectory();
}
}
// String kmlScriptFolder = NativeLib.getEmuDirectory();
// settings.putString("settings_kml_folder_embedded", kmlScriptFolder);
}
settings.putString("settings_kml_folder_embedded", kmlScriptFolder);
changeKMLFolder(kmlScriptFolder);
showCalculatorView(true);
displayFilename(url);
saveLastDocument(url);
showKMLLog();
} else {
// Because it failed to load the state file, we switch to the default settings
// Because the state file failed to load, we switch to the default settings.
settings.setIsDefaultSettings(true);
settings.clearEmbeddedStateSettings();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP // >= API 21
&& (result < 0 || kmlScriptFolder == null)) {
// If the KML file takes an access denied (-2) or the KML file has not been found (-3) or kmlScriptFolder is null,
// we must prompt the use to choose one (after onFileOpen to know the model)!
if(result == -2)
// For security reason, you must select the folder where are the KML and ROM files and then, reopen this file!
new AlertDialog.Builder(this)
.setTitle(getString(R.string.message_open_security))
.setMessage(getString(R.string.message_open_security_description))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
intentPickKmlFolderForUrlToOpen = url;
saveWhenLaunchingActivity = false;
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), INTENT_PICK_KML_FOLDER_FOR_SECURITY);
}).setNegativeButton(android.R.string.cancel, (dialog, which) -> {
removeMRU(url);
}).show();
else if(result == -3 || kmlScriptFolder == null) {
// KML file (or a compatible KML file) has not been found, you must select the folder where are the KML and ROM files and then, reopen this file!
String currentKml = NativeLib.getCurrentKml();
String description;
if(currentKml != null) {
if(kmlScriptFolder != null)
description = String.format(Locale.US, getString(R.string.message_open_kml_not_found_description3), currentKml, kmlScriptFolder);
else
description = String.format(Locale.US, getString(R.string.message_open_kml_not_found_description2), currentKml);
} else
description = getString(R.string.message_open_kml_not_found_description);
new AlertDialog.Builder(this)
.setTitle(getString(R.string.message_open_kml_not_found))
.setMessage(description)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
intentPickKmlFolderForUrlToOpen = url;
saveWhenLaunchingActivity = false;
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), INTENT_PICK_KML_FOLDER_FOR_KML_NOT_FOUND);
}).setNegativeButton(android.R.string.cancel, (dialog, which) -> {
removeMRU(url);
}).show();
} else
removeMRU(url);
} else {
// Show the KML error
showKMLLogForce();
removeMRU(url);
}
}
updateNavigationDrawerItems();
return result;
}
private void onFileSave() {
@ -1364,7 +1520,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@SuppressWarnings("unused")
public int openFileInFolderFromContentResolver(String filename, String folderURL, int writeAccess) {
if(folderURLCached == null || !folderURLCached.equals(folderURL)) {
if(filename != null) {
if(filename.startsWith("content://"))
return openFileFromContentResolver(filename, writeAccess);
if (folderURLCached == null || !folderURLCached.equals(folderURL)) {
folderURLCached = folderURL;
folderCache.clear();
Uri folderURI = Uri.parse(folderURL);
@ -1374,8 +1533,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
folderCache.put(file.getName(), file.getUri().toString());
}
String filenameUrl = folderCache.get(filename);
if(filenameUrl != null)
if (filenameUrl != null)
return openFileFromContentResolver(filenameUrl, writeAccess);
}
return -1;
}
@ -1397,7 +1557,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
public void showAlert(String text) {
Utils.showAlert(this, text);
showAlert(text, false);
}
public void showAlert(String text, boolean lengthLong) {
Utils.showAlert(this, text, lengthLong);
}
@SuppressWarnings("unused")
@ -1480,30 +1644,38 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
@SuppressWarnings("unused")
public String getFirstKMLFilenameForType(char chipsetType) {
public int getFirstKMLFilenameForType(char chipsetType) {
if(!kmlFolderUseDefault) {
extractKMLScripts();
for (int i = 0; i < kmlScripts.size(); i++) {
KMLScriptItem kmlScriptItem = kmlScripts.get(i);
if (kmlScriptItem.model.charAt(0) == chipsetType) {
return kmlScriptItem.filename;
showAlert(String.format(Locale.US, "Existing KML script not found. Trying the compatible script: %s", kmlScriptItem.filename), true);
NativeLib.setCurrentKml(kmlScriptItem.filename);
NativeLib.setEmuDirectory(kmlFolderURL);
return 1;
}
}
// Not found, so we search in the default KML asset folder
kmlFolderUseDefault = true;
kmlFolderChange = true;
}
extractKMLScripts();
for (int i = 0; i < kmlScripts.size(); i++) {
KMLScriptItem kmlScriptItem = kmlScripts.get(i);
if (kmlScriptItem.model.charAt(0) == chipsetType) {
return kmlScriptItem.filename;
showAlert(String.format(Locale.US, "Existing KML script not found. Trying the embedded and compatible script: %s", kmlScriptItem.filename), true);
NativeLib.setCurrentKml(kmlScriptItem.filename);
NativeLib.setEmuDirectory("assets/calculators/");
return 1;
}
}
return null;
showAlert("Cannot find the KML template file, sorry.", true);
return 0;
}
@SuppressWarnings("unused")
@ -1552,11 +1724,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
bitmapIcon.copyPixelsFromBuffer(buffer);
} catch (Exception ex) {
// Cannot load the icon
// bitmapIcon.recycle();
bitmapIcon = null;
}
} else if(bitmapIcon != null) {
// bitmapIcon.recycle();
bitmapIcon = null;
}
if(bitmapIcon == null)
@ -1580,10 +1750,12 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
private void setPort1Settings(boolean port1Plugged, boolean port1Writable) {
if(this.getClass().getPackage().getName().equals("org.emulator.forty.eight")) {
settings.putBoolean("settings_port1en", port1Plugged);
settings.putBoolean("settings_port1wr", port1Writable);
updateFromPreferences("settings_port1", true);
}
}
private void updateFromPreferences(String key, boolean isDynamic) {
int isDynamicValue = isDynamic ? 1 : 0;
@ -1683,14 +1855,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
case "settings_kml":
case "settings_kml_default":
case "settings_kml_folder":
kmlFolderUseDefault = settings.getBoolean("settings_kml_default", true);
if (!kmlFolderUseDefault) {
kmlFolderURL = settings.getString("settings_kml_folder", "");
// https://github.com/googlesamples/android-DirectorySelection
// https://stackoverflow.com/questions/44185477/intent-action-open-document-tree-doesnt-seem-to-return-a-real-path-to-drive/44185706
// https://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-android-5-0-lollipop
}
kmlFolderChange = true;
loadKMLFolder();
break;
case "settings_macro":

View file

@ -77,10 +77,16 @@
<string name="ram_cards_item_5">2mb (16 ports: 2 through 17)</string>
<string name="ram_cards_item_6">4mb (32 ports: 2 through 33)</string>
<string name="message_open_security">Permission Denied</string>
<string name="message_open_security_description">For security reason, you must select the folder where are the KML and ROM files and then, reopen this file!</string>
<string name="message_open_security_description">For security reason, you must select the folder where are the KML and ROM files, please.</string>
<string name="message_open_security_retry">Please, open again</string>
<string name="message_open_security_retry_description">I hope now you could open again the state file.</string>
<string name="message_state_saved">State saved in "%s".</string>
<string name="message_open_kml_not_found">KML Script not Found</string>
<string name="message_open_kml_not_found_description">You must select the folder where are the KML and ROM files, please.</string>
<string name="message_open_kml_not_found_description2">The KML script "%s" cannot be found. You must select the folder where are the KML and ROM files, please.</string>
<string name="message_open_kml_not_found_description3">The KML script "%s" cannot be found in the folder "%s". You must select the folder where are the KML and ROM files, please.</string>
<string name="message_open_port2_file_not_found">Port 2 File not Found</string>
<string name="message_open_port2_file_not_found_description">The port 2 file "%s" cannot be found. You should select it again, please.</string>
<string name="message_state_saved">State saved in %s</string>
<string name="message_do_you_want_to_save">Do you want to save changes?\n(BACK to cancel)</string>
<string name="message_save_new_file">Do you want to save this new state file?\n(To avoid losing the state of the machine)</string>
<string name="message_yes">Yes</string>