From a56ee1a62e0781df7eefa4a0408a3d84d5a2b807 Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Sat, 10 Jun 2023 14:18:27 -0400 Subject: [PATCH] Android: Convert GameFile to Kotlin --- .../dolphinemu/adapters/GameAdapter.kt | 8 +- .../dolphinemu/adapters/GameRowPresenter.kt | 6 +- .../dolphinemu/dialogs/GameDetailsDialog.kt | 50 ++++++------ .../dolphinemu/fragments/ConvertFragment.kt | 22 ++++-- .../dolphinemu/dolphinemu/model/GameFile.java | 78 ------------------- .../dolphinemu/dolphinemu/model/GameFile.kt | 69 ++++++++++++++++ .../dolphinemu/utils/CoverHelper.kt | 6 +- Source/Android/jni/AndroidCommon/IDCache.cpp | 2 +- 8 files changed, 120 insertions(+), 121 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.kt index 103ba4a318..520c96d812 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.kt @@ -61,12 +61,12 @@ class GameAdapter(private val mActivity: FragmentActivity) : RecyclerView.Adapte holder.apply { if (BooleanSetting.MAIN_SHOW_GAME_TITLES.boolean) { - binding.textGameTitle.text = gameFile.title + binding.textGameTitle.text = gameFile.getTitle() binding.textGameTitle.visibility = View.VISIBLE binding.textGameTitleInner.visibility = View.GONE binding.textGameCaption.visibility = View.VISIBLE } else { - binding.textGameTitleInner.text = gameFile.title + binding.textGameTitleInner.text = gameFile.getTitle() binding.textGameTitleInner.visibility = View.VISIBLE binding.textGameTitle.visibility = View.GONE binding.textGameCaption.visibility = View.GONE @@ -94,9 +94,9 @@ class GameAdapter(private val mActivity: FragmentActivity) : RecyclerView.Adapte holder.apply { if (GameFileCacheManager.findSecondDisc(gameFile) != null) { binding.textGameCaption.text = - context.getString(R.string.disc_number, gameFile.discNumber + 1) + context.getString(R.string.disc_number, gameFile.getDiscNumber() + 1) } else { - binding.textGameCaption.text = gameFile.company + binding.textGameCaption.text = gameFile.getCompany() } holder.gameFile = gameFile binding.root.onFocusChangeListener = diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.kt index c23b4b3e14..b355dc8f6d 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.kt @@ -48,7 +48,7 @@ class GameRowPresenter(private val mActivity: FragmentActivity) : Presenter() { holder.apply { imageScreenshot.setImageDrawable(null) - cardParent.titleText = gameFile.title + cardParent.titleText = gameFile.getTitle() holder.gameFile = gameFile // Set the background color of the card @@ -64,9 +64,9 @@ class GameRowPresenter(private val mActivity: FragmentActivity) : Presenter() { if (GameFileCacheManager.findSecondDisc(gameFile) != null) { holder.cardParent.contentText = - context.getString(R.string.disc_number, gameFile.discNumber + 1) + context.getString(R.string.disc_number, gameFile.getDiscNumber() + 1) } else { - holder.cardParent.contentText = gameFile.company + holder.cardParent.contentText = gameFile.getCompany() } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt index 83d69ebbb4..53b1467bbc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt @@ -25,8 +25,8 @@ class GameDetailsDialog : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val gameFile = GameFileCacheManager.addOrGet(requireArguments().getString(ARG_GAME_PATH)) - val country = resources.getStringArray(R.array.countryNames)[gameFile.country] - val fileSize = NativeLibrary.FormatSize(gameFile.fileSize, 2) + val country = resources.getStringArray(R.array.countryNames)[gameFile.getCountry()] + val fileSize = NativeLibrary.FormatSize(gameFile.getFileSize(), 2) // TODO: Remove dialog_game_details_tv if we switch to an AppCompatActivity for leanback val binding: DialogGameDetailsBinding @@ -35,16 +35,16 @@ class GameDetailsDialog : DialogFragment() { if (requireActivity() is AppCompatActivity) { binding = DialogGameDetailsBinding.inflate(layoutInflater) binding.apply { - textGameTitle.text = gameFile.title - textDescription.text = gameFile.description - if (gameFile.description.isEmpty()) { + textGameTitle.text = gameFile.getTitle() + textDescription.text = gameFile.getDescription() + if (gameFile.getDescription().isEmpty()) { textDescription.visibility = View.GONE } textCountry.text = country - textCompany.text = gameFile.company - textGameId.text = gameFile.gameId - textRevision.text = gameFile.revision.toString() + textCompany.text = gameFile.getCompany() + textGameId.text = gameFile.getGameId() + textRevision.text = gameFile.getRevision().toString() if (!gameFile.shouldShowFileFormatDetails()) { labelFileFormat.setText(R.string.game_details_file_size) @@ -55,19 +55,19 @@ class GameDetailsDialog : DialogFragment() { labelBlockSize.visibility = View.GONE textBlockSize.visibility = View.GONE } else { - val blockSize = gameFile.blockSize - val compression = gameFile.compressionMethod + val blockSize = gameFile.getBlockSize() + val compression = gameFile.getCompressionMethod() textFileFormat.text = resources.getString( R.string.game_details_size_and_format, - gameFile.fileFormatName, + gameFile.getFileFormatName(), fileSize ) if (compression.isEmpty()) { textCompression.setText(R.string.game_details_no_compression) } else { - textCompression.text = gameFile.compressionMethod + textCompression.text = gameFile.getCompressionMethod() } if (blockSize > 0) { @@ -87,16 +87,16 @@ class GameDetailsDialog : DialogFragment() { } else { tvBinding = DialogGameDetailsTvBinding.inflate(layoutInflater) tvBinding.apply { - textGameTitle.text = gameFile.title - textDescription.text = gameFile.description - if (gameFile.description.isEmpty()) { + textGameTitle.text = gameFile.getTitle() + textDescription.text = gameFile.getDescription() + if (gameFile.getDescription().isEmpty()) { tvBinding.textDescription.visibility = View.GONE } textCountry.text = country - textCompany.text = gameFile.company - textGameId.text = gameFile.gameId - textRevision.text = gameFile.revision.toString() + textCompany.text = gameFile.getCompany() + textGameId.text = gameFile.getGameId() + textRevision.text = gameFile.getRevision().toString() if (!gameFile.shouldShowFileFormatDetails()) { labelFileFormat.setText(R.string.game_details_file_size) @@ -107,19 +107,19 @@ class GameDetailsDialog : DialogFragment() { labelBlockSize.visibility = View.GONE textBlockSize.visibility = View.GONE } else { - val blockSize = gameFile.blockSize - val compression = gameFile.compressionMethod + val blockSize = gameFile.getBlockSize() + val compression = gameFile.getCompressionMethod() textFileFormat.text = resources.getString( R.string.game_details_size_and_format, - gameFile.fileFormatName, + gameFile.getFileFormatName(), fileSize ) if (compression.isEmpty()) { textCompression.setText(R.string.game_details_no_compression) } else { - textCompression.text = gameFile.compressionMethod + textCompression.text = gameFile.getCompressionMethod() } if (blockSize > 0) { @@ -141,9 +141,9 @@ class GameDetailsDialog : DialogFragment() { } private suspend fun loadGameBanner(imageView: ImageView, gameFile: GameFile) { - val vector = gameFile.banner - val width = gameFile.bannerWidth - val height = gameFile.bannerHeight + val vector = gameFile.getBanner() + val width = gameFile.getBannerWidth() + val height = gameFile.getBannerHeight() imageView.scaleType = ImageView.ScaleType.FIT_CENTER val request = ImageRequest.Builder(imageView.context) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.kt index 01a5d97743..0f5760a210 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/ConvertFragment.kt @@ -210,7 +210,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { R.array.convertFormatValues, format ) - if (gameFile.blobType == BLOB_TYPE_ISO) { + if (gameFile.getBlobType() == BLOB_TYPE_ISO) { setDropdownSelection( binding.dropdownFormat, format, @@ -240,6 +240,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownBlockSize.adapter.getItem(0).toString(), false ) } + BLOB_TYPE_WIA -> { populateDropdown( binding.blockSize, @@ -253,6 +254,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownBlockSize.adapter.getItem(0).toString(), false ) } + BLOB_TYPE_RVZ -> { populateDropdown( binding.blockSize, @@ -266,6 +268,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownBlockSize.adapter.getItem(2).toString(), false ) } + else -> clearDropdown(binding.blockSize, binding.dropdownBlockSize, blockSize) } } @@ -285,6 +288,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownCompression.adapter.getItem(0).toString(), false ) } + BLOB_TYPE_WIA -> { populateDropdown( binding.compression, @@ -298,6 +302,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownCompression.adapter.getItem(0).toString(), false ) } + BLOB_TYPE_RVZ -> { populateDropdown( binding.compression, @@ -311,6 +316,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { binding.dropdownCompression.adapter.getItem(4).toString(), false ) } + else -> clearDropdown( binding.compression, binding.dropdownCompression, @@ -336,6 +342,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { ).toString(), false ) } + COMPRESSION_ZSTD -> { // TODO: Query DiscIO for the supported compression levels, like we do in DolphinQt? populateDropdown( @@ -352,6 +359,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { ).toString(), false ) } + else -> clearDropdown( binding.compressionLevel, binding.dropdownCompressionLevel, @@ -362,7 +370,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { private fun populateRemoveJunkData() { val scrubbingAllowed = format.getValue(requireContext()) != BLOB_TYPE_RVZ && - !gameFile.isDatelDisc + !gameFile.isDatelDisc() binding.switchRemoveJunkData.isEnabled = scrubbingAllowed if (!scrubbingAllowed) binding.switchRemoveJunkData.isChecked = false @@ -374,11 +382,11 @@ class ConvertFragment : Fragment(), View.OnClickListener { var action = Runnable { showSavePrompt() } - if (gameFile.isNKit) { + if (gameFile.isNKit()) { action = addAreYouSureDialog(action, R.string.convert_warning_nkit) } - if (!scrub && format == BLOB_TYPE_GCZ && !gameFile.isDatelDisc && gameFile.platform == Platform.WII.toInt()) { + if (!scrub && format == BLOB_TYPE_GCZ && !gameFile.isDatelDisc() && gameFile.getPlatform() == Platform.WII.toInt()) { action = addAreYouSureDialog(action, R.string.convert_warning_gcz) } @@ -401,7 +409,7 @@ class ConvertFragment : Fragment(), View.OnClickListener { } private fun showSavePrompt() { - val originalPath = gameFile.path + val originalPath = gameFile.getPath() val filename = StringBuilder(File(originalPath).name) val dotIndex = filename.lastIndexOf(".") @@ -449,9 +457,9 @@ class ConvertFragment : Fragment(), View.OnClickListener { thread = Thread { val success = NativeLibrary.ConvertDiscImage( - gameFile.path, + gameFile.getPath(), outPath, - gameFile.platform, + gameFile.getPlatform(), format.getValue(context), blockSize.getValueOr(context, 0), compression.getValueOr(context, 0), diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java deleted file mode 100644 index 26f4c169ce..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.model; - -import androidx.annotation.Keep; - -public class GameFile -{ - public static int REGION_NTSC_J = 0; - public static int REGION_NTSC_U = 1; - public static int REGION_PAL = 2; - public static int REGION_NTSC_K = 4; - - @Keep - private long mPointer; - - @Keep - private GameFile(long pointer) - { - mPointer = pointer; - } - - public native static GameFile parse(String path); - - @Override - public native void finalize(); - - public native int getPlatform(); - - public native String getTitle(); - - public native String getDescription(); - - public native String getCompany(); - - public native int getCountry(); - - public native int getRegion(); - - public native String getPath(); - - public native String getGameId(); - - public native String getGameTdbId(); - - public native int getDiscNumber(); - - public native int getRevision(); - - public native int getBlobType(); - - public native String getFileFormatName(); - - public native long getBlockSize(); - - public native String getCompressionMethod(); - - public native boolean shouldShowFileFormatDetails(); - - public native boolean shouldAllowConversion(); - - public native long getFileSize(); - - public native boolean isDatelDisc(); - - public native boolean isNKit(); - - public native int[] getBanner(); - - public native int getBannerWidth(); - - public native int getBannerHeight(); - - public String getCustomCoverPath() - { - return getPath().substring(0, getPath().lastIndexOf(".")) + ".cover.png"; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt new file mode 100644 index 0000000000..347433f552 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.model + +import androidx.annotation.Keep + +@Keep +class GameFile private constructor(private val pointer: Long) { + external fun finalize() + + external fun getPlatform(): Int + + external fun getTitle(): String + + external fun getDescription(): String + + external fun getCompany(): String + + external fun getCountry(): Int + + external fun getRegion(): Int + + external fun getPath(): String + + external fun getGameId(): String + + external fun getGameTdbId(): String + + external fun getDiscNumber(): Int + + external fun getRevision(): Int + + external fun getBlobType(): Int + + external fun getFileFormatName(): String + + external fun getBlockSize(): Long + + external fun getCompressionMethod(): String + + external fun shouldShowFileFormatDetails(): Boolean + + external fun shouldAllowConversion(): Boolean + + external fun getFileSize(): Long + + external fun isDatelDisc(): Boolean + + external fun isNKit(): Boolean + + external fun getBanner(): IntArray + + external fun getBannerWidth(): Int + + external fun getBannerHeight(): Int + + val customCoverPath: String + get() = "${getPath().substring(0, getPath().lastIndexOf("."))}.cover.png" + + companion object { + var REGION_NTSC_J = 0 + var REGION_NTSC_U = 1 + var REGION_PAL = 2 + var REGION_NTSC_K = 4 + + @JvmStatic + external fun parse(path: String): GameFile? + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CoverHelper.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CoverHelper.kt index 9359d38eb3..172be697e9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CoverHelper.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CoverHelper.kt @@ -8,16 +8,16 @@ object CoverHelper { @JvmStatic fun buildGameTDBUrl(game: GameFile, region: String?): String { val baseUrl = "https://art.gametdb.com/wii/cover/%s/%s.png" - return String.format(baseUrl, region, game.gameTdbId) + return String.format(baseUrl, region, game.getGameTdbId()) } @JvmStatic fun getRegion(game: GameFile): String { - val region: String = when (game.region) { + val region: String = when (game.getRegion()) { GameFile.REGION_NTSC_J -> "JA" GameFile.REGION_NTSC_U -> "US" GameFile.REGION_NTSC_K -> "KO" - GameFile.REGION_PAL -> when (game.country) { + GameFile.REGION_PAL -> when (game.getCountry()) { 3 -> "AU" // Australia 4 -> "FR" // France 5 -> "DE" // Germany diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp index e4cacaa462..2396f0960b 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.cpp +++ b/Source/Android/jni/AndroidCommon/IDCache.cpp @@ -563,7 +563,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile"); s_game_file_class = reinterpret_cast(env->NewGlobalRef(game_file_class)); - s_game_file_pointer = env->GetFieldID(game_file_class, "mPointer", "J"); + s_game_file_pointer = env->GetFieldID(game_file_class, "pointer", "J"); s_game_file_constructor = env->GetMethodID(game_file_class, "", "(J)V"); env->DeleteLocalRef(game_file_class);