From 82d836f881d632f7100b55f8246a471c21609600 Mon Sep 17 00:00:00 2001 From: Jeremy <53489032+clang-clang-clang@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:53:34 +0800 Subject: [PATCH 1/2] Android: maintenance (#648) --- librtt/Rtt_Runtime.cpp | 2 +- platform/android/app/CMakeLists.txt | 2 +- platform/android/app/build.gradle.kts | 6 +- platform/android/ndk/Rtt_AndroidPlatform.cpp | 2 +- .../src/com/ansca/corona/AudioRecorder.java | 2 +- .../src/com/ansca/corona/CoronaActivity.java | 161 +++++++++--------- .../com/ansca/corona/CoronaEnvironment.java | 2 +- .../ansca/corona/CoronaSystemApiHandler.java | 18 +- .../sdk/src/com/ansca/corona/CoronaView.java | 6 +- .../com/ansca/corona/NativeToJavaBridge.java | 2 +- .../listeners/CoronaSystemApiListener.java | 2 +- .../ansca/corona/storage/FileServices.java | 22 ++- 12 files changed, 124 insertions(+), 103 deletions(-) diff --git a/librtt/Rtt_Runtime.cpp b/librtt/Rtt_Runtime.cpp index 024c52ae8..9e6698c00 100755 --- a/librtt/Rtt_Runtime.cpp +++ b/librtt/Rtt_Runtime.cpp @@ -1963,7 +1963,7 @@ Runtime::operator()() const bool isSuspended = IsSuspended(); if( wasSuspended != isSuspended && isSuspended ) { - // This condition is writtein inverse for better undrerstanding + // This condition is written inverse for better understanding // Sometimes (Splash Screen is shown) scheduled tasks can suspend Runtime // In that case (suspension state is changed and it is suspended), skip Display update } diff --git a/platform/android/app/CMakeLists.txt b/platform/android/app/CMakeLists.txt index 666b9a69b..8365ef6c5 100644 --- a/platform/android/app/CMakeLists.txt +++ b/platform/android/app/CMakeLists.txt @@ -1,2 +1,2 @@ -# This file is requiered due to Android Studio bug: if main app doesn't use NDK, project woun't use it either. +# This file is required due to Android Studio bug: if main app doesn't use NDK, project won't use it either. cmake_minimum_required(VERSION 3.4.1) diff --git a/platform/android/app/build.gradle.kts b/platform/android/app/build.gradle.kts index 44121a716..8c94bf00c 100644 --- a/platform/android/app/build.gradle.kts +++ b/platform/android/app/build.gradle.kts @@ -396,6 +396,8 @@ android.applicationVariants.all { val isRelease = (baseName == "release") val generatedAssetsDir = "$buildDir/generated/corona_assets/$baseName" val compiledLuaArchive = "$buildDir/intermediates/compiled_lua_archive/$baseName/resource.car" + // fix assets not been merge when lua file changed + val luaArchiveInMergedAssets = "$buildDir/intermediates/assets/$baseName/resource.car" val compileLuaTask = tasks.create("compileLua${baseName.capitalize()}") { description = "If required, compiles Lua and archives it into resource.car" @@ -512,9 +514,9 @@ android.applicationVariants.all { doFirst { delete(generatedAssetsDir) + delete(luaArchiveInMergedAssets) mkdir(generatedAssetsDir) - } - doFirst { + if (!file(coronaSrcDir).isDirectory) { throw InvalidUserDataException("Unable to find Solar2D project (for example platform/test/assets2/main.lua)!") } diff --git a/platform/android/ndk/Rtt_AndroidPlatform.cpp b/platform/android/ndk/Rtt_AndroidPlatform.cpp index 674d20ca0..18512bdc2 100644 --- a/platform/android/ndk/Rtt_AndroidPlatform.cpp +++ b/platform/android/ndk/Rtt_AndroidPlatform.cpp @@ -305,7 +305,7 @@ AndroidPlatform::FileExists( const char *filename ) const else { // The given file name is likely a relative path to an asset file or a URL to a local file. - // Check for its existance via Android's APIs on the Java side. + // Check for its existence via Android's APIs on the Java side. fileExists = fNativeToJavaBridge->GetRawAssetExists(filename); if (!fileExists) { diff --git a/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java b/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java index 26935e79e..f0c77619d 100644 --- a/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java +++ b/platform/android/sdk/src/com/ansca/corona/AudioRecorder.java @@ -205,7 +205,7 @@ public void setId(long id) { } /** - * Checks if this applicaction has permission to use the microphone. + * Checks if this application has permission to use the microphone. * @return Returns true if this application has permission. Returns false if not. */ private static boolean hasPermission() { diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java b/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java index 493390633..73fc0f817 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaActivity.java @@ -1141,7 +1141,7 @@ public android.view.WindowInsets onApplyWindowInsets(android.view.View v, androi || mode == CoronaStatusBarSettings.LIGHT_TRANSPARENT || mode == CoronaStatusBarSettings.DARK_TRANSPARENT) { - // Unhides it if its hidden + // Unhidden it if its hidden if (myStatusBarMode == CoronaStatusBarSettings.HIDDEN) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); @@ -2095,105 +2095,98 @@ void showCoronaSplashScreen() { // whether the splash screen is in the app bundle appears to be to query the APK contents android.content.Context context = CoronaEnvironment.getApplicationContext(); android.content.res.Resources resources = context.getResources(); - com.ansca.corona.storage.FileServices fileServices; - fileServices = new com.ansca.corona.storage.FileServices(context); - boolean splashExists = fileServices.doesResourceFileExist("drawable/_corona_splash_screen.png") - || fileServices.doesResourceFileExist("drawable/_corona_splash_screen.jpg"); - // Log.v("Corona", "showCoronaSplashScreen: splashExists: " + splashExists); - if ( splashExists ) - { - final ViewManager viewManager = fCoronaRuntime.getViewManager(); - int splash_drawable_id = 0; + final ViewManager viewManager = fCoronaRuntime.getViewManager(); + // 0 is not a valid resource ID; no need for rechecking. + int splash_drawable_id = 0; - try { - // Fetch the specified resource's unique integer ID by its name. - splash_drawable_id = resources.getIdentifier("_corona_splash_screen" , "drawable", context.getPackageName()); - } - catch (Exception ex) { - Log.v("Corona", "showCoronaSplashScreen load EXCEPTION: " + ex); - } - - // Log.v("Corona", "showCoronaSplashScreen: splash_drawable_id: " + splash_drawable_id); - if ( splash_drawable_id != 0 ) - { - try { - // LinearLayout - fSplashView = new LinearLayout(this); - fSplashView.setOrientation(LinearLayout.VERTICAL); - fSplashView.setBackgroundColor(0xFF000000); + try { + // Fetch the specified resource's unique integer ID by its name. + splash_drawable_id = resources.getIdentifier("_corona_splash_screen" , "drawable", context.getPackageName()); + } + catch (Exception ex) { + Log.v("Corona", "showCoronaSplashScreen load EXCEPTION: " + ex); + } - // ImageView - ImageView imageView = new ImageView(this); - imageView.setScaleType(ImageView.ScaleType.CENTER); + // Log.v("Corona", "showCoronaSplashScreen: splash_drawable_id: " + splash_drawable_id); + if ( splash_drawable_id != 0 ) + { + try { + // LinearLayout + fSplashView = new LinearLayout(this); + fSplashView.setOrientation(LinearLayout.VERTICAL); + fSplashView.setBackgroundColor(0xFF000000); + + // ImageView + ImageView imageView = new ImageView(this); + imageView.setScaleType(ImageView.ScaleType.CENTER); + + // Resize the bitmap + android.view.Display display = + ((android.view.WindowManager)getSystemService(android.content.Context.WINDOW_SERVICE)).getDefaultDisplay(); + Bitmap d = BitmapFactory.decodeResource(resources, splash_drawable_id); + + if (display.getWidth() >= d.getWidth() && display.getHeight() >= d.getHeight()) + { + // Screen is bigger that the splash screen, we don't scale up so just display it + // Log.v("Corona", "showCoronaSplashScreen: not scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()); + + imageView.setImageBitmap(d); + } + else + { + // Scaling the image ourselves avoids issues with "Bitmap too large to be uploaded into a texture" errors - // Resize the bitmap - android.view.Display display = - ((android.view.WindowManager)getSystemService(android.content.Context.WINDOW_SERVICE)).getDefaultDisplay(); - Bitmap d = BitmapFactory.decodeResource(resources, splash_drawable_id); + double widthRatio = ((double)display.getWidth() / d.getWidth()); + double heightRatio = ((double)display.getHeight() / d.getHeight()); + int nw = 0; + int nh = 0; - if (display.getWidth() >= d.getWidth() && display.getHeight() >= d.getHeight()) + // Scale by height or width, whichever is greater + if (heightRatio > widthRatio) { - // Screen is bigger that the splash screen, we don't scale up so just display it - // Log.v("Corona", "showCoronaSplashScreen: not scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()); - - imageView.setImageBitmap(d); + nw = (int) ((double)d.getWidth() * widthRatio); + nh = (int) ((double)d.getHeight() * widthRatio); } else { - // Scaling the image ourselves avoids issues with "Bitmap too large to be uploaded into a texture" errors - - double widthRatio = ((double)display.getWidth() / d.getWidth()); - double heightRatio = ((double)display.getHeight() / d.getHeight()); - int nw = 0; - int nh = 0; - - // Scale by height or width, whichever is greater - if (heightRatio > widthRatio) - { - nw = (int) ((double)d.getWidth() * widthRatio); - nh = (int) ((double)d.getHeight() * widthRatio); - } - else - { - nw = (int) ((double)d.getWidth() * heightRatio); - nh = (int) ((double)d.getHeight() * heightRatio); - } + nw = (int) ((double)d.getWidth() * heightRatio); + nh = (int) ((double)d.getHeight() * heightRatio); + } - Bitmap scaled = Bitmap.createScaledBitmap(d, nw, nh, true); + Bitmap scaled = Bitmap.createScaledBitmap(d, nw, nh, true); - // Log.v("Corona", "showCoronaSplashScreen: scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()+ "; scaled: "+ scaled.getWidth() +"x"+ scaled.getHeight()); - // Log.v("Corona", "showCoronaSplashScreen: new: "+ nw +"x"+ nh +"; ratio: "+ widthRatio + "x" + heightRatio); + // Log.v("Corona", "showCoronaSplashScreen: scaling: screen: "+ display.getWidth() +"x"+ display.getHeight() + "; original: "+ d.getWidth() +"x"+ d.getHeight()+ "; scaled: "+ scaled.getWidth() +"x"+ scaled.getHeight()); + // Log.v("Corona", "showCoronaSplashScreen: new: "+ nw +"x"+ nh +"; ratio: "+ widthRatio + "x" + heightRatio); - imageView.setImageBitmap(scaled); + imageView.setImageBitmap(scaled); - // On Android 2.3.3 we can help low memory devices by forcing the source bitmap to be recycled - // but only if Bitmap.createScaledBitmap() didn't return the same image - // if (android.os.Build.VERSION.SDK_INT <= 10) - // { - // if (scaled.getWidth() != d.getWidth() || scaled.getHeight() != d.getHeight()) - // { - // // We got a different bitmap back after scaling, it's safe to recycle the old one - // d.recycle(); - // } - // } - } + // On Android 2.3.3 we can help low memory devices by forcing the source bitmap to be recycled + // but only if Bitmap.createScaledBitmap() didn't return the same image + // if (android.os.Build.VERSION.SDK_INT <= 10) + // { + // if (scaled.getWidth() != d.getWidth() || scaled.getHeight() != d.getHeight()) + // { + // // We got a different bitmap back after scaling, it's safe to recycle the old one + // d.recycle(); + // } + // } + } - FrameLayout.LayoutParams layoutParams; - layoutParams = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.FILL_PARENT, - FrameLayout.LayoutParams.FILL_PARENT, - android.view.Gravity.CENTER_HORIZONTAL | android.view.Gravity.CENTER_VERTICAL); + FrameLayout.LayoutParams layoutParams; + layoutParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.FILL_PARENT, + FrameLayout.LayoutParams.FILL_PARENT, + android.view.Gravity.CENTER_HORIZONTAL | android.view.Gravity.CENTER_VERTICAL); - imageView.setLayoutParams(layoutParams); + imageView.setLayoutParams(layoutParams); - fSplashView.addView(imageView); - // Make visible - viewManager.getContentView().addView(fSplashView, layoutParams); - } - catch (Exception ex) { - Log.v("Corona", "showCoronaSplashScreen display EXCEPTION: " + ex); - } + fSplashView.addView(imageView); + // Make visible + viewManager.getContentView().addView(fSplashView, layoutParams); + } + catch (Exception ex) { + Log.v("Corona", "showCoronaSplashScreen display EXCEPTION: " + ex); } } } diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java b/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java index 718ad04be..772d50a5d 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaEnvironment.java @@ -405,7 +405,7 @@ public static void setLuaErrorHandler(com.naef.jnlua.JavaFunction handler) { } /** - * Called by the C++ side of Corona when a Lua error occurrs. + * Called by the C++ side of Corona when a Lua error occurs. * Should only be invoked if JavaToNativeShim.useDefaultLuaErrorHandler() has been called, * which sets up the core code to use a custom error handler implemented on the Java side. *
diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java b/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java index 126b77e19..4e96aa9ae 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaSystemApiHandler.java @@ -9,10 +9,11 @@ package com.ansca.corona; +import android.os.Build; import android.util.Log; import android.content.Intent; -/** The interface has all the funcations that are activity specific and aren't implemented by default. */ +/** The interface has all the functions that are activity specific and aren't implemented by default. */ public class CoronaSystemApiHandler implements com.ansca.corona.listeners.CoronaSystemApiListener { private CoronaActivity fActivity; private static final boolean DEBUG = true; @@ -111,6 +112,21 @@ else if (actionName.equals("validateResourceFile")) return false; } } + else if (actionName.equals("reportFullyDrawn")) + { + // Report to the system that app is now fully drawn, for diagnostic and optimization purposes. + // API introduced in KITKAT but has permission issue, so raise to LOLLIPOP, see https://github.com/flutter/flutter/issues/46172. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + fActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (fActivity != null) { + fActivity.reportFullyDrawn(); + } + } + }); + } + } else { // The requested action is unknown. return false; diff --git a/platform/android/sdk/src/com/ansca/corona/CoronaView.java b/platform/android/sdk/src/com/ansca/corona/CoronaView.java index 8f1a79d3f..0893790ae 100644 --- a/platform/android/sdk/src/com/ansca/corona/CoronaView.java +++ b/platform/android/sdk/src/com/ansca/corona/CoronaView.java @@ -173,7 +173,7 @@ protected Parcelable onSaveInstanceState() { } /** - * Initalizes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. Uses the base "assets" directory as the base + * Initializes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. Uses the base "assets" directory as the base * Corona project directory. *
* This must be the first function you call! @@ -183,10 +183,10 @@ public void init() { } /** - * Initalizes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. + * Initializes the {@link com.ansca.corona.CoronaView CoronaView} so that it can be used. *
* This must be the first function you call!
- * @param baseDir The directory of the Corona project relative to the "assests" directory.
+ * @param baseDir The directory of the Corona project relative to the "assets" directory.
*/
public void init(String baseDir) {
if (Looper.myLooper() == null) {
diff --git a/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java b/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java
index e2dca97b7..7e3916368 100644
--- a/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java
+++ b/platform/android/sdk/src/com/ansca/corona/NativeToJavaBridge.java
@@ -146,7 +146,7 @@ protected static int callLoadClass(
StringBuilder err = new StringBuilder();
if (runtime != null) {
// Fetch the runtime's Lua state.
- // TODO: We need to account for corountines.
+ // TODO: We need to account for coroutines.
LuaState L = runtime.getLuaState();
if ( null == L ) {
L = new com.naef.jnlua.LuaState(luaStateMemoryAddress);
diff --git a/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java b/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java
index 3b64be992..1c38c94f7 100644
--- a/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java
+++ b/platform/android/sdk/src/com/ansca/corona/listeners/CoronaSystemApiListener.java
@@ -12,7 +12,7 @@
import android.content.Intent;
import com.ansca.corona.CoronaRuntime;
-/** The interface has all the funcations that are activity specific and aren't implemented by default. */
+/** The interface has all the functions that are activity specific and aren't implemented by default. */
public interface CoronaSystemApiListener{
public boolean requestSystem(CoronaRuntime runtime, String actionName, long luaStateMemoryAddress, int luaStackIndex);
diff --git a/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java b/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java
index 309874a17..f9cd3e534 100644
--- a/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java
+++ b/platform/android/sdk/src/com/ansca/corona/storage/FileServices.java
@@ -44,6 +44,13 @@ public class FileServices extends com.ansca.corona.ApplicationContextProvider {
/** Provides fast access to file entries within an APK file, which is really a zip file. */
private static ZipResourceFile sApkZipEntryReader = null;
+ /**
+ * For more efficient I/O throughput, BUFFER_SIZE at least 4KB is needed.
+ * For copy size 1MB and above, 64KB is recommended.
+ */
+ private final static int BUFFER_SIZE_NORMAL = 4096; // 4KB
+ private final static int BUFFER_SIZE_LARGE_IO = 65536; // 64KB
+ private final static int BUFFER_SIZE_THRESHOLD = 1048576; // 1MB
/**
* Creates an object that provides easy access to the file system and this application's
@@ -417,7 +424,8 @@ public void loadExpansionFiles() {
// Attempt to load the expansion files.
sHasAccessedExpansionFileDirectory = false;
- if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
+ if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)
+ || android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY)) {
java.io.File expansionDirectory = getExpansionFileDirectory();
if ((expansionDirectory != null) && expansionDirectory.exists()) {
try { sPatchExpansionZipReader = new ZipResourceFile(getPatchExpansionFile()); }
@@ -958,7 +966,7 @@ public boolean copyFile(java.io.File sourceFile, java.io.File destinationFile) {
if (outputStream != null) {
int byteCount = inputStream.available();
if (byteCount > 0) {
- final int BUFFER_SIZE = 1024;
+ final int BUFFER_SIZE = byteCount > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL;
byte[] byteBuffer = new byte[BUFFER_SIZE];
while (byteCount > 0) {
int bytesToCopy = BUFFER_SIZE;
@@ -1020,7 +1028,7 @@ public boolean writeToFile(java.io.InputStream inputStream, java.io.File destina
try {
outputStream = new java.io.FileOutputStream(destinationFile);
if (outputStream != null) {
- final int BUFFER_SIZE = 1024;
+ final int BUFFER_SIZE = inputStream.available() > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL;
byte[] byteBuffer = new byte[BUFFER_SIZE];
while (true) {
int bytesToCopy = BUFFER_SIZE;
@@ -1112,13 +1120,15 @@ public byte[] getBytesFromFile(String filePath) {
try {
inputStream = openFile(filePath);
if (inputStream != null) {
- int byteCount = inputStream.available();
+ final int byteCount = inputStream.available();
if (byteCount > 0) {
bytes = new byte[byteCount];
+ final int BUFFER_SIZE = byteCount > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL;
+
for (int bytesCopied = 0; bytesCopied < byteCount;) {
int bytesToRead = byteCount - bytesCopied;
- if (bytesToRead > 1024) {
- bytesToRead = 1024;
+ if (bytesToRead > BUFFER_SIZE) {
+ bytesToRead = BUFFER_SIZE;
}
int readBytes = inputStream.read(bytes, bytesCopied, bytesToRead);
bytesCopied += readBytes;
From 996f85d0d4d47b8ff5e04853858fdcea553f4917 Mon Sep 17 00:00:00 2001
From: Huynh Quoc Khanh aka Kan <70838508+Kan-Kzeit@users.noreply.github.com>
Date: Mon, 20 Nov 2023 08:11:46 +0700
Subject: [PATCH 2/2] Core: adding some extensions getter method of box2D
(#647)
Co-authored-by: Vlad Svoka