mirror of
https://github.com/dgis/emu48android
synced 2024-11-16 07:48:08 +01:00
Allow to load and save.
This commit is contained in:
parent
7e008185b5
commit
d623bcc609
9 changed files with 94 additions and 44 deletions
|
@ -1,7 +1,7 @@
|
|||
ABOUT
|
||||
This project ports the Windows application Emu48 written in C to Android.
|
||||
It uses the Android NDK. The former Emu48 source code remains untouch because a thin win32 emulation layer above Linux/NDK!
|
||||
This win32 layer will allow to update easily from the original source code.
|
||||
This win32 layer will allow to easily update from the original Emu48 source code.
|
||||
|
||||
NOT WORKING
|
||||
- Sound
|
||||
|
@ -12,6 +12,9 @@ NOT WORKING
|
|||
- Serial Ports (Wire or Ir)
|
||||
|
||||
TODO
|
||||
- Choose KML/Change KML/NewDocument
|
||||
- Option to allow rotation
|
||||
- Option to auto hide the menu
|
||||
- Bitmap corruption when touching the buttons
|
||||
- Android UI Settings
|
||||
- Sound
|
||||
|
|
|
@ -33,6 +33,7 @@ extern void mainViewUpdateCallback();
|
|||
extern void mainViewResizeCallback(int x, int y);
|
||||
extern int mainViewGetOpenFileNameCallback(OPENFILENAME * ofn);
|
||||
extern int mainViewGetSaveFileNameCallback(OPENFILENAME * ofn);
|
||||
extern int openFileFromContentResolver(const TCHAR * url, int writeAccess);
|
||||
|
||||
|
||||
#if !defined VERIFY
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
extern void emu48Start();
|
||||
extern AAssetManager * assetManager;
|
||||
static jobject viewToUpdate = NULL;
|
||||
static jobject mainActivity = NULL;
|
||||
jobject bitmapMainScreen;
|
||||
AndroidBitmapInfo androidBitmapInfo;
|
||||
|
||||
|
@ -40,6 +41,7 @@ extern void OnBackupRestore();
|
|||
extern void OnBackupDelete();
|
||||
|
||||
|
||||
JNIEnv *getJNIEnvironment();
|
||||
|
||||
JavaVM *java_machine;
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
|
@ -48,6 +50,21 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
JNIEnv *getJNIEnvironment() {
|
||||
JNIEnv * jniEnv;
|
||||
jint ret;
|
||||
BOOL needDetach = FALSE;
|
||||
ret = (*java_machine)->GetEnv(java_machine, &jniEnv, JNI_VERSION_1_6);
|
||||
if (ret == JNI_EDETACHED) {
|
||||
// GetEnv: not attached
|
||||
ret = (*java_machine)->AttachCurrentThread(java_machine, &jniEnv, NULL);
|
||||
if (ret == JNI_OK) {
|
||||
needDetach = TRUE;
|
||||
}
|
||||
}
|
||||
return jniEnv;
|
||||
}
|
||||
|
||||
enum CALLBACK_TYPE {
|
||||
CALLBACK_TYPE_INVALIDATE = 0,
|
||||
CALLBACK_TYPE_WINDOW_RESIZE = 1,
|
||||
|
@ -132,36 +149,33 @@ int mainViewGetSaveFileNameCallback(OPENFILENAME * ofn) {
|
|||
// https://stackoverflow.com/questions/9630134/jni-how-to-callback-from-c-or-c-to-java
|
||||
int mainViewCallback(int type, int param1, int param2, const TCHAR * param3, const TCHAR * param4) {
|
||||
if (viewToUpdate) {
|
||||
JNIEnv * jniEnv;
|
||||
jint ret;
|
||||
BOOL needDetach = FALSE;
|
||||
ret = (*java_machine)->GetEnv(java_machine, &jniEnv, JNI_VERSION_1_6);
|
||||
if (ret == JNI_EDETACHED) {
|
||||
// GetEnv: not attached
|
||||
ret = (*java_machine)->AttachCurrentThread(java_machine, &jniEnv, NULL);
|
||||
if (ret == JNI_OK) {
|
||||
needDetach = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv *jniEnv = getJNIEnvironment();
|
||||
jclass viewToUpdateClass = (*jniEnv)->GetObjectClass(jniEnv, viewToUpdate);
|
||||
//jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, viewToUpdateClass, "updateCallback", "()V");
|
||||
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, viewToUpdateClass, "updateCallback", "(IIILjava/lang/String;Ljava/lang/String;)I");
|
||||
jstring utfParam3 = (*jniEnv)->NewStringUTF(jniEnv, param3);
|
||||
jstring utfParam4 = (*jniEnv)->NewStringUTF(jniEnv, param4);
|
||||
int result = (*jniEnv)->CallIntMethod(jniEnv, viewToUpdate, midStr, type, param1, param2, utfParam3, utfParam4);
|
||||
|
||||
// if(needDetach)
|
||||
// ret = (*java_machine)->DetachCurrentThread(java_machine);
|
||||
// if(needDetach) ret = (*java_machine)->DetachCurrentThread(java_machine);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Must be called in the main thread
|
||||
int openFileFromContentResolver(const TCHAR * url, int writeAccess) {
|
||||
JNIEnv *jniEnv = getJNIEnvironment();
|
||||
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
|
||||
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "openFileFromContentResolver", "(Ljava/lang/String;I)I");
|
||||
jstring utfUrl = (*jniEnv)->NewStringUTF(jniEnv, url);
|
||||
int result = (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, utfUrl, writeAccess);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject view) {
|
||||
JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject activity, jobject view) {
|
||||
|
||||
viewToUpdate = (*env)->NewGlobalRef(env, view);
|
||||
bitmapMainScreen = (*env)->NewGlobalRef(env, bitmapMainScreen0);
|
||||
mainActivity = (*env)->NewGlobalRef(env, activity);
|
||||
viewToUpdate = (*env)->NewGlobalRef(env, view);
|
||||
|
||||
|
||||
int ret = AndroidBitmap_getInfo(env, bitmapMainScreen, &androidBitmapInfo);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -101,23 +101,27 @@ HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
flags |= O_CREAT;
|
||||
}
|
||||
|
||||
fd = open(lpFileName, flags, perm);
|
||||
if (-1 != fd && 0 != dwShareMode) {
|
||||
// Not specifiying shared write means non-shared (exclusive) write
|
||||
if (0 == (dwShareMode & FILE_SHARE_WRITE))
|
||||
lock.l_type = F_WRLCK;
|
||||
else if (0 != (dwShareMode & FILE_SHARE_READ))
|
||||
lock.l_type = F_RDLCK;
|
||||
|
||||
// Lock entire file
|
||||
lock.l_len = lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
|
||||
if (-1 == fcntl(fd, F_SETLK, &lock) && (EACCES == errno || EAGAIN == errno)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
TCHAR * urlSchemeFound = _tcsstr(lpFileName, _T("://"));
|
||||
if(urlSchemeFound)
|
||||
fd = openFileFromContentResolver(lpFileName, dwDesiredAccess);
|
||||
else
|
||||
fd = open(lpFileName, flags, perm);
|
||||
// if (-1 != fd && 0 != dwShareMode) {
|
||||
// // Not specifiying shared write means non-shared (exclusive) write
|
||||
// if (0 == (dwShareMode & FILE_SHARE_WRITE))
|
||||
// lock.l_type = F_WRLCK;
|
||||
// else if (0 != (dwShareMode & FILE_SHARE_READ))
|
||||
// lock.l_type = F_RDLCK;
|
||||
//
|
||||
// // Lock entire file
|
||||
// lock.l_len = lock.l_start = 0;
|
||||
// lock.l_whence = SEEK_SET;
|
||||
//
|
||||
// if (-1 == fcntl(fd, F_SETLK, &lock) && (EACCES == errno || EAGAIN == errno)) {
|
||||
// close(fd);
|
||||
// return -1;
|
||||
// }
|
||||
// }
|
||||
if (fd != -1) {
|
||||
HANDLE handle = malloc(sizeof(_HANDLE));
|
||||
memset(handle, 0, sizeof(_HANDLE));
|
||||
|
|
|
@ -934,10 +934,11 @@ extern int lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2);
|
|||
|
||||
extern int lstrcmpi(LPCWSTR lpString1, LPCWSTR lpString2);
|
||||
#define _tcstoul wcstoul
|
||||
#define _tcsncmp wcsncmp
|
||||
#define _tcslen wcslen
|
||||
#define _tcscpy wcscpy
|
||||
#define _tcscat wcscat
|
||||
#define _tcsncmp wcsncmp
|
||||
#define _tcslen wcslen
|
||||
#define _tcscpy wcscpy
|
||||
#define _tcscat wcscat
|
||||
#define _tcsstr wcsstr
|
||||
|
||||
#else
|
||||
|
||||
|
@ -959,6 +960,7 @@ extern int lstrcmpi(LPCSTR lpString1, LPCSTR lpString2);
|
|||
#define _tcslen strlen
|
||||
#define _tcscpy strcpy
|
||||
#define _tcscat strcat
|
||||
#define _tcsstr strstr
|
||||
|
||||
|
||||
#endif // !UNICODE
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Activity;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -23,6 +24,7 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
@ -169,7 +171,7 @@ public class MainActivity extends AppCompatActivity
|
|||
public static int INTENT_GETSAVEFILENAME = 2;
|
||||
|
||||
private void OnFileOpen() {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
//intent.setType("YOUR FILETYPE"); //not needed, but maybe usefull
|
||||
intent.setType("*/*");
|
||||
|
@ -269,7 +271,8 @@ public class MainActivity extends AppCompatActivity
|
|||
|
||||
//just as an example, I am writing a String to the Uri I received from the user:
|
||||
Log.d(TAG, "onActivityResult INTENT_GETSAVEFILENAME " + uri.toString());
|
||||
NativeLib.onFileSaveAs(uri.toString());
|
||||
String url = uri.toString();
|
||||
NativeLib.onFileSaveAs(url);
|
||||
// try {
|
||||
// OutputStream output = getContentResolver().openOutputStream(uri);
|
||||
//
|
||||
|
@ -283,4 +286,25 @@ public class MainActivity extends AppCompatActivity
|
|||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
final int GENERIC_READ = 1;
|
||||
final int GENERIC_WRITE = 2;
|
||||
int openFileFromContentResolver(String url, int writeAccess) {
|
||||
//https://stackoverflow.com/a/31677287
|
||||
Uri uri = Uri.parse(url);
|
||||
ParcelFileDescriptor filePfd;
|
||||
try {
|
||||
String mode = "";
|
||||
if((writeAccess & GENERIC_READ) == GENERIC_READ)
|
||||
mode += "r";
|
||||
if((writeAccess & GENERIC_WRITE) == GENERIC_WRITE)
|
||||
mode += "w";
|
||||
filePfd = getContentResolver().openFileDescriptor(uri, mode);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
int fd = filePfd != null ? filePfd.getFd() : 0;
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class MainScreenView extends SurfaceView {
|
|||
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
bitmapMainScreen = Bitmap.createBitmap(displayMetrics.widthPixels, displayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
|
||||
bitmapMainScreen.eraseColor(Color.LTGRAY);
|
||||
NativeLib.start(mgr, bitmapMainScreen, this);
|
||||
NativeLib.start(mgr, bitmapMainScreen, (MainActivity)context, this);
|
||||
|
||||
vkmap = new HashMap<Integer, Integer>();
|
||||
vkmap.put(KeyEvent.KEYCODE_BACK, 0x08); // VK_BACK
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.regis.cosnier.emu48;
|
|||
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.view.View;
|
||||
|
||||
public class NativeLib {
|
||||
|
@ -10,7 +12,7 @@ public class NativeLib {
|
|||
System.loadLibrary("native-lib");
|
||||
}
|
||||
|
||||
public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, MainScreenView view);
|
||||
public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, MainActivity activity, MainScreenView view);
|
||||
public static native void stop();
|
||||
//public static native void resize(int width, int height);
|
||||
public static native void draw();
|
||||
|
|
Loading…
Reference in a new issue