diff --git a/app/build.gradle b/app/build.gradle index d25d7b4..cebbdd7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.zane.smapiinstaller" minSdkVersion 19 targetSdkVersion 28 - versionCode 46 - versionName "1.5.5" + versionCode 48 + versionName "1.5.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true diff --git a/app/src/main/assets/apk/StardewModdingAPI.dll b/app/src/main/assets/apk/StardewModdingAPI.dll index b4a130c..ec7afb8 100644 Binary files a/app/src/main/assets/apk/StardewModdingAPI.dll and b/app/src/main/assets/apk/StardewModdingAPI.dll differ diff --git a/app/src/main/assets/downloadable_content_list.json b/app/src/main/assets/downloadable_content_list.json index 7409593..83fd3cb 100644 --- a/app/src/main/assets/downloadable_content_list.json +++ b/app/src/main/assets/downloadable_content_list.json @@ -1,5 +1,5 @@ { - "version": 21, + "version": 23, "contents": [ { "type": "COMPAT", @@ -14,16 +14,16 @@ "name": "SMAPI for Galaxy Store", "assetPath": "compat/samsung_138/", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip", - "hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626" + "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip", + "hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc" }, { "type": "COMPAT", "name": "SMAPI for Amazon Store", "assetPath": "compat/amazon_138/", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip", - "hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d" + "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip", + "hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb" }, { "type": "LOCALE", diff --git a/app/src/main/assets/downloadable_content_list.json.en b/app/src/main/assets/downloadable_content_list.json.en index 7409593..83fd3cb 100644 --- a/app/src/main/assets/downloadable_content_list.json.en +++ b/app/src/main/assets/downloadable_content_list.json.en @@ -1,5 +1,5 @@ { - "version": 21, + "version": 23, "contents": [ { "type": "COMPAT", @@ -14,16 +14,16 @@ "name": "SMAPI for Galaxy Store", "assetPath": "compat/samsung_138/", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip", - "hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626" + "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip", + "hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc" }, { "type": "COMPAT", "name": "SMAPI for Amazon Store", "assetPath": "compat/amazon_138/", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip", - "hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d" + "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip", + "hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb" }, { "type": "LOCALE", diff --git a/app/src/main/assets/downloadable_content_list.json.in b/app/src/main/assets/downloadable_content_list.json.in index 6d546ec..92d9352 100644 --- a/app/src/main/assets/downloadable_content_list.json.in +++ b/app/src/main/assets/downloadable_content_list.json.in @@ -1,5 +1,5 @@ { - "version": 21, + "version": 23, "contents": [ { "type": "COMPAT", @@ -14,16 +14,16 @@ "name": "SMAPI untuk Galaxy Store", "assetPath": "compat/samsung_138/", "description": "Paket kompatibilitas SMAPI untuk versi 1.4.4.138 - terbaru, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip", - "hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626" + "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip", + "hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc" }, { "type": "COMPAT", "name": "SMAPI untuk Amazon Store", "assetPath": "compat/amazon_138/", "description": "Paket kompatibilitas SMAPI untuk versi 1.4.4.138 - terbaru, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip", - "hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d" + "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip", + "hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb" }, { "type": "LOCAL", diff --git a/app/src/main/assets/downloadable_content_list.json.zh b/app/src/main/assets/downloadable_content_list.json.zh index 4384760..254ca54 100644 --- a/app/src/main/assets/downloadable_content_list.json.zh +++ b/app/src/main/assets/downloadable_content_list.json.zh @@ -1,5 +1,5 @@ { - "version": 21, + "version": 23, "contents": [ { "type": "COMPAT", @@ -14,16 +14,16 @@ "name": "SMAPI三星商店兼容包", "assetPath": "compat/samsung_138/", "description": "SMAPI三星商店兼容包, 适用版本1.4.4.138至今, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip", - "hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626" + "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip", + "hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc" }, { "type": "COMPAT", "name": "SMAPI亚马逊商店兼容包", "assetPath": "compat/amazon_138/", "description": "SMAPI亚马逊商店兼容包, 适用版本1.4.4.138至今, SMAPI 3.6.1", - "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip", - "hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d" + "url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip", + "hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb" }, { "type": "LOCALE", diff --git a/app/src/main/java/com/zane/smapiinstaller/MainActivity.java b/app/src/main/java/com/zane/smapiinstaller/MainActivity.java index 513f319..dffd465 100644 --- a/app/src/main/java/com/zane/smapiinstaller/MainActivity.java +++ b/app/src/main/java/com/zane/smapiinstaller/MainActivity.java @@ -26,6 +26,7 @@ import com.zane.smapiinstaller.constant.DialogAction; import com.zane.smapiinstaller.dto.AppUpdateCheckResultDto; import com.zane.smapiinstaller.entity.AppConfig; import com.zane.smapiinstaller.entity.FrameworkConfig; +import com.zane.smapiinstaller.logic.ActivityResultHandler; import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.ConfigManager; import com.zane.smapiinstaller.logic.GameLauncher; @@ -42,6 +43,7 @@ import java.io.File; import java.util.Locale; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; @@ -97,6 +99,12 @@ public class MainActivity extends AppCompatActivity { } } + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + ActivityResultHandler.triggerListener(requestCode, resultCode, data); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/ActivityResultHandler.java b/app/src/main/java/com/zane/smapiinstaller/logic/ActivityResultHandler.java new file mode 100644 index 0000000..a6d9a05 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/logic/ActivityResultHandler.java @@ -0,0 +1,24 @@ +package com.zane.smapiinstaller.logic; + +import android.content.Intent; + +import java.util.concurrent.ConcurrentHashMap; + +import java9.util.function.BiConsumer; + +public class ActivityResultHandler { + public static int REQUEST_CODE_APP_INSTALL = 1001; + + public static ConcurrentHashMap> listenerMap = new ConcurrentHashMap<>(); + + public static void registerListener(int requestCode, BiConsumer listener) { + listenerMap.put(requestCode, listener); + } + + public static void triggerListener(int requestCode, int resultCode, Intent data) { + BiConsumer biConsumer = listenerMap.get(requestCode); + if(biConsumer != null) { + biConsumer.accept(resultCode, data); + } + } +} diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/ApkPatcher.java b/app/src/main/java/com/zane/smapiinstaller/logic/ApkPatcher.java index 7e7f84d..689a1e3 100644 --- a/app/src/main/java/com/zane/smapiinstaller/logic/ApkPatcher.java +++ b/app/src/main/java/com/zane/smapiinstaller/logic/ApkPatcher.java @@ -8,6 +8,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.provider.Settings; import android.util.Log; import com.android.apksig.ApkSigner; @@ -19,11 +20,14 @@ import com.google.common.collect.Iterables; import com.google.common.hash.Hashing; import com.google.common.io.Files; import com.zane.smapiinstaller.BuildConfig; +import com.zane.smapiinstaller.MainActivity; import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.constant.Constants; +import com.zane.smapiinstaller.constant.DialogAction; import com.zane.smapiinstaller.constant.ManifestPatchConstants; import com.zane.smapiinstaller.entity.ApkFilesManifest; import com.zane.smapiinstaller.entity.ManifestEntry; +import com.zane.smapiinstaller.utils.DialogUtils; import com.zane.smapiinstaller.utils.FileUtils; import com.zane.smapiinstaller.utils.ZipUtils; @@ -126,13 +130,12 @@ public class ApkPatcher { return distFile.getAbsolutePath(); } else if (advancedStage == 1) { File contentFolder = new File(externalFilesDir.getAbsolutePath() + "/StardewValley/Content"); - if(contentFolder.exists()) { - if(!contentFolder.isDirectory()) { + if (contentFolder.exists()) { + if (!contentFolder.isDirectory()) { errorMessage.set(context.getString(R.string.error_directory_exists_with_same_filename, contentFolder.getAbsolutePath())); return null; } - } - else { + } else { extract(0); } ZipUtils.removeEntries(sourceDir, "assets/Content", distFile.getAbsolutePath(), (progress) -> emitProgress((int) (progress * 0.05))); @@ -189,7 +192,7 @@ public class ApkPatcher { List manifestEntries = apkFilesManifest.getManifestEntries(); errorMessage.set(null); List entries = StreamSupport.stream(manifestEntries).map(entry -> { - if(entry.isAdvanced() && !advanced) { + if (entry.isAdvanced() && !advanced) { return null; } byte[] bytes; @@ -209,11 +212,9 @@ public class ApkPatcher { errorMessage.set(StringUtils.stripToEmpty(errorMessage.get()) + "\n" + errorMsg); return null; } - } - else if(StringUtils.equals(crc, entry.getPatchedCrc())){ + } else if (StringUtils.equals(crc, entry.getPatchedCrc())) { bytes = originBytes; - } - else { + } else { String errorMsg = context.getString(R.string.error_patch_crc_incorrect, entry.getTargetPath(), crc); errorMessage.set(StringUtils.stripToEmpty(errorMessage.get()) + "\n" + errorMsg); return null; @@ -402,6 +403,20 @@ public class ApkPatcher { * @param apkPath 安装包路径 */ public void install(String apkPath) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + boolean haveInstallPermission = context.getPackageManager().canRequestPackageInstalls(); + if (!haveInstallPermission) { + DialogUtils.showConfirmDialog(MainActivity.instance, R.string.confirm, R.string.request_unknown_source_permission, ((dialog, dialogAction) -> { + if(dialogAction == DialogAction.POSITIVE) { + Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); + ActivityResultHandler.registerListener(ActivityResultHandler.REQUEST_CODE_APP_INSTALL, (resultCode, data) -> this.install(apkPath)); + MainActivity.instance.startActivityForResult(intent, ActivityResultHandler.REQUEST_CODE_APP_INSTALL); + } + })); + return; + } + } + Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(fromFile(new File(apkPath)), "application/vnd.android.package-archive"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); diff --git a/app/src/main/java/com/zane/smapiinstaller/ui/config/ModManifestAdapter.java b/app/src/main/java/com/zane/smapiinstaller/ui/config/ModManifestAdapter.java index b0b2391..5e4ae34 100644 --- a/app/src/main/java/com/zane/smapiinstaller/ui/config/ModManifestAdapter.java +++ b/app/src/main/java/com/zane/smapiinstaller/ui/config/ModManifestAdapter.java @@ -7,6 +7,7 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; +import com.zane.smapiinstaller.MobileNavigationDirections; import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.DialogAction; @@ -175,7 +176,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter { + MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(null, message, null).positiveButton(R.string.ok, null, null); + DialogUtils.setCurrentDialog(materialDialog); + materialDialog.show(); + }); + } /** * 显示警告对话框 @@ -83,6 +90,14 @@ public class DialogUtils { }); } + public static void showAlertDialog(Activity context, int title, int message) { + CommonLogic.runOnUiThread(context, (activity) -> { + MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.ok, null, null); + DialogUtils.setCurrentDialog(materialDialog); + materialDialog.show(); + }); + } + /** * 显示确认对话框 * @@ -104,6 +119,19 @@ public class DialogUtils { materialDialog.show(); }); } + public static void showConfirmDialog(Activity context, int title, int message, BiConsumer callback) { + CommonLogic.runOnUiThread(context, (activity) -> { + MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.confirm, null, dialog -> { + callback.accept(dialog, DialogAction.POSITIVE); + return null; + }).negativeButton(R.string.cancel, null, dialog -> { + callback.accept(dialog, DialogAction.NEGATIVE); + return null; + }); + DialogUtils.setCurrentDialog(materialDialog); + materialDialog.show(); + }); + } /** * 显示确认对话框 @@ -178,6 +206,20 @@ public class DialogUtils { }); return reference; } + public static AtomicReference showProgressDialog(Activity context, int title, String message) { + AtomicReference reference = new AtomicReference<>(); + CommonLogic.runOnUiThread(context, (activity) -> { + ProgressDialog dialog = new ProgressDialog(activity); + DialogUtils.setCurrentDialog(dialog); + dialog.setMessage(message); + dialog.setCancelable(false); + dialog.setMax(100); + dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + dialog.show(); + reference.set(dialog); + }); + return reference; + } /** * 解散指定对话框 @@ -221,6 +263,20 @@ public class DialogUtils { } } + public static void dismissDialog(Activity activity, ProgressDialog dialog) { + if (activity != null && !activity.isFinishing()) { + activity.runOnUiThread(() -> { + if (dialog != null) { + try { + dialog.dismiss(); + } catch (Exception e) { + Crashes.trackError(e); + } + } + }); + } + } + /** * 解散当前对话框 */ diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index b3bbb7b..48e9ceb 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -31,24 +31,12 @@ android:name="com.zane.smapiinstaller.ui.config.ConfigFragment" android:label="@string/menu_config" tools:layout="@layout/fragment_config"> - - - - - - - - - + + + + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 6e6f10b..43f6e36 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -81,4 +81,5 @@ %1$s不是一個文件夾, 請手動刪除該文件 增量更新%1$s失敗: CRC (%2$s)) 多線程重寫 + 需要开启未知源权限以安装Mod框架,是否前往设置开启? diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 4cc8212..a6bd235 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -81,4 +81,5 @@ %1$s不是一个文件夹, 请手动删除该文件 增量更新%1$s失败: CRC (%2$s)) 多线程重写 + 需要开启未知源权限以安装Mod框架,是否前往设置开启? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a125fee..6308482 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,4 +85,5 @@ %1$s is not a directory, please delete it manually. Patch %1$s failed: CRC (%2$s)) Rewrite in Parallel + Needs to switch unknown source permission on to install mod framework, open settings?