mirror of
https://github.com/dgis/emu48android
synced 2025-01-29 08:34:25 +01:00
* Remove the KML folder from the KML URL.
* Add the state file name in the save toast.
This commit is contained in:
parent
588c5dc3df
commit
c5d135d73f
9 changed files with 207 additions and 139 deletions
18
ReadMe.txt
18
ReadMe.txt
|
@ -196,9 +196,23 @@ 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".
|
||||
- The clock seems unsynchronized sometimes.
|
||||
- Bug: In Xiaomi mi A3 under Android10, the haptic feedback does not work (add an intensity setting).
|
||||
- Somehow LEFT (Shift on the keyboard) + 7 activates the DIVIDE-key (z-Key)..., but with the NUM-Key it can make it work without problems...
|
||||
I think it might have something to do with the "/" sign on the Shifted-7-key.
|
||||
- The render pixels are very nice. A solution to obtain uniform pixel size could be a preset (a multiplier, auto) so the user could decide and upscale/downscale (Michael P).
|
||||
- The clock seems unsynchronized sometimes (Michael P).
|
||||
- Retain a key by right clicking if it is from a mouse.
|
||||
- Add the possibility to load and save the flash in another file.
|
||||
- Sometimes, the calculator seems to lag and finally freeze.
|
||||
|
@ -209,7 +223,7 @@ TODO
|
|||
|
||||
BUILD
|
||||
|
||||
Emu48 for Android is built with Android Studio 3.5 (2019).
|
||||
Emu48 for Android is built with Android Studio 4.0 (2020).
|
||||
And to generate an installable APK file with a real Android device, it MUST be signed.
|
||||
|
||||
Either use Android Studio:
|
||||
|
|
|
@ -489,29 +489,37 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getMacroState(JNIE
|
|||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileNew(JNIEnv *env, jobject thisz, jstring kmlFilename) {
|
||||
if (bDocumentAvail)
|
||||
{
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileNew(JNIEnv *env, jobject thisz, jstring kmlFilename, jstring kmlFolder) {
|
||||
if (bDocumentAvail) {
|
||||
SwitchToState(SM_INVALID);
|
||||
if(bAutoSave) {
|
||||
SaveDocument();
|
||||
}
|
||||
}
|
||||
|
||||
const char *filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename , NULL) ;
|
||||
const char *filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename, NULL);
|
||||
chooseCurrentKmlMode = ChooseKmlMode_FILE_NEW;
|
||||
_tcscpy(szChosenCurrentKml, filenameUTF8);
|
||||
(*env)->ReleaseStringUTFChars(env, kmlFilename, filenameUTF8);
|
||||
|
||||
TCHAR * fileScheme = _T("document:");
|
||||
TCHAR * urlSchemeFound = _tcsstr(szChosenCurrentKml, fileScheme);
|
||||
TCHAR * documentScheme = _T("document:");
|
||||
TCHAR * urlSchemeFound = _tcsstr(szChosenCurrentKml, documentScheme);
|
||||
if(urlSchemeFound) {
|
||||
_tcscpy(szEmuDirectory, szChosenCurrentKml + _tcslen(fileScheme) * sizeof(TCHAR));
|
||||
TCHAR * filename = _tcschr(szEmuDirectory, _T('|'));
|
||||
if(filename) {
|
||||
*filename = _T('\0');
|
||||
}
|
||||
_tcscpy(szRomDirectory, szEmuDirectory);
|
||||
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 {
|
||||
// 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) {
|
||||
*filename = _T('\0');
|
||||
}
|
||||
_tcscpy(szRomDirectory, szEmuDirectory);
|
||||
}
|
||||
} else {
|
||||
_tcscpy(szEmuDirectory, "assets/calculators/");
|
||||
_tcscpy(szRomDirectory, "assets/calculators/");
|
||||
|
@ -535,26 +543,32 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileNew(JNIEnv *
|
|||
}
|
||||
return result;
|
||||
}
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileOpen(JNIEnv *env, jobject thisz, jstring stateFilename) {
|
||||
if (bDocumentAvail)
|
||||
{
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileOpen(JNIEnv *env, jobject thisz, jstring stateFilename, jstring kmlFolder) {
|
||||
if (bDocumentAvail) {
|
||||
SwitchToState(SM_INVALID);
|
||||
if(bAutoSave) {
|
||||
SaveDocument();
|
||||
}
|
||||
}
|
||||
const char *stateFilenameUTF8 = (*env)->GetStringUTFChars(env, stateFilename , NULL) ;
|
||||
const char *stateFilenameUTF8 = (*env)->GetStringUTFChars(env, stateFilename, NULL);
|
||||
_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;
|
||||
lastKMLFilename[0] = '\0';
|
||||
BOOL result = OpenDocument(szBufferFilename);
|
||||
if (result) {
|
||||
if(hLcdDC && hLcdDC->selectedBitmap) {
|
||||
hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight = -abs(hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight);
|
||||
}
|
||||
|
||||
//MruAdd(szBufferFilename);
|
||||
}
|
||||
chooseCurrentKmlMode = ChooseKmlMode_UNKNOWN;
|
||||
mainViewResizeCallback(nBackgroundW, nBackgroundH);
|
||||
|
@ -562,7 +576,6 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onFileOpen(JNIEnv
|
|||
if (pbyRom) SwitchToState(SM_RUN);
|
||||
}
|
||||
draw();
|
||||
(*env)->ReleaseStringUTFChars(env, stateFilename, stateFilenameUTF8);
|
||||
if(securityExceptionOccured) {
|
||||
securityExceptionOccured = FALSE;
|
||||
result = -2;
|
||||
|
@ -694,6 +707,16 @@ 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;
|
||||
}
|
||||
|
@ -849,55 +872,29 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onViewReset(JNIEnv
|
|||
SwitchToState(SM_RUN);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEnv *env, jobject thisz, jstring kmlFilename) {
|
||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEnv *env, jobject thisz, jstring kmlFilename, jstring kmlFolder) {
|
||||
|
||||
TCHAR szKmlFile[MAX_PATH];
|
||||
// BOOL bKMLChanged,bSucc;
|
||||
BYTE cType = cCurrentRomType;
|
||||
SwitchToState(SM_INVALID);
|
||||
|
||||
// make a copy of the current KML script file name
|
||||
_ASSERT(sizeof(szKmlFile) == sizeof(szCurrentKml));
|
||||
lstrcpyn(szKmlFile,szCurrentKml,ARRAYSIZEOF(szKmlFile));
|
||||
|
||||
const char *filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename , NULL) ;
|
||||
_tcscpy(szCurrentKml, filenameUTF8);
|
||||
(*env)->ReleaseStringUTFChars(env, kmlFilename, filenameUTF8);
|
||||
|
||||
// bKMLChanged = FALSE; // KML script not changed
|
||||
BOOL bSucc = TRUE; // KML script successful loaded
|
||||
const char *kmlFolderUTF8 = (*env)->GetStringUTFChars(env, kmlFolder, NULL);
|
||||
if(kmlFolderUTF8) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
chooseCurrentKmlMode = ChooseKmlMode_CHANGE_KML;
|
||||
chooseCurrentKmlMode = ChooseKmlMode_CHANGE_KML;
|
||||
|
||||
// do
|
||||
// {
|
||||
// if (!DisplayChooseKml(cType)) // quit with Cancel
|
||||
// {
|
||||
// if (!bKMLChanged) // KML script not changed
|
||||
// break; // exit loop with current loaded KML script
|
||||
//
|
||||
// // restore KML script file name
|
||||
// lstrcpyn(szCurrentKml,szKmlFile,ARRAYSIZEOF(szCurrentKml));
|
||||
//
|
||||
// // try to restore old KML script
|
||||
// if ((bSucc = InitKML(szCurrentKml,FALSE)))
|
||||
// break; // exit loop with success
|
||||
//
|
||||
// // restoring failed, save document
|
||||
// if (IDCANCEL != SaveChanges(bAutoSave))
|
||||
// break; // exit loop with no success
|
||||
//
|
||||
// _ASSERT(bSucc == FALSE); // for continuing loop
|
||||
// }
|
||||
// else // quit with Ok
|
||||
// {
|
||||
// bKMLChanged = TRUE; // KML script changed
|
||||
bSucc = InitKML(szCurrentKml,FALSE);
|
||||
// }
|
||||
// }
|
||||
// while (!bSucc); // retry if KML script is invalid
|
||||
|
||||
BOOL result = bSucc;
|
||||
BOOL bSucc = InitKML(szCurrentKml,FALSE);
|
||||
|
||||
if(!bSucc) {
|
||||
// restore KML script file name
|
||||
|
@ -912,8 +909,7 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEn
|
|||
}
|
||||
chooseCurrentKmlMode = ChooseKmlMode_UNKNOWN;
|
||||
|
||||
if (bSucc)
|
||||
{
|
||||
if (bSucc) {
|
||||
if(hLcdDC && hLcdDC->selectedBitmap) {
|
||||
hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight = -abs(hLcdDC->selectedBitmap->bitmapInfoHeader->biHeight);
|
||||
}
|
||||
|
@ -928,14 +924,12 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_onViewScript(JNIEn
|
|||
Chipset.wRomCrc = wRomCrc; // update current ROM fingerprint
|
||||
}
|
||||
if (pbyRom) SwitchToState(SM_RUN); // continue emulation
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ResetDocument(); // close document
|
||||
SetWindowTitle(NULL);
|
||||
}
|
||||
|
||||
return result;
|
||||
return bSucc;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onBackupSave(JNIEnv *env, jobject thisz) {
|
||||
|
|
|
@ -41,6 +41,8 @@ size_t assetsPrefixLength;
|
|||
const TCHAR * contentScheme = _T("content://");
|
||||
size_t contentSchemeLength;
|
||||
const TCHAR * documentScheme = _T("document:");
|
||||
TCHAR szFilePathTmp[MAX_PATH];
|
||||
|
||||
|
||||
|
||||
DWORD GetLastError(VOID) {
|
||||
|
@ -80,8 +82,9 @@ DWORD GetCurrentDirectory(DWORD nBufferLength, LPTSTR lpBuffer) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
BOOL SetCurrentDirectory(LPCTSTR path)
|
||||
{
|
||||
BOOL SetCurrentDirectory(LPCTSTR path) {
|
||||
// Set the current directory for the next calls to CreateFile() API with a relative path.
|
||||
|
||||
szCurrentContentDirectory = NULL;
|
||||
szCurrentAssetDirectory = NULL;
|
||||
|
||||
|
@ -89,21 +92,22 @@ BOOL SetCurrentDirectory(LPCTSTR path)
|
|||
return FALSE;
|
||||
|
||||
if(_tcsncmp(path, contentScheme, contentSchemeLength) == 0) {
|
||||
// Set the current directory with an URL with the scheme "content://".
|
||||
szCurrentContentDirectory = (LPTSTR) path;
|
||||
return TRUE;
|
||||
} else if(_tcsncmp(path, assetsPrefix, assetsPrefixLength) == 0) {
|
||||
// Set the current directory with a path to target the Android asset folders (embedded in the app).
|
||||
szCurrentAssetDirectory = (LPTSTR) (path + assetsPrefixLength * sizeof(TCHAR));
|
||||
return TRUE;
|
||||
} else {
|
||||
} else
|
||||
// Set the current directory using the file system "chdir" API. Deprecated, not supported by Android >= 10.
|
||||
return (BOOL) chdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
extern BOOL settingsPort2en;
|
||||
extern BOOL settingsPort2wr;
|
||||
|
||||
HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPVOID lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, LPVOID hTemplateFile)
|
||||
{
|
||||
HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPVOID lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, LPVOID hTemplateFile) {
|
||||
FILE_LOGD("CreateFile(lpFileName: \"%s\", dwDesiredAccess: 0x%08x)", lpFileName, dwShareMode);
|
||||
BOOL forceNormalFile = FALSE;
|
||||
securityExceptionOccured = FALSE;
|
||||
|
@ -120,65 +124,68 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
TCHAR * urlContentSchemeFound = _tcsstr(lpFileName, contentScheme);
|
||||
|
||||
if(chooseCurrentKmlMode == ChooseKmlMode_FILE_OPEN || chooseCurrentKmlMode == ChooseKmlMode_CHANGE_KML) {
|
||||
// When we open a new E48 state document
|
||||
// Deal with the KML file and its containing folder
|
||||
// A E48 state file can contain a path to the KML script.
|
||||
if(foundDocumentScheme) {
|
||||
// With a recorded "document:" scheme, extract the folder URL with content:// scheme
|
||||
// document: is only for a KML file
|
||||
_tcscpy(szEmuDirectory, lpFileName + _tcslen(documentScheme) * sizeof(TCHAR));
|
||||
TCHAR * filename = _tcschr(szEmuDirectory, _T('|'));
|
||||
if(filename) {
|
||||
// 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.
|
||||
// Here we want to open a file (lpFileName) which contains the prefix "document:"
|
||||
// So, we are loading a KML script.
|
||||
// We extract the KML File URL with "content://" scheme (in the variable "filename"),
|
||||
// and we extract the folder URL with "content://" scheme (in the variable "szEmuDirectory"/"szRomDirectory" and "szCurrentContentDirectory")
|
||||
// which should contain the script and its dependencies like the includes, the images and the ROMs.
|
||||
_tcscpy(szFilePathTmp, lpFileName + _tcslen(documentScheme) * sizeof(TCHAR));
|
||||
TCHAR * filename = _tcschr(szFilePathTmp, _T('|'));
|
||||
if(filename)
|
||||
*filename = _T('\0');
|
||||
if(szFilePathTmp[0]) {
|
||||
// If szFilePathTmp is empty, this mean that the variable "szEmuDirectory", "szRomDirectory"
|
||||
// and "szCurrentContentDirectory" are set before that method, using the JSON settings embedded in the state file.
|
||||
_tcscpy(szEmuDirectory, szFilePathTmp);
|
||||
#if EMUXX == 48
|
||||
_tcscpy(szRomDirectory, szFilePathTmp);
|
||||
#endif
|
||||
SetCurrentDirectory(szFilePathTmp);
|
||||
}
|
||||
#if EMUXX == 48
|
||||
_tcscpy(szRomDirectory, szEmuDirectory);
|
||||
#endif
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
} 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')
|
||||
)) {
|
||||
// And opening a KML file
|
||||
if(lpFileName[0] == '/') {
|
||||
// With a recorded standard file
|
||||
_tcscpy(szEmuDirectory, lpFileName);
|
||||
TCHAR * filename = _tcsrchr(szEmuDirectory, _T('/'));
|
||||
if(filename) {
|
||||
*filename = _T('\0');
|
||||
}
|
||||
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);
|
||||
_tcscpy(szRomDirectory, szEmuDirectory);
|
||||
#endif
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
// } else if(foundDocumentScheme) {
|
||||
// // With a recorded "document:" scheme, extract the folder URL with content:// scheme
|
||||
// _tcscpy(szEmuDirectory, lpFileName + _tcslen(documentScheme) * sizeof(TCHAR));
|
||||
// TCHAR * filename = _tcschr(szEmuDirectory, _T('|'));
|
||||
// if(filename) {
|
||||
// *filename = _T('\0');
|
||||
// }
|
||||
//#if EMUXX == 48
|
||||
// _tcscpy(szRomDirectory, szEmuDirectory);
|
||||
//#endif
|
||||
// SetCurrentDirectory(szEmuDirectory);
|
||||
} else {
|
||||
_tcscpy(szEmuDirectory, "assets/calculators/");
|
||||
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/");
|
||||
_tcscpy(szRomDirectory, "assets/calculators/");
|
||||
#endif
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!forceNormalFile
|
||||
&& (szCurrentAssetDirectory || _tcsncmp(lpFileName, assetsPrefix, assetsPrefixLength) == 0)
|
||||
&& foundDocumentScheme == NULL
|
||||
&& urlContentSchemeFound == NULL) {
|
||||
// Asset file
|
||||
// Loading a file from the Android asset folders (embedded in the app)
|
||||
TCHAR szFileName[MAX_PATH];
|
||||
AAsset * asset = NULL;
|
||||
szFileName[0] = _T('\0');
|
||||
|
@ -197,7 +204,10 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
return handle;
|
||||
}
|
||||
} else {
|
||||
// Normal file
|
||||
// Loading a "normal" file
|
||||
// * either a file with the scheme "content://"
|
||||
// * or a file with a simple name but within the current folder (szCurrentContentDirectory)
|
||||
// * or a file with the scheme "file://". Deprecated not supported by Android >= 10.
|
||||
BOOL useOpenFileFromContentResolver = FALSE;
|
||||
int flags = O_RDWR;
|
||||
int fd = -1;
|
||||
|
@ -223,7 +233,7 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
}
|
||||
|
||||
if(urlContentSchemeFound) {
|
||||
// Case of an absolute file with the scheme content://
|
||||
// Case of an absolute file with the scheme "content://".
|
||||
fd = openFileFromContentResolver(lpFileName, dwDesiredAccess);
|
||||
useOpenFileFromContentResolver = TRUE;
|
||||
if(fd < 0) {
|
||||
|
@ -232,13 +242,14 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
securityExceptionOccured = TRUE;
|
||||
}
|
||||
} else if(szCurrentContentDirectory) {
|
||||
// Case of a relative file to a folder with the scheme content://
|
||||
// Case of a relative file to a folder with the scheme "content://".
|
||||
fd = openFileInFolderFromContentResolver(lpFileName, szCurrentContentDirectory, dwDesiredAccess);
|
||||
useOpenFileFromContentResolver = TRUE;
|
||||
if(fd == -1) {
|
||||
FILE_LOGD("CreateFile() openFileFromContentResolver() %d", errno);
|
||||
}
|
||||
} else {
|
||||
// Case of an absolute file with the scheme "file://". Deprecated not supported by Android >= 10.
|
||||
TCHAR * urlFileSchemeFound = _tcsstr(lpFileName, _T("file://"));
|
||||
if(urlFileSchemeFound)
|
||||
lpFileName = urlFileSchemeFound + 7;
|
||||
|
|
|
@ -18,6 +18,9 @@ import android.app.Activity;
|
|||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class NativeLib {
|
||||
|
||||
static {
|
||||
|
@ -49,12 +52,14 @@ public class NativeLib {
|
|||
public static native int getGlobalColor();
|
||||
public static native int getMacroState();
|
||||
|
||||
public static native int onFileNew(String kmlFilename);
|
||||
public static native int onFileOpen(String filename);
|
||||
public static native int onFileNew(String kmlFilename, String kmlFolder);
|
||||
public static native int onFileOpen(String filename, String kmlFolder);
|
||||
public static native int onFileSave();
|
||||
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);
|
||||
|
@ -62,7 +67,7 @@ public class NativeLib {
|
|||
public static native void onStackCopy();
|
||||
public static native void onStackPaste();
|
||||
public static native void onViewReset();
|
||||
public static native int onViewScript(String kmlFilename);
|
||||
public static native int onViewScript(String kmlFilename, String kmlFolder);
|
||||
public static native void onBackupSave();
|
||||
public static native void onBackupRestore();
|
||||
public static native void onBackupDelete();
|
||||
|
|
|
@ -49,10 +49,19 @@ public class Settings extends PreferenceDataStore {
|
|||
protected final boolean debug = false;
|
||||
|
||||
private final SharedPreferences androidSettings;
|
||||
|
||||
// Defined the setting keys which are only defined at the application level.
|
||||
private List<String> applicationSettingKeys = Arrays.asList("settings_kml_default", "settings_kml_folder", "lastDocument", "MRU");
|
||||
|
||||
// The settings only defined at the application level.
|
||||
private final HashMap<String, Object> applicationSettings = new HashMap<>();
|
||||
|
||||
// The commonSettings are used when no calculator is loaded, and are the default settings of the embeddedStateSettings.
|
||||
private final HashMap<String, Object> commonSettings = new HashMap<>();
|
||||
|
||||
// The embeddedStateSettings are saved in the calculator state file.
|
||||
private final HashMap<String, Object> embeddedStateSettings = new HashMap<>();
|
||||
|
||||
private boolean isCommonSettings = true;
|
||||
|
||||
public interface OnOneKeyChangedListener {
|
||||
|
|
|
@ -438,7 +438,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
|
||||
class KMLScriptItem {
|
||||
public String filename;
|
||||
public String filename;
|
||||
public String folder;
|
||||
public String title;
|
||||
public String model;
|
||||
}
|
||||
|
@ -450,6 +451,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
kmlScripts = new ArrayList<>();
|
||||
|
||||
if(kmlFolderUseDefault) {
|
||||
// We use the default KML scripts and ROMs from the embedded asset folder inside the Android app.
|
||||
AssetManager assetManager = getAssets();
|
||||
String[] calculatorsAssetFilenames = new String[0];
|
||||
try {
|
||||
|
@ -483,7 +485,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
if (inGlobal) {
|
||||
if (mLine.indexOf("End") == 0) {
|
||||
KMLScriptItem newKMLScriptItem = new KMLScriptItem();
|
||||
newKMLScriptItem.filename = calculatorFilename;
|
||||
newKMLScriptItem.filename = calculatorFilename;
|
||||
newKMLScriptItem.folder = null;
|
||||
newKMLScriptItem.title = title;
|
||||
newKMLScriptItem.model = model;
|
||||
kmlScripts.add(newKMLScriptItem);
|
||||
|
@ -516,7 +519,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Uri kmlFolderUri = Uri.parse(kmlFolderURL);
|
||||
// We use the custom KML scripts and ROMs from a chosen folder.
|
||||
Uri kmlFolderUri = Uri.parse(kmlFolderURL);
|
||||
List<String> calculatorsAssetFilenames = new LinkedList<>();
|
||||
|
||||
DocumentFile kmlFolderDocumentFile = DocumentFile.fromTreeUri(this, kmlFolderUri);
|
||||
|
@ -561,7 +565,9 @@ 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 = kmlFolderUseDefault ? calculatorFilename : "document:" + kmlFolderURL + "|" + calculatorFilename;
|
||||
newKMLScriptItem.filename = "document:|" + calculatorFilename;
|
||||
newKMLScriptItem.folder = kmlFolderURL;
|
||||
newKMLScriptItem.title = title;
|
||||
newKMLScriptItem.model = model;
|
||||
kmlScripts.add(newKMLScriptItem);
|
||||
|
@ -647,7 +653,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
ensureDocumentSaved(() -> showKMLPicker(false) );
|
||||
}
|
||||
|
||||
private void newFileFromKML(String kmlScriptFilename) {
|
||||
private void newFileFromKML(String kmlScriptFilename, String kmlScriptFolder) {
|
||||
// Eventually, close the previous state file
|
||||
NativeLib.onFileClose();
|
||||
showCalculatorView(false);
|
||||
|
@ -661,12 +667,15 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
updateFromPreferences(null, false);
|
||||
|
||||
// Create a new genuine state file
|
||||
int result = NativeLib.onFileNew(kmlScriptFilename);
|
||||
int result = NativeLib.onFileNew(kmlScriptFilename, kmlScriptFolder);
|
||||
if(result > 0) {
|
||||
showCalculatorView(true);
|
||||
displayFilename("");
|
||||
showKMLLog();
|
||||
suggestToSaveNewFile();
|
||||
// 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();
|
||||
updateNavigationDrawerItems();
|
||||
|
@ -942,9 +951,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
else
|
||||
OnFileNew();
|
||||
} else {
|
||||
String kmlScriptFilename = kmlScriptsForCurrentModel.get(which).filename;
|
||||
KMLScriptItem scriptItem = kmlScriptsForCurrentModel.get(which);
|
||||
if(changeKML) {
|
||||
int result = NativeLib.onViewScript(kmlScriptFilename);
|
||||
// We only change the KML script here.
|
||||
int result = NativeLib.onViewScript(scriptItem.filename, scriptItem.folder);
|
||||
if(result > 0) {
|
||||
displayKMLTitle();
|
||||
showKMLLog();
|
||||
|
@ -952,7 +962,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
showKMLLogForce();
|
||||
updateNavigationDrawerItems();
|
||||
} else
|
||||
newFileFromKML(kmlScriptFilename);
|
||||
// We create a new calculator with a specific KML script.
|
||||
newFileFromKML(scriptItem.filename, scriptItem.folder);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
@ -1062,11 +1073,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
case INTENT_GETSAVEFILENAME: {
|
||||
if(debug) Log.d(TAG, "onActivityResult INTENT_GETSAVEFILENAME " + url);
|
||||
if (NativeLib.onFileSaveAs(url) != 0) {
|
||||
showAlert(getString(R.string.message_state_saved));
|
||||
settings.saveInStateFile(this, url);
|
||||
saveLastDocument(url);
|
||||
Utils.makeUriPersistable(this, data, uri);
|
||||
displayFilename(url);
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), getFilenameFromURL(url)));
|
||||
if (fileSaveAsCallback != null)
|
||||
fileSaveAsCallback.run();
|
||||
}
|
||||
|
@ -1187,14 +1198,36 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
settings.clearEmbeddedStateSettings();
|
||||
settings.loadFromStateFile(this, url);
|
||||
|
||||
String kmlScriptFolder = settings.getString("settings_kml_folder_embedded", null);
|
||||
|
||||
// Update the Emu VM with the new settings
|
||||
updateFromPreferences(null, false);
|
||||
|
||||
// Load the genuine state file
|
||||
int result = NativeLib.onFileOpen(url);
|
||||
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?
|
||||
if(kmlScriptFolder == null) {
|
||||
// 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
|
||||
String currentKml = NativeLib.getCurrentKml();
|
||||
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);
|
||||
} 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!
|
||||
}
|
||||
}
|
||||
|
||||
// String kmlScriptFolder = NativeLib.getEmuDirectory();
|
||||
// settings.putString("settings_kml_folder_embedded", kmlScriptFolder);
|
||||
}
|
||||
showCalculatorView(true);
|
||||
displayFilename(url);
|
||||
showKMLLog();
|
||||
|
@ -1210,8 +1243,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
|
||||
private void onFileSave() {
|
||||
if (NativeLib.onFileSave() == 1) {
|
||||
settings.saveInStateFile(this, NativeLib.getCurrentFilename());
|
||||
showAlert(getString(R.string.message_state_saved));
|
||||
String currentFilenameUrl = NativeLib.getCurrentFilename();
|
||||
settings.saveInStateFile(this, currentFilenameUrl);
|
||||
String currentFilename = getFilenameFromURL(currentFilenameUrl);
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), currentFilename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
<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_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</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>
|
||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Wed Feb 26 12:01:15 CET 2020
|
||||
#Mon Jun 01 16:14:55 CEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
|
|
Loading…
Add table
Reference in a new issue