Version 2.3

This commit is contained in:
dgis 2021-10-19 18:25:34 +02:00
parent 009ecbccf5
commit 1b26b74f48
9 changed files with 144 additions and 80 deletions

View file

@ -17,7 +17,7 @@ QUICK START
1. From the left side, slide your finger to open the menu.
2. Touch the "New..." menu item.
3. Select a predefined faceplate (or select a custom KML script folder with Android >= 5.0).
3. Select a default calculator (or with Android >= 5.0, "[Select a Custom KML script folder...]" where you have copied the KML scripts and ROM files (Android 11 cannot use the folder Download)).
4. And the calculator should now be opened.
@ -58,7 +58,7 @@ LINKS
CHANGES
Version 2.3 (2021-09-xx)
Version 2.3 (2021-10-19)
- Add an experimental serial port support (via USB OTG).
- Show KML log on request.
@ -66,6 +66,9 @@ Version 2.3 (2021-09-xx)
- Update the embedded help file "Emu48.html" to the latest version.
- Open an external web browser when you click an external links in the Help.
- Add Real blue 50g faceplate based on my calculator and on the KML script from Eric Rechlin.
- Display the graphic tab of the printer without antialiasing.
- Fix a crash about the Most Recently Used state files.
- Fix an issue with "Copy Screen".
Version 2.2 (2020-12-09)

View file

@ -33,8 +33,8 @@ android {
applicationId "org.emulator.forty.eight"
minSdkVersion 19
targetSdkVersion 30
versionCode 20
versionName "2.2"
versionCode 22
versionName "2.3"
setProperty("archivesBaseName", "Emu48-v$versionName")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {

View file

@ -17,7 +17,7 @@ QUICK START
1. From the left side, slide your finger to open the menu.
2. Touch the "New..." menu item.
3. Select a predefined faceplate (or select a custom KML script folder with Android >= 5.0).
3. Select a default calculator (or with Android >= 5.0, "[Select a Custom KML script folder...]" where you have copied the KML scripts and ROM files (Android 11 cannot use the folder Download)).
4. And the calculator should now be opened.
@ -58,7 +58,7 @@ LINKS
CHANGES
Version 2.3 (2021-09-xx)
Version 2.3 (2021-10-19)
- Add an experimental serial port support (via USB OTG).
- Show KML log on request.
@ -66,6 +66,9 @@ Version 2.3 (2021-09-xx)
- Update the embedded help file "Emu48.html" to the latest version.
- Open an external web browser when you click an external links in the Help.
- Add Real blue 50g faceplate based on my calculator and on the KML script from Eric Rechlin.
- Display the graphic tab of the printer without antialiasing.
- Fix a crash about the Most Recently Used state files.
- Fix an issue with "Copy Screen".
Version 2.2 (2020-12-09)

View file

@ -28,6 +28,7 @@ extern AAssetManager * assetManager;
static jobject mainActivity = NULL;
jobject bitmapMainScreen = NULL;
AndroidBitmapInfo androidBitmapInfo;
//RECT mainViewRectangleToUpdate = { 0, 0, 0, 0 };
enum DialogBoxMode currentDialogBoxMode;
LPBYTE pbyRomBackup = NULL;
enum ChooseKmlMode chooseCurrentKmlMode;
@ -106,7 +107,19 @@ int mainViewCallback(int type, int param1, int param2, const TCHAR * param3, con
}
void mainViewUpdateCallback() {
mainViewCallback(CALLBACK_TYPE_INVALIDATE, 0, 0, NULL, NULL);
// if(!IsRectEmpty(&mainViewRectangleToUpdate)) {
// int param1 = ((mainViewRectangleToUpdate.left & 0xFFFF) << 16) | (mainViewRectangleToUpdate.top & 0xFFFF);
// int param2 = ((mainViewRectangleToUpdate.right & 0xFFFF) << 16) | (mainViewRectangleToUpdate.bottom & 0xFFFF);
// mainViewCallback(CALLBACK_TYPE_INVALIDATE,
// param1,
// param2,
// NULL, NULL);
// SetRectEmpty(&mainViewRectangleToUpdate);
// } else
mainViewCallback(CALLBACK_TYPE_INVALIDATE,
0,
0,
NULL, NULL);
}
void mainViewResizeCallback(int x, int y) {
@ -975,11 +988,11 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_onViewCopy(JNIEnv
size_t strideSource = (size_t)(4 * ((hBmp->bitmapInfoHeader->biWidth * hBmp->bitmapInfoHeader->biBitCount + 31) / 32));
size_t strideDestination = bitmapScreenInfo.stride;
VOID * bitmapBitsSource = (VOID *)hBmp->bitmapBits;
VOID * bitmapBitsDestination = pixelsDestination;
VOID * bitmapBitsDestination = pixelsDestination + (hBmp->bitmapInfoHeader->biHeight - 1) * strideDestination;
for(int y = 0; y < hBmp->bitmapInfoHeader->biHeight; y++) {
memcpy(bitmapBitsDestination, bitmapBitsSource, strideSource);
bitmapBitsSource += strideSource;
bitmapBitsDestination += strideDestination;
bitmapBitsDestination -= strideDestination;
}

View file

@ -60,6 +60,8 @@ static void initTimer();
#define MAX_FILE_MAPPING_HANDLE 10
static HANDLE fileMappingHandles[MAX_FILE_MAPPING_HANDLE];
HBITMAP rootBITMAP;
void win32Init() {
initTimer();
for (int i = 0; i < MAX_FILE_MAPPING_HANDLE; ++i) {
@ -70,6 +72,8 @@ void win32Init() {
contentSchemeLength = _tcslen(contentScheme);
documentSchemeLength = _tcslen(documentScheme);
comPrefixLength = _tcslen(comPrefix);
rootBITMAP = CreateCompatibleBitmap(NULL, 0, 0);
}
int abs (int i) {
@ -1832,6 +1836,8 @@ BOOL DeleteObject(HGDIOBJ ho) {
}
case HGDIOBJ_TYPE_BITMAP: {
PAINT_LOGD("PAINT DeleteObject() HGDIOBJ_TYPE_BITMAP");
if(ho == rootBITMAP)
return FALSE;
ho->handleType = HGDIOBJ_TYPE_INVALID;
if(ho->bitmapInfo)
free((void *) ho->bitmapInfo);
@ -1903,6 +1909,7 @@ HDC CreateCompatibleDC(HDC hdc) {
memset(handle, 0, sizeof(struct _HDC));
handle->handleType = HDC_TYPE_DC;
handle->hdcCompatible = hdc;
handle->selectedBitmap = rootBITMAP;
return handle;
}
HDC GetDC(HWND hWnd) {

View file

@ -63,6 +63,7 @@ public class MainScreenView extends PanAndScaleView {
public float defaultViewPanOffsetX = 0.0f;
public float defaultViewPanOffsetY = 0.0f;
// private Rect invalidateRectangle = new Rect();
public MainScreenView(Context context) {
super(context);
@ -406,6 +407,16 @@ public class MainScreenView extends PanAndScaleView {
// Copy the full calculator with antialiasing
canvas.drawBitmap(bitmapMainScreen, 0, 0, paintFullCalc);
// synchronized (invalidateRectangle) {
// if (invalidateRectangle.isEmpty()) {
// canvas.drawColor(getBackgroundColor());
// canvas.drawBitmap(bitmapMainScreen, 0, 0, paintFullCalc);
// } else {
// canvas.drawBitmap(bitmapMainScreen, invalidateRectangle, invalidateRectangle, paintFullCalc);
// invalidateRectangle.setEmpty();
// }
// }
if(usePixelBorders) {
// Copy the LCD part only without antialiasing
int x = NativeLib.getScreenPositionX();
@ -457,36 +468,51 @@ public class MainScreenView extends PanAndScaleView {
}
public void updateCallback(int type, int param1, int param2, String param3, String param4) {
switch (type) {
case NativeLib.CALLBACK_TYPE_INVALIDATE:
if (debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_INVALIDATE postInvalidate()");
postInvalidate();
if(this.onUpdateDisplayListener != null)
this.onUpdateDisplayListener.run();
break;
case NativeLib.CALLBACK_TYPE_WINDOW_RESIZE:
if (debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_WINDOW_RESIZE()");
// New Bitmap size
if(bitmapMainScreen == null || bitmapMainScreen.getWidth() != param1 || bitmapMainScreen.getHeight() != param2) {
if(debug) Log.d(TAG, "updateCallback() Bitmap.createBitmap(x: " + Math.max(1, param1) + ", y: " + Math.max(1, param2) + ")");
Bitmap oldBitmapMainScreen = bitmapMainScreen;
bitmapMainScreen = Bitmap.createBitmap(Math.max(1, param1), Math.max(1, param2), Bitmap.Config.ARGB_8888);
int globalColor = NativeLib.getGlobalColor();
kmlBackgroundColor = Color.argb(255, (globalColor & 0x00FF0000) >> 16, (globalColor & 0x0000FF00) >> 8, globalColor & 0x000000FF);
try {
switch (type) {
case NativeLib.CALLBACK_TYPE_INVALIDATE:
// int left = param1 >> 16;
// int top = param1 & 0xFFFF;
// int right = param2 >> 16;
// int bottom = param2 & 0xFFFF;
// if (debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_INVALIDATE postInvalidate() left: " + left + ", top: " + top + ", right: " + right + ", bottom: " + bottom);
// synchronized (invalidateRectangle) {
// invalidateRectangle.union(left, top, right, bottom);
// }
if (debug)
Log.d(TAG, "updateCallback() CALLBACK_TYPE_INVALIDATE postInvalidate()");
postInvalidate();
if (this.onUpdateDisplayListener != null)
this.onUpdateDisplayListener.run();
break;
case NativeLib.CALLBACK_TYPE_WINDOW_RESIZE:
if (debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_WINDOW_RESIZE()");
// New Bitmap size
if (bitmapMainScreen == null || bitmapMainScreen.getWidth() != param1 || bitmapMainScreen.getHeight() != param2) {
if (debug)
Log.d(TAG, "updateCallback() Bitmap.createBitmap(x: " + Math.max(1, param1) + ", y: " + Math.max(1, param2) + ")");
Bitmap oldBitmapMainScreen = bitmapMainScreen;
bitmapMainScreen = Bitmap.createBitmap(Math.max(1, param1), Math.max(1, param2), Bitmap.Config.ARGB_8888);
int globalColor = NativeLib.getGlobalColor();
kmlBackgroundColor = Color.argb(255, (globalColor & 0x00FF0000) >> 16, (globalColor & 0x0000FF00) >> 8, globalColor & 0x000000FF);
bitmapMainScreen.eraseColor(getBackgroundColor());
NativeLib.changeBitmap(bitmapMainScreen);
bitmapMainScreen.eraseColor(getBackgroundColor());
NativeLib.changeBitmap(bitmapMainScreen);
if(oldBitmapMainScreen != null) {
oldBitmapMainScreen.recycle();
}
firstTime = true;
setVirtualSize(bitmapMainScreen.getWidth(), bitmapMainScreen.getHeight());
if(viewSized)
updateLayout();
}
break;
}
if (oldBitmapMainScreen != null) {
oldBitmapMainScreen.recycle();
}
firstTime = true;
setVirtualSize(bitmapMainScreen.getWidth(), bitmapMainScreen.getHeight());
if (viewSized)
updateLayout();
}
break;
}
} catch (Exception ex) {
if (debug)
Log.d(TAG, "updateCallback() Exception: " + ex.toString());
}
}
public void setRotationMode(int rotationMode, boolean isDynamic) {

View file

@ -22,9 +22,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
@ -113,6 +111,8 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment {
Bitmap croppedPaperBitmap = Bitmap.createBitmap(paperBitmap.getWidth(), printerSimulator.getPaperHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(croppedPaperBitmap);
Paint paint = new Paint();
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
canvas.drawBitmap(paperBitmap, 0, 0, paint);
Activity activity = getActivity();
@ -122,13 +122,16 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment {
FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
croppedPaperBitmap.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream);
fileOutputStream.close();
String mimeType = "application/png";
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, Utils.resId(PrinterSimulatorFragment.this, "string", "message_printer_share_graphic"));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider", imageFile));
String subject = getString(Utils.resId(PrinterSimulatorFragment.this, "string", "message_printer_share_graphic"));
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TITLE, subject);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider", imageFile));
intent.setType("image/png");
// intent.setDataAndType(FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider", imageFile), "image/png");
startActivity(Intent.createChooser(intent, getString(Utils.resId(PrinterSimulatorFragment.this, "string", "message_printer_share_graphic"))));
}
} catch (Exception e) {
@ -243,6 +246,7 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment {
scaleThumbnailColor = Color.GRAY;
paintBitmap.setAntiAlias(false);
paintBitmap.setFilterBitmap(false);
}
public void setBitmap(Bitmap bitmap) {

View file

@ -145,6 +145,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
return size() > MAX_MRU;
}
};
private HashMap<Integer, String> mruByMenuId = new HashMap<>();
private final PrinterSimulator printerSimulator = new PrinterSimulator();
private final PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
@ -261,6 +262,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if (recentsSubMenu != null)
recentsSubMenu.clear();
}
mruByMenuId.clear();
if (recentsSubMenu != null) {
Set<String> mruLinkedHashMapKeySet = mruLinkedHashMap.keySet();
String[] mrus = mruLinkedHashMapKeySet.toArray(new String[0]);
@ -271,8 +273,11 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
// We should remove this file because it seems impossible to get the display name of this Most Recently Used state file.
// It might be deleted or the permissions does not allow to reach it anymore.
mruLinkedHashMap.remove(mostRecentlyUsedFile);
} else
recentsSubMenu.add(Menu.NONE, MRU_ID_START + i, Menu.NONE, displayName);
} else {
int menuId = MRU_ID_START + i;
mruByMenuId.put(menuId, mostRecentlyUsedFile);
recentsSubMenu.add(Menu.NONE, menuId, Menu.NONE, displayName);
}
}
}
}
@ -397,20 +402,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
} else if (id == R.id.nav_about) {
OnAbout();
} else if(id >= MRU_ID_START && id < MRU_ID_START + MAX_MRU) {
String url = mruByMenuId.get(id);
if(url != null) {
// Increase the file usage count
mruLinkedHashMap.get(url);
Set<String> mruLinkedHashMapKeySet = mruLinkedHashMap.keySet();
int mruLength = mruLinkedHashMapKeySet.size();
String[] mrus = mruLinkedHashMapKeySet.toArray(new String[mruLength]);
int mruClickedIndex = id - MRU_ID_START;
String url = mrus[mruClickedIndex];
mruLinkedHashMap.get(url);
ensureDocumentSaved(() -> {
// FileOpen from MRU.
onFileOpen(url, null, null);
});
ensureDocumentSaved(() -> {
// FileOpen from MRU.
onFileOpen(url, null, null);
});
}
}
drawer.closeDrawer(GravityCompat.START);
@ -862,14 +863,17 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
bitmapScreen.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream);
fileOutputStream.close();
String mimeType = "application/png";
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, R.string.message_screenshot);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile));
startActivity(Intent.createChooser(intent, getString(R.string.message_share_screenshot)));
String subject = getString(R.string.message_screenshot);
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TITLE, subject);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile));
intent.setType("image/png");
// intent.setDataAndType(FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile), "image/png");
startActivity(Intent.createChooser(intent, getString(R.string.message_share_screenshot)));
} catch (Exception e) {
e.printStackTrace();
showAlert(e.getMessage());
@ -890,14 +894,17 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
bitmapScreen.compress(Bitmap.CompressFormat.PNG, 90, fileOutputStream);
fileOutputStream.close();
String mimeType = "application/png";
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, R.string.message_screenshot);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile));
startActivity(Intent.createChooser(intent, getString(R.string.message_share_screenshot)));
String subject = getString(R.string.message_screenshot);
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TITLE, subject);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile));
intent.setType("image/png");
// intent.setDataAndType(FileProvider.getUriForFile(this,this.getPackageName() + ".provider", imageFile), "image/png");
startActivity(Intent.createChooser(intent, getString(R.string.message_share_screenshot)));
} catch (Exception e) {
e.printStackTrace();
showAlert(e.getMessage());
@ -961,7 +968,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
} else
kmlScriptsForCurrentModel = kmlScripts;
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && getPackageName().contains("org.emulator.forty.eight");
boolean showDefaultKMLScriptFolderItem = !kmlFolderUseDefault && (getPackageName().contains("org.emulator.forty.eight") || getPackageName().contains("org.emulator.forty.two"));
int lastIndex = kmlScriptsForCurrentModel.size();
String[] kmlScriptTitles = new String[lastIndex + (showDefaultKMLScriptFolderItem ? 2 : 1)];
for (int i = 0; i < kmlScriptsForCurrentModel.size(); i++)
@ -970,7 +977,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if(showDefaultKMLScriptFolderItem)
kmlScriptTitles[lastIndex + 1] = getResources().getString(R.string.load_default_kml);
new AlertDialog.Builder(MainActivity.this)
.setTitle(getResources().getString(R.string.pick_calculator))
.setTitle(getResources().getString(kmlFolderUseDefault ? R.string.pick_default_calculator : R.string.pick_custom_calculator))
.setItems(kmlScriptTitles, (dialog, which) -> {
if(which == lastIndex) {
// [Select a Custom KML script folder...]

View file

@ -61,7 +61,8 @@
<string name="load_custom_kml">[Select a Custom KML script folder...]</string>
<string name="load_default_kml">[Default KML script folder]</string>
<string name="pick_calculator">Pick a calculator</string>
<string name="pick_default_calculator">Pick a default calculator</string>
<string name="pick_custom_calculator">Pick a custom calculator</string>
<string name="dialog_printer_simulator_title">Printer Simulator</string>
<string name="tab_printer_textual">Text</string>