[Scummvm-git-logs] scummvm master -> aef1690c1d115e3d15b043ab5ef61ff46aa7d531

lephilousophe noreply at scummvm.org
Tue Nov 12 21:46:26 UTC 2024


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
eed4d8a219 ANDROID: Add folders support to copyAssetsToInternalMemory
5603f64873 ANDROID: Use a checksum of all assets to determine if an update is needed
90f7892e3b ANDROID: Forward to C++ side the assets change status
aef1690c1d ANDROID: Allow packagers to bundle games in the assets


Commit: eed4d8a21971e03786bd672c3576f3f9d941d634
    https://github.com/scummvm/scummvm/commit/eed4d8a21971e03786bd672c3576f3f9d941d634
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2024-11-12T22:46:21+01:00

Commit Message:
ANDROID: Add folders support to copyAssetsToInternalMemory

This allows to extract shaders too.
Move the assets inside a specific subfolder.
This avoid extracting some data from system assets.

Changed paths:
    backends/platform/android/android.mk
    backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java


diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index 4011f83a705..9a63072bd1f 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -5,7 +5,8 @@ GRADLE_FILES = $(shell find $(PATH_DIST)/gradle -type f)
 
 PATH_BUILD = ./android_project
 PATH_BUILD_GRADLE = $(PATH_BUILD)/gradle/.timestamp $(PATH_BUILD)/gradlew $(PATH_BUILD)/build.gradle $(PATH_BUILD)/settings.gradle $(PATH_BUILD)/mainAssets/build.gradle $(PATH_BUILD)/gradle.properties $(PATH_BUILD)/local.properties $(PATH_BUILD)/src.properties
-PATH_BUILD_ASSETS = $(PATH_BUILD)/mainAssets/src/main/assets
+# $(PATH_BUILD)/mainAssets/src/main/assets is the root and everything is placed in the assets subdirectory
+PATH_BUILD_ASSETS = $(PATH_BUILD)/mainAssets/src/main/assets/assets
 PATH_BUILD_LIB = $(PATH_BUILD)/lib/$(ABI)
 PATH_BUILD_LIBSCUMMVM = $(PATH_BUILD)/lib/$(ABI)/libscummvm.so
 
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index a792ea29654..429c6e147f1 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -53,6 +53,7 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -839,11 +840,14 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 
 		@Override
 		protected String[] getSysArchives() {
-			Log.d(ScummVM.LOG_TAG, "Adding to Search Archive: " + _actualScummVMDataDir.getPath());
+			File assetsDir = new File(_actualScummVMDataDir, "assets");
+			Log.d(ScummVM.LOG_TAG, "Adding to Search Archive: " + assetsDir.getPath());
 			if (_externalPathAvailableForReadAccess && _possibleExternalScummVMDir != null) {
 				Log.d(ScummVM.LOG_TAG, "Adding to Search Archive: " + _possibleExternalScummVMDir.getPath());
-				return new String[]{_actualScummVMDataDir.getPath(), _possibleExternalScummVMDir.getPath()};
-			} else return new String[]{_actualScummVMDataDir.getPath()};
+				return new String[]{assetsDir.getPath(), _possibleExternalScummVMDir.getPath()};
+			} else {
+				return new String[]{assetsDir.getPath()};
+			}
 		}
 
 		@Override
@@ -1964,97 +1968,189 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		return true;
 	}
 
+	// Deletes recursively a directory and its contents
+	private static void deleteDir(File dir) {
+		for (File child : dir.listFiles()) {
+			if (child.isDirectory()) {
+				deleteDir(child);
+			} else {
+				if (!child.delete()) {
+					Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + child.getPath());
+				}
+			}
+		}
+		if (!dir.delete()) {
+			Log.e(ScummVM.LOG_TAG, "Failed to delete dir:" + dir.getPath());
+		}
+	}
 
-	private boolean containsStringEntry(@NonNull String[] stringItenary, String targetEntry) {
-		for (String sourceEntry : stringItenary) {
-			// Log.d(ScummVM.LOG_TAG, "Comparing filename: " + sourceEntry + " to filename: " + targetEntry);
-			if (sourceEntry.compareToIgnoreCase(targetEntry) == 0) {
-				return true;
+	// clear up all files in the root of the internal app directory
+	// Don't remove the scummvm.ini nor the scummvm.log file!
+	private static void internalAppFolderCleanup(File dataDir) {
+		// We check if we already did the cleanup before by using a known to exist file
+		// scummmodern.zip has always been there in the Android port
+		if (!(new File(dataDir, "scummmodern.zip")).exists()) {
+			// We already did the cleanup: nothing to do
+			return;
+		}
+
+		File[] extfiles = dataDir.listFiles();
+		if (extfiles == null) {
+			// This should not happen
+			return;
+		}
+
+		Log.d(ScummVM.LOG_TAG, "Cleaning up old files in " + dataDir.getPath());
+		for (File extfile : extfiles) {
+			if (extfile.isDirectory()) {
+				// We never extracted folders before
+				continue;
+			}
+			// Skip scummvm.ini, scummvm.log at root
+			String name = extfile.getName();
+			if ((name.compareToIgnoreCase("scummvm.ini") == 0) ||
+				(name.compareToIgnoreCase("scummvm.log") == 0)) {
+					continue;
+			}
+			Log.d(ScummVM.LOG_TAG, "Deleting file:" + extfile.getName());
+			if (!extfile.delete()) {
+				Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + extfile.getName());
 			}
 		}
-		return false;
 	}
 
 	// clear up any possibly deprecated assets (when upgrading to a new version)
 	// Don't remove the scummvm.ini nor the scummvm.log file!
 	// Remove any files not in the filesItenary, even in a sideUpgrade
 	// Remove any files in the filesItenary only if not a sideUpgrade
-	private void internalAppFolderCleanup(String[] filesItenary, boolean sideUpgrade) {
-		if (_actualScummVMDataDir != null) {
-			File[] extfiles = _actualScummVMDataDir.listFiles();
-			if (extfiles != null) {
-				Log.d(ScummVM.LOG_TAG, "Cleaning up files in internal app space");
-				for (File extfile : extfiles) {
-					if (extfile.isFile()) {
-						if (extfile.getName().compareToIgnoreCase("scummvm.ini") != 0
-							&& extfile.getName().compareToIgnoreCase("scummvm.log") != 0
-							&& (!containsStringEntry(filesItenary, extfile.getName())
-							|| !sideUpgrade)
-						) {
-							Log.d(ScummVM.LOG_TAG, "Deleting file:" + extfile.getName());
-							if (!extfile.delete()) {
-								Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + extfile.getName());
-							}
-						}
-					}
+	// Returns true if the dataDir was a directory and false otherwise
+	private static boolean assetsFolderCleanup(boolean sideUpgrade, File dataDir, String[] assetsToExtract) {
+		HashSet<String> filesToKeep = new HashSet<>(Arrays.asList(assetsToExtract));
+
+		File[] extfiles = dataDir.listFiles();
+		if (extfiles == null) {
+			// If we are here, this means dataDir is a file
+			return false;
+		}
+
+		Log.d(ScummVM.LOG_TAG, "Cleaning up files in " + dataDir.getPath());
+		for (File extfile : extfiles) {
+			String name = extfile.getName();
+
+			if (filesToKeep.contains(name) && sideUpgrade) {
+				continue;
+			}
+
+			if (extfile.isDirectory()) {
+				Log.d(ScummVM.LOG_TAG, "Deleting folder:" + extfile.getName());
+				deleteDir(extfile);
+			} else {
+				Log.d(ScummVM.LOG_TAG, "Deleting file:" + extfile.getName());
+				if (!extfile.delete()) {
+					Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + extfile.getName());
 				}
 			}
 		}
+		return true;
 	}
 
 	// code based on https://stackoverflow.com/a/4530294
 	// Note, the following assumptions are made (since they are true as of yet)
-	// - We don't need to copy (sub)folders
 	// - We copy all the files from our assets (not a subset of them)
 	// Otherwise we would probably need to create a specifically named zip file with the selection of files we'd need to extract to the internal memory
-	private void copyAssetsToInternalMemory(boolean sideUpgrade) {
-		// sideUpgrade is set to true, if we upgrade to the same version -- just check for the files existence before copying
-		if (_actualScummVMDataDir != null) {
-			AssetManager assetManager = getAssets();
-			String[] files = null;
-			try {
-				files = assetManager.list("");
-			} catch (IOException e) {
-				Log.e(ScummVM.LOG_TAG, "Failed to get asset file list.", e);
+	// Returns true if the assetDir was a directory and false otherwise
+	private static boolean extractAssets(boolean sideUpgrade, AssetManager assetManager, String assetDir, File dataDir) {
+		String[] files = null;
+		try {
+			files = assetManager.list(assetDir);
+		} catch (IOException e) {
+			Log.e(ScummVM.LOG_TAG, "Failed to get asset file list.", e);
+		}
+
+		if (files == null || files.length == 0) {
+			// The asset is a file: remove any directory with the same name
+			if (dataDir.isDirectory()) {
+				deleteDir(dataDir);
+			}
+			return false;
+		}
+
+		// Starting from here, assetDir is a directory
+
+		// Cleanup old files
+		if (!assetsFolderCleanup(sideUpgrade, dataDir, files)) {
+			// dataDir is a file but we need a folder
+			if (dataDir.exists()) {
+				if (!dataDir.delete()) {
+					Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + dataDir.getName());
+					// There is no point on continuing this
+					return true;
+				}
+			}
+		}
+
+		if (!dataDir.exists()) {
+			if (!dataDir.mkdir()) {
+				Log.e(ScummVM.LOG_TAG, "Failed to create directory: " + dataDir.getPath());
+				// There is no point on continuing this
+				return true;
 			}
+		}
 
-			internalAppFolderCleanup(files, sideUpgrade);
+		for (String filename : files) {
+			String assetPath = (assetDir.length() > 0 ? assetDir + File.separator : "") + filename;
+			File dataPath = new File(dataDir, filename);
+
+			if (extractAssets(sideUpgrade, assetManager, assetPath, dataPath)) {
+				// This was a directory: no data to extract
+				continue;
+			}
 
-			if (files != null) {
-				for (String filename : files) {
-					InputStream in = null;
-					OutputStream out = null;
+			// This must be a file: extract it
+			InputStream in = null;
+			OutputStream out = null;
+			try {
+				// sideUpgrade is set to true, if we upgrade to the same version -- just check for the files existence before copying
+				if (sideUpgrade && dataPath.exists()) {
+					Log.d(ScummVM.LOG_TAG, "Side-upgrade. No need to update asset file: " + assetPath);
+					continue;
+				}
+
+				Log.d(ScummVM.LOG_TAG, "Copying asset file: " + assetPath);
+				in = assetManager.open(assetPath);
+				out = new FileOutputStream(dataPath);
+				copyStreamToStream(in, out);
+			} catch (IOException e) {
+				Log.e(ScummVM.LOG_TAG, "Failed to copy asset file: " + assetPath);
+			} finally {
+				if (in != null) {
 					try {
-						in = assetManager.open(filename);
-						File outFile = new File(_actualScummVMDataDir, filename);
-						if (sideUpgrade && outFile.exists()) {
-							Log.d(ScummVM.LOG_TAG, "Side-upgrade. No need to update asset file: " + filename);
-						} else {
-							Log.d(ScummVM.LOG_TAG, "Copying asset file: " + filename);
-							out = new FileOutputStream(outFile);
-							copyStreamToStream(in, out);
-						}
+						in.close();
 					} catch (IOException e) {
-						Log.e(ScummVM.LOG_TAG, "Failed to copy asset file: " + filename);
-					} finally {
-						if (in != null) {
-							try {
-								in.close();
-							} catch (IOException e) {
-								// NOOP
-							}
-						}
-						if (out != null) {
-							try {
-								out.close();
-							} catch (IOException e) {
-								// NOOP
-							}
-						}
+						// NOOP
+					}
+				}
+				if (out != null) {
+					try {
+						out.close();
+					} catch (IOException e) {
+						// NOOP
 					}
 				}
 			}
 		}
+		return true;
+	}
+
+	private void copyAssetsToInternalMemory(boolean sideUpgrade) {
+		if (_actualScummVMDataDir == null) {
+			return;
+		}
+
+		internalAppFolderCleanup(_actualScummVMDataDir);
+
+		AssetManager assetManager = getAssets();
+		extractAssets(sideUpgrade, assetManager, "assets", new File(_actualScummVMDataDir, "assets"));
 	}
 
 	// -------------------------------------------------------------------------------------------


Commit: 5603f64873ff25cba6bc2fab4b2a2af4c525439f
    https://github.com/scummvm/scummvm/commit/5603f64873ff25cba6bc2fab4b2a2af4c525439f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2024-11-12T22:46:21+01:00

Commit Message:
ANDROID: Use a checksum of all assets to determine if an update is needed

Changed paths:
    backends/platform/android/android.mk
    backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java


diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index 9a63072bd1f..62ae69793d1 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -6,7 +6,7 @@ GRADLE_FILES = $(shell find $(PATH_DIST)/gradle -type f)
 PATH_BUILD = ./android_project
 PATH_BUILD_GRADLE = $(PATH_BUILD)/gradle/.timestamp $(PATH_BUILD)/gradlew $(PATH_BUILD)/build.gradle $(PATH_BUILD)/settings.gradle $(PATH_BUILD)/mainAssets/build.gradle $(PATH_BUILD)/gradle.properties $(PATH_BUILD)/local.properties $(PATH_BUILD)/src.properties
 # $(PATH_BUILD)/mainAssets/src/main/assets is the root and everything is placed in the assets subdirectory
-PATH_BUILD_ASSETS = $(PATH_BUILD)/mainAssets/src/main/assets/assets
+PATH_BUILD_ASSETS = $(PATH_BUILD)/mainAssets/src/main/assets
 PATH_BUILD_LIB = $(PATH_BUILD)/lib/$(ABI)
 PATH_BUILD_LIBSCUMMVM = $(PATH_BUILD)/lib/$(ABI)/libscummvm.so
 
@@ -42,43 +42,51 @@ $(PATH_BUILD)/local.properties: configure.stamp | $(PATH_BUILD)
 $(PATH_BUILD)/src.properties: configure.stamp | $(PATH_BUILD)
 	$(ECHO) "srcdir=$(realpath $(srcdir))\n" > $(PATH_BUILD)/src.properties
 
-$(PATH_BUILD)/mainAssets/build.gradle: $(PATH_DIST)/mainAssets.gradle | $(PATH_BUILD_ASSETS)
+$(PATH_BUILD)/mainAssets/build.gradle: $(PATH_DIST)/mainAssets.gradle | $(PATH_BUILD_ASSETS)/MD5SUMS
 	$(INSTALL) -c -m 644 $< $@
 
-$(PATH_BUILD_ASSETS): $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) $(DIST_FILES_SHADERS) | $(PATH_BUILD)
-	$(INSTALL) -d $(PATH_BUILD_ASSETS)
-	$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) $(PATH_BUILD_ASSETS)/
+$(PATH_BUILD_ASSETS)/MD5SUMS: $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) $(DIST_FILES_SHADERS) | $(PATH_BUILD)
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/
+	$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) $(PATH_BUILD_ASSETS)/assets/
 ifneq ($(DIST_FILES_SHADERS),)
-	$(INSTALL) -d $(PATH_BUILD_ASSETS)/shaders
-	$(INSTALL) -c -m 644 $(DIST_FILES_SHADERS) $(PATH_BUILD_ASSETS)/shaders
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/shaders
+	$(INSTALL) -c -m 644 $(DIST_FILES_SHADERS) $(PATH_BUILD_ASSETS)/assets/shaders
 endif
+	(cd $(PATH_BUILD_ASSETS)/ && find assets -type f | sort | xargs md5sum) > $@
 
 ifdef DIST_ANDROID_CACERT_PEM
-$(PATH_BUILD_ASSETS)/cacert.pem: $(DIST_ANDROID_CACERT_PEM) | $(PATH_BUILD_ASSETS)
-	$(INSTALL) -c -m 644 $(DIST_ANDROID_CACERT_PEM) $(PATH_BUILD_ASSETS)/cacert.pem
+$(PATH_BUILD_ASSETS)/assets/cacert.pem: $(DIST_ANDROID_CACERT_PEM)
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/
+	$(INSTALL) -c -m 644 $(DIST_ANDROID_CACERT_PEM) $(PATH_BUILD_ASSETS)/assets/cacert.pem
+$(PATH_BUILD_ASSETS)/MD5SUMS: $(PATH_BUILD_ASSETS)/assets/cacert.pem
 else
 ifdef USE_CURL
-$(PATH_BUILD_ASSETS)/cacert.pem: | $(PATH_BUILD_ASSETS)
-	$(QUIET_CURL)$(CURL) -s https://curl.se/ca/cacert.pem --time-cond $(PATH_BUILD_ASSETS)/cacert.pem --output $(PATH_BUILD_ASSETS)/cacert.pem
-androidcacert: | $(PATH_BUILD_ASSETS)
-	$(QUIET_CURL)$(CURL) -s https://curl.se/ca/cacert.pem --time-cond $(PATH_BUILD_ASSETS)/cacert.pem --output $(PATH_BUILD_ASSETS)/cacert.pem
+$(PATH_BUILD_ASSETS)/cacert.pem:
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/
+	$(QUIET_CURL)$(CURL) -s https://curl.se/ca/cacert.pem --time-cond $(PATH_BUILD_ASSETS)/assets/cacert.pem --output $(PATH_BUILD_ASSETS)/assets/cacert.pem
+androidcacert:
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/
+	$(QUIET_CURL)$(CURL) -s https://curl.se/ca/cacert.pem --time-cond $(PATH_BUILD_ASSETS)/assets/cacert.pem --output $(PATH_BUILD_ASSETS)/assets/cacert.pem
+
 .PHONY: androidcacert
 endif
 endif
+# Make MD5SUMS depend on cacert. If it's not here and neither DIST_ANDROID_CACERT_PEM nor USE_CURL are defined, it will error out
+$(PATH_BUILD_ASSETS)/MD5SUMS: $(PATH_BUILD_ASSETS)/assets/cacert.pem
 
 $(PATH_BUILD_LIBSCUMMVM): libscummvm.so | $(PATH_BUILD)
 	$(INSTALL) -d  $(PATH_BUILD_LIB)
 	$(INSTALL) -c -m 644 libscummvm.so $(PATH_BUILD_LIBSCUMMVM)
 
-$(APK_MAIN): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS) $(PATH_BUILD_ASSETS)/cacert.pem $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
+$(APK_MAIN): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS)/MD5SUMS $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
 	(cd $(PATH_BUILD); ./gradlew assembleDebug)
 	$(CP) $(PATH_BUILD)/build/outputs/apk/debug/$(APK_MAIN) $@
 
-$(APK_MAIN_RELEASE): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS) $(PATH_BUILD_ASSETS)/cacert.pem $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
+$(APK_MAIN_RELEASE): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS)/MD5SUMS $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
 	(cd $(PATH_BUILD); ./gradlew assembleRelease)
 	$(CP) $(PATH_BUILD)/build/outputs/apk/release/$(APK_MAIN_RELEASE) $@
 
-$(AAB_MAIN_RELEASE): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS) $(PATH_BUILD_ASSETS)/cacert.pem $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
+$(AAB_MAIN_RELEASE): $(PATH_BUILD_GRADLE) $(PATH_BUILD_ASSETS)/MD5SUMS $(PATH_BUILD_LIBSCUMMVM) | $(PATH_BUILD)
 	(cd $(PATH_BUILD); ./gradlew bundleRelease -PsplitAssets)
 	$(CP) $(PATH_BUILD)/build/outputs/bundle/release/$(AAB_MAIN_RELEASE) $@
 
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index 429c6e147f1..320b61ab43a 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -46,6 +46,8 @@ import android.widget.Toast;
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -1418,6 +1420,27 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		}
 	}
 
+	private static boolean equalsStreamToStream(InputStream is1, InputStream is2) throws IOException {
+		byte[] buffer1 = new byte[1024];
+		byte[] buffer2 = new byte[1024];
+		int length1, length2;
+
+		while (true) {
+			length1 = is1.read(buffer1);
+			length2 = is2.read(buffer2);
+			if (length1 != length2) {
+				return false;
+			}
+			if (length1 == -1) {
+				// Both streams are finished at the same point
+				return true;
+			}
+			if (!Arrays.equals(buffer1, buffer2)) {
+				return false;
+			}
+		}
+	}
+
 	private static String getVersionInfoFromScummvmConfiguration(String fullIniFilePath) {
 		Map<String, Map<String, String>> parsedIniMap;
 		try (FileReader reader = new FileReader(fullIniFilePath)) {
@@ -1687,25 +1710,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			Log.d(ScummVM.LOG_TAG, "No viable existing ScummVM config version found");
 		}
 
-		//
-		// TODO The assets cleanup upgrading system is not perfect but it will have to do
-		//      A more efficient way would be to compare hash (when we deem that an upgrade is happening, so we will also still have to compare versions)
-		// Note that isSideUpgrading is also true each time we re-launch the app
-		// Also even during a side-upgrade we cleanup any redundant files (no longer part of our assets)
-
-		// By first checking for isDirty() and then comparing the Version objects,
-		// we don't need to also compare the Version descriptions (full version text) for a match too,
-		// since, if the full versions text do not match, it's because at least one of them is dirty.
-		// TODO: This does mean that "pre" (or similar) versions (eg. 2.2.1pre) will always be considered non-side-upgrades
-		//        and will re-copy the assets upon each launch
-		//       This should have a slight performance impact (for launch time) for those intermediate version releases,
-		//       but it's better than the alternative (comparing MD5 hashes for all files), and it should go away with the next proper release.
-		//       This solution should cover "git" versions properly
-		//       (ie. developer builds, built with release configuration (eg 2.3.0git) or debug configuration (eg. 2.3.0git9272-gc71ac4748b))
-		boolean isSideUpgrading = (!_currentScummVMVersion.isDirty()
-		                           && !maxOldVersionFound.isDirty()
-		                           && maxOldVersionFound.compareTo(_currentScummVMVersion) == 0);
-		copyAssetsToInternalMemory(isSideUpgrading);
+		updateAssetsToInternalMemory();
 
 		//
 		// Set global savepath
@@ -2021,10 +2026,9 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 
 	// clear up any possibly deprecated assets (when upgrading to a new version)
 	// Don't remove the scummvm.ini nor the scummvm.log file!
-	// Remove any files not in the filesItenary, even in a sideUpgrade
-	// Remove any files in the filesItenary only if not a sideUpgrade
+	// Remove any files not in the assetsToExtract
 	// Returns true if the dataDir was a directory and false otherwise
-	private static boolean assetsFolderCleanup(boolean sideUpgrade, File dataDir, String[] assetsToExtract) {
+	private static boolean assetsFolderCleanup(File dataDir, String[] assetsToExtract) {
 		HashSet<String> filesToKeep = new HashSet<>(Arrays.asList(assetsToExtract));
 
 		File[] extfiles = dataDir.listFiles();
@@ -2037,7 +2041,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		for (File extfile : extfiles) {
 			String name = extfile.getName();
 
-			if (filesToKeep.contains(name) && sideUpgrade) {
+			if (filesToKeep.contains(name)) {
 				continue;
 			}
 
@@ -2048,6 +2052,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 				Log.d(ScummVM.LOG_TAG, "Deleting file:" + extfile.getName());
 				if (!extfile.delete()) {
 					Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + extfile.getName());
+					// Ignore error, that will be a leftover
 				}
 			}
 		}
@@ -2059,12 +2064,13 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 	// - We copy all the files from our assets (not a subset of them)
 	// Otherwise we would probably need to create a specifically named zip file with the selection of files we'd need to extract to the internal memory
 	// Returns true if the assetDir was a directory and false otherwise
-	private static boolean extractAssets(boolean sideUpgrade, AssetManager assetManager, String assetDir, File dataDir) {
+	private static boolean extractAssets(AssetManager assetManager, String assetDir, File dataDir) throws IOException {
 		String[] files = null;
 		try {
 			files = assetManager.list(assetDir);
 		} catch (IOException e) {
 			Log.e(ScummVM.LOG_TAG, "Failed to get asset file list.", e);
+			throw e;
 		}
 
 		if (files == null || files.length == 0) {
@@ -2078,13 +2084,13 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		// Starting from here, assetDir is a directory
 
 		// Cleanup old files
-		if (!assetsFolderCleanup(sideUpgrade, dataDir, files)) {
+		if (!assetsFolderCleanup(dataDir, files)) {
 			// dataDir is a file but we need a folder
 			if (dataDir.exists()) {
 				if (!dataDir.delete()) {
 					Log.e(ScummVM.LOG_TAG, "Failed to delete file:" + dataDir.getName());
 					// There is no point on continuing this
-					return true;
+					throw new IOException("Failed to delete file:" + dataDir.getName());
 				}
 			}
 		}
@@ -2093,7 +2099,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			if (!dataDir.mkdir()) {
 				Log.e(ScummVM.LOG_TAG, "Failed to create directory: " + dataDir.getPath());
 				// There is no point on continuing this
-				return true;
+				throw new IOException("Failed to create directory:" + dataDir.getName());
 			}
 		}
 
@@ -2101,7 +2107,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			String assetPath = (assetDir.length() > 0 ? assetDir + File.separator : "") + filename;
 			File dataPath = new File(dataDir, filename);
 
-			if (extractAssets(sideUpgrade, assetManager, assetPath, dataPath)) {
+			if (extractAssets(assetManager, assetPath, dataPath)) {
 				// This was a directory: no data to extract
 				continue;
 			}
@@ -2110,12 +2116,6 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			InputStream in = null;
 			OutputStream out = null;
 			try {
-				// sideUpgrade is set to true, if we upgrade to the same version -- just check for the files existence before copying
-				if (sideUpgrade && dataPath.exists()) {
-					Log.d(ScummVM.LOG_TAG, "Side-upgrade. No need to update asset file: " + assetPath);
-					continue;
-				}
-
 				Log.d(ScummVM.LOG_TAG, "Copying asset file: " + assetPath);
 				in = assetManager.open(assetPath);
 				out = new FileOutputStream(dataPath);
@@ -2142,7 +2142,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		return true;
 	}
 
-	private void copyAssetsToInternalMemory(boolean sideUpgrade) {
+	private void updateAssetsToInternalMemory() {
 		if (_actualScummVMDataDir == null) {
 			return;
 		}
@@ -2150,7 +2150,87 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 		internalAppFolderCleanup(_actualScummVMDataDir);
 
 		AssetManager assetManager = getAssets();
-		extractAssets(sideUpgrade, assetManager, "assets", new File(_actualScummVMDataDir, "assets"));
+
+		// We need to compare MD5SUMS from our assets with what is on disk
+		File md5sumsPath = new File(_actualScummVMDataDir, "MD5SUMS");
+
+		Log.d(ScummVM.LOG_TAG, "Checking status of MD5SUMS");
+		// First: read MD5SUMS from our assets, we will need it
+		byte[] newSums = null;
+		{
+			InputStream newStreamAsset = null;
+			try {
+				newStreamAsset = assetManager.open("MD5SUMS");
+				ByteArrayOutputStream newStream = new ByteArrayOutputStream();
+				copyStreamToStream(newStreamAsset, newStream);
+				newSums = newStream.toByteArray();
+			} catch (IOException e) {
+				Log.e(ScummVM.LOG_TAG, "Failed to read MD5SUMS asset");
+			} finally {
+				if (newStreamAsset != null) {
+					try {
+						newStreamAsset.close();
+					} catch (IOException e) {
+						// NOOP
+					}
+				}
+				// Closing a ByteArrayOutputStream is useless
+			}
+		}
+
+		// Then: open the on disk file, check its size and if they match, compare the contents
+		if (newSums != null && newSums.length > 0) {
+			FileInputStream oldStream = null;
+			try {
+				oldStream = new FileInputStream(md5sumsPath);
+				if (oldStream.getChannel().size() == newSums.length &&
+					equalsStreamToStream(new ByteArrayInputStream(newSums), oldStream)) {
+					// The files are identical: nothing to do
+					Log.d(ScummVM.LOG_TAG, "MD5SUMS is already up to date");
+					return;
+				}
+			} catch (IOException e) {
+				Log.e(ScummVM.LOG_TAG, "Failed to read MD5SUMS file");
+			} finally {
+				if (oldStream != null) {
+					try {
+						oldStream.close();
+					} catch (IOException e) {
+						// NOOP
+					}
+				}
+			}
+		}
+
+		// Continue: with extracting the whole assets
+		try {
+			extractAssets(assetManager, "assets", new File(_actualScummVMDataDir, "assets"));
+		} catch (IOException e) {
+			Log.e(ScummVM.LOG_TAG, "An error happened while extracting the assets");
+			// Don't write the new MD5SUMS: we did not finish our work well
+			return;
+		}
+
+
+		// Finally: everything is now fresh, store the new sums
+		if (newSums != null) {
+			FileOutputStream newStream = null;
+			try {
+				newStream = new FileOutputStream(md5sumsPath);
+				newStream.write(newSums);
+			} catch (IOException e) {
+				Log.e(ScummVM.LOG_TAG, "Failed to write MD5SUMS file");
+				// If we fail to write MD5SUMS, we will try again at the next startup
+			} finally {
+				if (newStream != null) {
+					try {
+						newStream.close();
+					} catch (IOException e) {
+						// NOOP
+					}
+				}
+			}
+		}
 	}
 
 	// -------------------------------------------------------------------------------------------


Commit: 90f7892e3b8165f3a43e90269aca8f3d6cff6e7e
    https://github.com/scummvm/scummvm/commit/90f7892e3b8165f3a43e90269aca8f3d6cff6e7e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2024-11-12T22:46:21+01:00

Commit Message:
ANDROID: Forward to C++ side the assets change status

Changed paths:
    backends/platform/android/jni-android.cpp
    backends/platform/android/jni-android.h
    backends/platform/android/org/scummvm/scummvm/ScummVM.java
    backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java


diff --git a/backends/platform/android/jni-android.cpp b/backends/platform/android/jni-android.cpp
index c8808bbc7dc..f2f43971064 100644
--- a/backends/platform/android/jni-android.cpp
+++ b/backends/platform/android/jni-android.cpp
@@ -69,6 +69,8 @@ int JNI::_egl_version = 0;
 Common::Archive *JNI::_asset_archive = 0;
 OSystem_Android *JNI::_system = 0;
 
+bool JNI::assets_updated = false;
+
 bool JNI::pause = false;
 sem_t JNI::pause_sem;
 
@@ -120,7 +122,7 @@ const JNINativeMethod JNI::_natives[] = {
 	{ "create", "(Landroid/content/res/AssetManager;"
 				"Ljavax/microedition/khronos/egl/EGL10;"
 				"Ljavax/microedition/khronos/egl/EGLDisplay;"
-				"Landroid/media/AudioTrack;II)V",
+				"Landroid/media/AudioTrack;IIZ)V",
 		(void *)JNI::create },
 	{ "destroy", "()V",
 		(void *)JNI::destroy },
@@ -721,7 +723,8 @@ void JNI::setAudioStop() {
 
 void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
 				jobject egl, jobject egl_display,
-				jobject at, jint audio_sample_rate, jint audio_buffer_size) {
+				jobject at, jint audio_sample_rate, jint audio_buffer_size,
+				jboolean assets_updated_) {
 	LOGI("Native version: %s", gScummVMFullVersion);
 
 	assert(!_system);
@@ -798,6 +801,8 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
 	env->DeleteLocalRef(cls);
 #undef FIND_METHOD
 
+	assets_updated = assets_updated_;
+
 	pause = false;
 	// initial value of zero!
 	sem_init(&pause_sem, 0, 0);
diff --git a/backends/platform/android/jni-android.h b/backends/platform/android/jni-android.h
index 3ceb3f76f04..d5d55b3a172 100644
--- a/backends/platform/android/jni-android.h
+++ b/backends/platform/android/jni-android.h
@@ -44,6 +44,8 @@ private:
 	virtual ~JNI();
 
 public:
+	static bool assets_updated;
+
 	static bool pause;
 	static sem_t pause_sem;
 
@@ -183,7 +185,8 @@ private:
 	static void create(JNIEnv *env, jobject self, jobject asset_manager,
 						jobject egl, jobject egl_display,
 						jobject at, jint audio_sample_rate,
-						jint audio_buffer_size);
+						jint audio_buffer_size,
+						jboolean assets_updated_);
 	static void destroy(JNIEnv *env, jobject self);
 
 	static void setSurface(JNIEnv *env, jobject self, jint width, jint height, jint bpp);
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
index ced347e1ee3..a21af60e1d6 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
@@ -44,14 +44,16 @@ public abstract class ScummVM implements SurfaceHolder.Callback,
 	private int _sample_rate = 0;
 	private int _buffer_size = 0;
 
+	private boolean _assetsUpdated;
 	private String[] _args;
 
 	private native void create(AssetManager asset_manager,
 	                           EGL10 egl,
-							   EGLDisplay egl_display,
+	                           EGLDisplay egl_display,
 	                           AudioTrack audio_track,
-							   int sample_rate,
-							   int buffer_size);
+	                           int sample_rate,
+	                           int buffer_size,
+	                           boolean assetsUpdated);
 	private native void destroy();
 	private native void setSurface(int width, int height, int bpp);
 	private native int main(String[] args);
@@ -151,6 +153,10 @@ public abstract class ScummVM implements SurfaceHolder.Callback,
 		setSurface(0, 0, 0);
 	}
 
+	final public void setAssetsUpdated(boolean assetsUpdated) {
+		_assetsUpdated = assetsUpdated;
+	}
+
 	final public void setArgs(String[] args) {
 		_args = args;
 	}
@@ -173,7 +179,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback,
 		}
 
 		create(_asset_manager, _egl, _egl_display,
-				_audio_track, _sample_rate, _buffer_size);
+				_audio_track, _sample_rate, _buffer_size,
+				_assetsUpdated);
 
 		int res = main(_args);
 
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index 320b61ab43a..9b969bbe9cc 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -68,6 +68,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 	private ClipboardManager _clipboardManager;
 
 	private Version _currentScummVMVersion;
+	private boolean _assetsUpdated;
 	private File _configScummvmFile;
 	private File _logScummvmFile;
 	private File _actualScummVMDataDir;
@@ -1012,6 +1013,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			// in fact in all the cases where we return false, we also called finish()
 			return;
 		}
+		_scummvm.setAssetsUpdated(_assetsUpdated);
 
 		// We should have a valid path to a configuration file here
 
@@ -2147,6 +2149,8 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			return;
 		}
 
+		_assetsUpdated = true;
+
 		internalAppFolderCleanup(_actualScummVMDataDir);
 
 		AssetManager assetManager = getAssets();
@@ -2187,6 +2191,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 					equalsStreamToStream(new ByteArrayInputStream(newSums), oldStream)) {
 					// The files are identical: nothing to do
 					Log.d(ScummVM.LOG_TAG, "MD5SUMS is already up to date");
+					_assetsUpdated = false;
 					return;
 				}
 			} catch (IOException e) {


Commit: aef1690c1d115e3d15b043ab5ef61ff46aa7d531
    https://github.com/scummvm/scummvm/commit/aef1690c1d115e3d15b043ab5ef61ff46aa7d531
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2024-11-12T22:46:21+01:00

Commit Message:
ANDROID: Allow packagers to bundle games in the assets

They get copied on update and automatically added.
Removed games located in the assets are cleaned up too.

Changed paths:
    backends/platform/android/android.cpp
    backends/platform/android/android.h
    backends/platform/android/android.mk


diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 6a1521a66e4..ea26cfeaf77 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -74,14 +74,14 @@
 #include "backends/keymapper/keymapper-defaults.h"
 #include "backends/keymapper/standard-actions.h"
 
-#include "common/util.h"
-#include "common/textconsole.h"
-#include "common/rect.h"
-#include "common/queue.h"
-#include "common/mutex.h"
-#include "common/events.h"
 #include "common/config-manager.h"
+#include "common/events.h"
+#include "common/mutex.h"
+#include "common/queue.h"
+#include "common/textconsole.h"
 #include "common/translation.h"
+#include "common/util.h"
+
 #include "graphics/cursorman.h"
 
 const char *android_log_tag = "ScummVM";
@@ -587,6 +587,53 @@ void OSystem_Android::engineDone() {
 	JNI::setCurrentGame("");
 }
 
+void OSystem_Android::updateStartSettings(const Common::String &executable, Common::String &command, Common::StringMap &settings, Common::StringArray& additionalArgs) {
+	// We only try to detect bundled games only on an app version update
+	if (!JNI::assets_updated) {
+		return;
+	}
+
+	Common::Path gamesPath(JNI::getScummVMBasePath(), Common::Path::kNativeSeparator);
+	gamesPath.joinInPlace("assets/games");
+
+	// We need to init the ConfMan ourselves to cleanup outdated games
+	Common::SeekableReadStream *configStream = createConfigReadStream();
+	if (configStream) {
+		// The configuration file exists, we can load it and clean it
+		delete configStream;
+		ConfMan.loadDefaultConfigFile(Common::Path());
+
+		for (Common::ConfigManager::DomainMap::iterator it = ConfMan.beginGameDomains(), end = ConfMan.endGameDomains(); it != end; ++it) {
+			if (!it->_value.contains("path")) {
+				continue;
+			}
+			Common::Path path = Common::Path::fromConfig(it->_value.getVal("path"));
+			if (!path.isRelativeTo(gamesPath)) {
+				continue;
+			}
+			if (Common::FSNode(path).isDirectory()) {
+				continue;
+			}
+			LOGI("Cleanup up: %s, %s not found", it->_key.c_str(), path.toString().c_str());
+			// path is inside our assets games directory and doesn't exist anymore: cleanup
+			ConfMan.removeGameDomain(it->_key);
+		}
+		ConfMan.flushToDisk();
+	}
+
+	Common::FSNode node(gamesPath);
+	if (!node.exists() || !node.isDirectory() ) {
+		return;
+	}
+
+	// As this detection happens only once per version upgrade, ignore command and override it
+	LOGD("Searching games");
+	command = "add";
+	settings["path"] = gamesPath.toConfig();
+	settings["recursive"] = "true";
+	settings["exit"] = "false";
+}
+
 void OSystem_Android::updateOnScreenControls() {
 	int enableMask = SHOW_ON_SCREEN_ALL;
 	if (!ConfMan.getBool("onscreen_control")) {
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 4c89a514a3c..6e277a11073 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -215,6 +215,8 @@ public:
 	void engineInit() override;
 	void engineDone() override;
 
+	void updateStartSettings(const Common::String &executable, Common::String &command, Common::StringMap &startSettings, Common::StringArray& additionalArgs) override;
+
 	bool hasFeature(OSystem::Feature f) override;
 	void setFeatureState(OSystem::Feature f, bool enable) override;
 	bool getFeatureState(OSystem::Feature f) override;
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index 62ae69793d1..d9e50135a6f 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -51,6 +51,10 @@ $(PATH_BUILD_ASSETS)/MD5SUMS: $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DI
 ifneq ($(DIST_FILES_SHADERS),)
 	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/shaders
 	$(INSTALL) -c -m 644 $(DIST_FILES_SHADERS) $(PATH_BUILD_ASSETS)/assets/shaders
+endif
+ifneq ($(GAMES_BUNDLE_DIRECTORY),)
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/assets/games
+	$(CP) -r $(GAMES_BUNDLE_DIRECTORY)/. $(PATH_BUILD_ASSETS)/assets/games/
 endif
 	(cd $(PATH_BUILD_ASSETS)/ && find assets -type f | sort | xargs md5sum) > $@
 




More information about the Scummvm-git-logs mailing list