Dependency check logic, some code refactor
This commit is contained in:
parent
659c5b065a
commit
7fd7e00511
|
@ -9,7 +9,7 @@ android {
|
||||||
applicationId "com.zane.smapiinstaller"
|
applicationId "com.zane.smapiinstaller"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 5
|
versionCode 6
|
||||||
versionName "1.1.2"
|
versionName "1.1.2"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 2,
|
"version": 3,
|
||||||
"contents": [
|
"contents": [
|
||||||
{
|
{
|
||||||
"type": "COMPAT",
|
"type": "COMPAT",
|
||||||
|
@ -11,10 +11,10 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "LOCALE",
|
"type": "LOCALE",
|
||||||
"name": "中文汉化v2.4",
|
"name": "中文汉化v2.5",
|
||||||
"description": "简体中文语言包,感谢Wabi-Sabi提供",
|
"description": "简体中文语言包,感谢Wabi-Sabi提供",
|
||||||
"url": "http://zaneyork.cn/download/locale/locale_pack_zh_2.4.zip",
|
"url": "http://zaneyork.cn/download/locale/locale_pack_zh_2.5.zip",
|
||||||
"hash": "59be19240160de61046f05619f3e448d180137e0989feb537e392a014588615f"
|
"hash": "64eb016f22ecb7ba54318e55e11ddeb9fc3d634187d90fad1df5501113881382"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package com.zane.smapiinstaller.entity;
|
package com.zane.smapiinstaller.entity;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -7,6 +9,8 @@ public class ModManifestEntry {
|
||||||
private String assetPath;
|
private String assetPath;
|
||||||
private String Name;
|
private String Name;
|
||||||
private String UniqueID;
|
private String UniqueID;
|
||||||
|
private String Version;
|
||||||
private String Description;
|
private String Description;
|
||||||
|
private Set<ModManifestEntry> Dependencies;
|
||||||
private ModManifestEntry ContentPackFor;
|
private ModManifestEntry ContentPackFor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.zane.smapiinstaller.R;
|
||||||
import com.zane.smapiinstaller.constant.Constants;
|
import com.zane.smapiinstaller.constant.Constants;
|
||||||
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
||||||
import com.zane.smapiinstaller.entity.ManifestEntry;
|
import com.zane.smapiinstaller.entity.ManifestEntry;
|
||||||
|
import com.zane.smapiinstaller.utils.FileUtils;
|
||||||
|
|
||||||
import net.fornwall.apksigner.KeyStoreFileManager;
|
import net.fornwall.apksigner.KeyStoreFileManager;
|
||||||
import net.fornwall.apksigner.ZipSigner;
|
import net.fornwall.apksigner.ZipSigner;
|
||||||
|
@ -58,7 +59,7 @@ public class ApkPatcher {
|
||||||
|
|
||||||
public String extract() {
|
public String extract() {
|
||||||
PackageManager packageManager = context.getPackageManager();
|
PackageManager packageManager = context.getPackageManager();
|
||||||
List<String> packageNames = CommonLogic.getAssetJson(context, "package_names.json", new TypeToken<List<String>>() {
|
List<String> packageNames = FileUtils.getAssetJson(context, "package_names.json", new TypeToken<List<String>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
if (packageNames == null) {
|
if (packageNames == null) {
|
||||||
errorMessage.set(context.getString(R.string.error_game_not_found));
|
errorMessage.set(context.getString(R.string.error_game_not_found));
|
||||||
|
@ -115,10 +116,10 @@ public class ApkPatcher {
|
||||||
List<ManifestEntry> manifestEntries = apkFilesManifest.getManifestEntries();
|
List<ManifestEntry> manifestEntries = apkFilesManifest.getManifestEntries();
|
||||||
for (ManifestEntry entry : manifestEntries) {
|
for (ManifestEntry entry : manifestEntries) {
|
||||||
if(entry.isExternal()) {
|
if(entry.isExternal()) {
|
||||||
zipEntrySourceList.add(new ByteSource(entry.getTargetPath(), CommonLogic.getAssetBytes(context, apkFilesManifest.getBasePath() + entry.getAssetPath()), entry.getCompression()));
|
zipEntrySourceList.add(new ByteSource(entry.getTargetPath(), FileUtils.getAssetBytes(context, apkFilesManifest.getBasePath() + entry.getAssetPath()), entry.getCompression()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
zipEntrySourceList.add(new ByteSource(entry.getTargetPath(), CommonLogic.getAssetBytes(context, entry.getAssetPath()), entry.getCompression()));
|
zipEntrySourceList.add(new ByteSource(entry.getTargetPath(), FileUtils.getAssetBytes(context, entry.getAssetPath()), entry.getCompression()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ZipUtil.addOrReplaceEntries(file, zipEntrySourceList.toArray(new ZipEntrySource[0]));
|
ZipUtil.addOrReplaceEntries(file, zipEntrySourceList.toArray(new ZipEntrySource[0]));
|
||||||
|
|
|
@ -12,29 +12,18 @@ import android.view.View;
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.hash.Hashing;
|
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.CharStreams;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.zane.smapiinstaller.R;
|
import com.zane.smapiinstaller.R;
|
||||||
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
||||||
import com.zane.smapiinstaller.entity.ManifestEntry;
|
import com.zane.smapiinstaller.entity.ManifestEntry;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
import org.zeroturnaround.zip.commons.FileUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -47,93 +36,6 @@ import pxb.android.axml.NodeVisitor;
|
||||||
|
|
||||||
public class CommonLogic {
|
public class CommonLogic {
|
||||||
|
|
||||||
public static String getFileText(File file) {
|
|
||||||
try {
|
|
||||||
InputStream inputStream = new FileInputStream(file);
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
|
||||||
return CharStreams.toString(reader);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream getLocalAsset(Context context, String filename) throws IOException {
|
|
||||||
File file = new File(context.getFilesDir(), filename);
|
|
||||||
if (file.exists()) {
|
|
||||||
return new FileInputStream(file);
|
|
||||||
}
|
|
||||||
return context.getAssets().open(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T getFileJson(File file, Type type) {
|
|
||||||
try {
|
|
||||||
InputStream inputStream = new FileInputStream(file);
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
|
||||||
return new Gson().fromJson(CharStreams.toString(reader), type);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T getFileJson(File file, Class<T> tClass) {
|
|
||||||
try {
|
|
||||||
InputStream inputStream = new FileInputStream(file);
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
|
||||||
return new Gson().fromJson(CharStreams.toString(reader), tClass);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeAssetJson(Context context, String filename, Object content) {
|
|
||||||
try {
|
|
||||||
String tmpFilename = filename + ".tmp";
|
|
||||||
File file = new File(context.getFilesDir(), tmpFilename);
|
|
||||||
FileOutputStream outputStream = new FileOutputStream(file);
|
|
||||||
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
|
|
||||||
writer.write(new Gson().toJson(content));
|
|
||||||
} finally {
|
|
||||||
FileUtils.moveFile(file, new File(context.getFilesDir(), filename));
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T getAssetJson(Context context, String filename, Class<T> tClass) {
|
|
||||||
try {
|
|
||||||
InputStream inputStream = getLocalAsset(context, filename);
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
|
||||||
return new Gson().fromJson(CharStreams.toString(reader), tClass);
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T getAssetJson(Context context, String filename, Type type) {
|
|
||||||
try {
|
|
||||||
InputStream inputStream = getLocalAsset(context, filename);
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
|
||||||
return new Gson().fromJson(CharStreams.toString(reader), type);
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] getAssetBytes(Context context, String filename) {
|
|
||||||
try {
|
|
||||||
try (InputStream inputStream = getLocalAsset(context, filename)) {
|
|
||||||
return ByteStreams.toByteArray(inputStream);
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setProgressDialogState(View view, MaterialDialog dialog, int message, int progress) {
|
public static void setProgressDialogState(View view, MaterialDialog dialog, int message, int progress) {
|
||||||
Activity activity = getActivityFromView(view);
|
Activity activity = getActivityFromView(view);
|
||||||
if (activity != null && !activity.isFinishing() && !dialog.isCancelled()) {
|
if (activity != null && !activity.isFinishing() && !dialog.isCancelled()) {
|
||||||
|
@ -202,15 +104,22 @@ public class CommonLogic {
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openUrl(Context context, String url) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setData(Uri.parse(url));
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<ApkFilesManifest> findAllApkFileManifest(Context context) {
|
public static List<ApkFilesManifest> findAllApkFileManifest(Context context) {
|
||||||
ApkFilesManifest apkFilesManifest = CommonLogic.getAssetJson(context, "apk_files_manifest.json", ApkFilesManifest.class);
|
ApkFilesManifest apkFilesManifest = com.zane.smapiinstaller.utils.FileUtils.getAssetJson(context, "apk_files_manifest.json", ApkFilesManifest.class);
|
||||||
ArrayList<ApkFilesManifest> apkFilesManifests = Lists.newArrayList(apkFilesManifest);
|
ArrayList<ApkFilesManifest> apkFilesManifests = Lists.newArrayList(apkFilesManifest);
|
||||||
File compatFolder = new File(context.getFilesDir(), "compat");
|
File compatFolder = new File(context.getFilesDir(), "compat");
|
||||||
if (compatFolder.exists()) {
|
if (compatFolder.exists()) {
|
||||||
for (File directory : compatFolder.listFiles(File::isDirectory)) {
|
for (File directory : compatFolder.listFiles(File::isDirectory)) {
|
||||||
File manifestFile = new File(directory, "apk_files_manifest.json");
|
File manifestFile = new File(directory, "apk_files_manifest.json");
|
||||||
if (manifestFile.exists()) {
|
if (manifestFile.exists()) {
|
||||||
ApkFilesManifest manifest = getFileJson(manifestFile, ApkFilesManifest.class);
|
ApkFilesManifest manifest = com.zane.smapiinstaller.utils.FileUtils.getFileJson(manifestFile, ApkFilesManifest.class);
|
||||||
if (manifest != null) {
|
if (manifest != null) {
|
||||||
apkFilesManifests.add(manifest);
|
apkFilesManifests.add(manifest);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +131,7 @@ public class CommonLogic {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean unpackSmapiFiles(Context context, String apkPath, boolean checkMod) {
|
public static boolean unpackSmapiFiles(Context context, String apkPath, boolean checkMod) {
|
||||||
List<ManifestEntry> manifestEntries = CommonLogic.getAssetJson(context, "smapi_files_manifest.json", new TypeToken<List<ManifestEntry>>() {
|
List<ManifestEntry> manifestEntries = com.zane.smapiinstaller.utils.FileUtils.getAssetJson(context, "smapi_files_manifest.json", new TypeToken<List<ManifestEntry>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
if (manifestEntries == null)
|
if (manifestEntries == null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -268,13 +177,6 @@ public class CommonLogic {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openUrl(Context context, String url) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setData(Uri.parse(url));
|
|
||||||
intent.setAction(Intent.ACTION_VIEW);
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] modifyManifest(byte[] bytes, Predicate<ManifestTagVisitor.AttrArgs> processLogic) throws IOException {
|
public static byte[] modifyManifest(byte[] bytes, Predicate<ManifestTagVisitor.AttrArgs> processLogic) throws IOException {
|
||||||
AxmlReader reader = new AxmlReader(bytes);
|
AxmlReader reader = new AxmlReader(bytes);
|
||||||
AxmlWriter writer = new AxmlWriter();
|
AxmlWriter writer = new AxmlWriter();
|
||||||
|
@ -288,24 +190,4 @@ public class CommonLogic {
|
||||||
return writer.toByteArray();
|
return writer.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toPrettyPath(String path) {
|
|
||||||
return StringUtils.removeStart(path, Environment.getExternalStorageDirectory().getAbsolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFileHash(Context context, String filename) {
|
|
||||||
try (InputStream inputStream = getLocalAsset(context, filename)) {
|
|
||||||
return Hashing.sha256().hashBytes(ByteStreams.toByteArray(inputStream)).toString();
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFileHash(File file) {
|
|
||||||
try (InputStream inputStream = new FileInputStream(file)) {
|
|
||||||
return Hashing.sha256().hashBytes(ByteStreams.toByteArray(inputStream)).toString();
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.lzy.okgo.callback.StringCallback;
|
||||||
import com.lzy.okgo.model.Response;
|
import com.lzy.okgo.model.Response;
|
||||||
import com.zane.smapiinstaller.constant.Constants;
|
import com.zane.smapiinstaller.constant.Constants;
|
||||||
import com.zane.smapiinstaller.entity.DownloadableContentList;
|
import com.zane.smapiinstaller.entity.DownloadableContentList;
|
||||||
|
import com.zane.smapiinstaller.utils.FileUtils;
|
||||||
|
|
||||||
public class DownloadabeContentManager {
|
public class DownloadabeContentManager {
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ public class DownloadabeContentManager {
|
||||||
|
|
||||||
public DownloadabeContentManager(View root) {
|
public DownloadabeContentManager(View root) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
downloadableContentList = CommonLogic.getAssetJson(root.getContext(), "downloadable_content_list.json", DownloadableContentList.class);
|
downloadableContentList = FileUtils.getAssetJson(root.getContext(), "downloadable_content_list.json", DownloadableContentList.class);
|
||||||
if(!updateChecked) {
|
if(!updateChecked) {
|
||||||
updateChecked = true;
|
updateChecked = true;
|
||||||
OkGo.<String>get(Constants.DLC_LIST_UPDATE_URL).execute(new StringCallback(){
|
OkGo.<String>get(Constants.DLC_LIST_UPDATE_URL).execute(new StringCallback(){
|
||||||
|
@ -29,7 +30,7 @@ public class DownloadabeContentManager {
|
||||||
public void onSuccess(Response<String> response) {
|
public void onSuccess(Response<String> response) {
|
||||||
DownloadableContentList content = new Gson().fromJson(response.body(), DownloadableContentList.class);
|
DownloadableContentList content = new Gson().fromJson(response.body(), DownloadableContentList.class);
|
||||||
if(downloadableContentList.getVersion() < content.getVersion()) {
|
if(downloadableContentList.getVersion() < content.getVersion()) {
|
||||||
CommonLogic.writeAssetJson(root.getContext(), "downloadable_content_list.json", content);
|
FileUtils.writeAssetJson(root.getContext(), "downloadable_content_list.json", content);
|
||||||
downloadableContentList = content;
|
downloadableContentList = content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ public class GameLauncher {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ModAssetsManager modAssetsManager = new ModAssetsManager(root);
|
ModAssetsManager modAssetsManager = new ModAssetsManager(root);
|
||||||
modAssetsManager.checkModEnvironment((isOk) -> {
|
modAssetsManager.checkModEnvironment((isConfirm) -> {
|
||||||
if(isOk) {
|
if(isConfirm) {
|
||||||
Intent intent = packageManager.getLaunchIntentForPackage(Constants.TARGET_PACKAGE_NAME);
|
Intent intent = packageManager.getLaunchIntentForPackage(Constants.TARGET_PACKAGE_NAME);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableListMultimap;
|
import com.google.common.collect.ImmutableListMultimap;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
import com.google.common.collect.Queues;
|
import com.google.common.collect.Queues;
|
||||||
|
@ -17,6 +18,8 @@ import com.google.gson.reflect.TypeToken;
|
||||||
import com.zane.smapiinstaller.R;
|
import com.zane.smapiinstaller.R;
|
||||||
import com.zane.smapiinstaller.constant.Constants;
|
import com.zane.smapiinstaller.constant.Constants;
|
||||||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||||
|
import com.zane.smapiinstaller.utils.FileUtils;
|
||||||
|
import com.zane.smapiinstaller.utils.VersionUtil;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
|
@ -44,48 +47,51 @@ public class ModAssetsManager {
|
||||||
files.add(new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH));
|
files.add(new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH));
|
||||||
do {
|
do {
|
||||||
File currentFile = files.poll();
|
File currentFile = files.poll();
|
||||||
if(currentFile != null && currentFile.exists()) {
|
if (currentFile != null && currentFile.exists()) {
|
||||||
boolean foundManifest = false;
|
boolean foundManifest = false;
|
||||||
for(File file : currentFile.listFiles(File::isFile)) {
|
for (File file : currentFile.listFiles(File::isFile)) {
|
||||||
if(StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
|
if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
|
||||||
ModManifestEntry manifest = CommonLogic.getFileJson(file, new TypeToken<ModManifestEntry>(){}.getType());
|
ModManifestEntry manifest = FileUtils.getFileJson(file, new TypeToken<ModManifestEntry>() {
|
||||||
|
}.getType());
|
||||||
foundManifest = true;
|
foundManifest = true;
|
||||||
if(manifest != null) {
|
if (manifest != null) {
|
||||||
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
||||||
if(filter.apply(manifest)) {
|
if (filter.apply(manifest)) {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!foundManifest) {
|
if (!foundManifest) {
|
||||||
files.addAll(Lists.newArrayList(currentFile.listFiles(File::isDirectory)));
|
files.addAll(Lists.newArrayList(currentFile.listFiles(File::isDirectory)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (!files.isEmpty());
|
} while (!files.isEmpty());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ModManifestEntry> findAllInstalledMods() {
|
public static List<ModManifestEntry> findAllInstalledMods() {
|
||||||
ConcurrentLinkedQueue<File> files = Queues.newConcurrentLinkedQueue();
|
ConcurrentLinkedQueue<File> files = Queues.newConcurrentLinkedQueue();
|
||||||
files.add(new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH));
|
files.add(new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH));
|
||||||
List<ModManifestEntry> mods = new ArrayList<>(30);
|
List<ModManifestEntry> mods = new ArrayList<>(30);
|
||||||
do {
|
do {
|
||||||
File currentFile = files.poll();
|
File currentFile = files.poll();
|
||||||
if(currentFile != null && currentFile.exists()) {
|
if (currentFile != null && currentFile.exists()) {
|
||||||
boolean foundManifest = false;
|
boolean foundManifest = false;
|
||||||
for(File file : currentFile.listFiles(File::isFile)) {
|
for (File file : currentFile.listFiles(File::isFile)) {
|
||||||
if(StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
|
if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
|
||||||
ModManifestEntry manifest = CommonLogic.getFileJson(file, new TypeToken<ModManifestEntry>(){}.getType());
|
ModManifestEntry manifest = FileUtils.getFileJson(file, new TypeToken<ModManifestEntry>() {
|
||||||
|
}.getType());
|
||||||
foundManifest = true;
|
foundManifest = true;
|
||||||
if(manifest != null) {
|
if (manifest != null) {
|
||||||
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
||||||
mods.add(manifest);
|
mods.add(manifest);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!foundManifest) {
|
if (!foundManifest) {
|
||||||
files.addAll(Lists.newArrayList(currentFile.listFiles(File::isDirectory)));
|
files.addAll(Lists.newArrayList(currentFile.listFiles(File::isDirectory)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,33 +101,31 @@ public class ModAssetsManager {
|
||||||
|
|
||||||
public boolean installDefaultMods() {
|
public boolean installDefaultMods() {
|
||||||
Activity context = CommonLogic.getActivityFromView(root);
|
Activity context = CommonLogic.getActivityFromView(root);
|
||||||
List<ModManifestEntry> modManifestEntries = CommonLogic.getAssetJson(context, "mods_manifest.json", new TypeToken<List<ModManifestEntry>>() {
|
List<ModManifestEntry> modManifestEntries = FileUtils.getAssetJson(context, "mods_manifest.json", new TypeToken<List<ModManifestEntry>>() {
|
||||||
}.getType());
|
}.getType());
|
||||||
if(modManifestEntries == null)
|
if (modManifestEntries == null)
|
||||||
return false;
|
return false;
|
||||||
File modFolder = new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH);
|
File modFolder = new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH);
|
||||||
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
||||||
for (ModManifestEntry mod : modManifestEntries) {
|
for (ModManifestEntry mod : modManifestEntries) {
|
||||||
if(installedModMap.containsKey(mod.getUniqueID()) || installedModMap.containsKey(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"))) {
|
if (installedModMap.containsKey(mod.getUniqueID()) || installedModMap.containsKey(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"))) {
|
||||||
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(mod.getUniqueID());
|
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(mod.getUniqueID());
|
||||||
if(installedMods.size() > 1) {
|
if (installedMods.size() > 1) {
|
||||||
CommonLogic.showAlertDialog(root, R.string.error,
|
CommonLogic.showAlertDialog(root, R.string.error,
|
||||||
String.format(context.getString(R.string.duplicate_mod_found),
|
String.format(context.getString(R.string.duplicate_mod_found),
|
||||||
Joiner.on(",").join(Lists.transform(installedMods, item -> CommonLogic.toPrettyPath(item.getAssetPath())))));
|
Joiner.on(",").join(Lists.transform(installedMods, item -> FileUtils.toPrettyPath(item.getAssetPath())))));
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (installedMods.size() == 0) {
|
||||||
else if(installedMods.size() == 0) {
|
|
||||||
installedMods = installedModMap.get(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"));
|
installedMods = installedModMap.get(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"));
|
||||||
}
|
}
|
||||||
if(installedMods.size() > 0) {
|
if (installedMods.size() > 0) {
|
||||||
try {
|
try {
|
||||||
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), new File(installedMods.get(0).getAssetPath()), (name) -> StringUtils.removeStart(name, mod.getName() + "/"));
|
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), new File(installedMods.get(0).getAssetPath()), (name) -> StringUtils.removeStart(name, mod.getName() + "/"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Install Mod Error", e);
|
Log.e(TAG, "Install Mod Error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
try {
|
try {
|
||||||
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), modFolder);
|
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), modFolder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -134,26 +138,115 @@ public class ModAssetsManager {
|
||||||
|
|
||||||
public void checkModEnvironment(Consumer<Boolean> returnCallback) {
|
public void checkModEnvironment(Consumer<Boolean> returnCallback) {
|
||||||
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
||||||
|
checkDuplicateMod(installedModMap, (isConfirm) -> {
|
||||||
|
if (isConfirm)
|
||||||
|
checkUnsatisfiedDependencies(installedModMap, (isConfirm2) -> {
|
||||||
|
if (isConfirm2)
|
||||||
|
checkContentpacks(installedModMap, returnCallback);
|
||||||
|
else
|
||||||
|
returnCallback.accept(false);
|
||||||
|
});
|
||||||
|
else
|
||||||
|
returnCallback.accept(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDuplicateMod(ImmutableListMultimap<String, ModManifestEntry> installedModMap, Consumer<Boolean> returnCallback) {
|
||||||
|
// Duplicate mod check
|
||||||
ArrayList<String> list = Lists.newArrayList();
|
ArrayList<String> list = Lists.newArrayList();
|
||||||
for (String key : installedModMap.keySet()) {
|
for (String key : installedModMap.keySet()) {
|
||||||
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(key);
|
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(key);
|
||||||
if(installedMods.size() > 1) {
|
if (installedMods.size() > 1) {
|
||||||
list.add(Joiner.on(",").join(Lists.transform(installedMods, item -> CommonLogic.toPrettyPath(item.getAssetPath()))));
|
list.add(Joiner.on(",").join(Lists.transform(installedMods, item -> FileUtils.toPrettyPath(item.getAssetPath()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(list.size() > 0) {
|
if (list.size() > 0) {
|
||||||
CommonLogic.showConfirmDialog(root, R.string.error,
|
CommonLogic.showConfirmDialog(root, R.string.error,
|
||||||
String.format(root.getContext().getString(R.string.duplicate_mod_found),
|
root.getContext().getString(R.string.duplicate_mod_found, Joiner.on(";").join(list)),
|
||||||
Joiner.on(";").join(list)), ((dialog, which) -> {
|
((dialog, which) -> {
|
||||||
if(which == DialogAction.POSITIVE) {
|
if (which == DialogAction.POSITIVE) {
|
||||||
returnCallback.accept(true);
|
returnCallback.accept(true);
|
||||||
}
|
} else {
|
||||||
else {
|
returnCallback.accept(false);
|
||||||
returnCallback.accept(false);
|
}
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
returnCallback.accept(true);
|
else
|
||||||
|
returnCallback.accept(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUnsatisfiedDependencies(ImmutableListMultimap<String, ModManifestEntry> installedModMap, Consumer<Boolean> returnCallback) {
|
||||||
|
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
|
||||||
|
if (mod.getDependencies() != null) {
|
||||||
|
ArrayList<ModManifestEntry> unsatisfiedDependencies = Lists.newArrayList(Iterables.filter(mod.getDependencies(), dependency -> {
|
||||||
|
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||||
|
if (entries.size() != 1)
|
||||||
|
return true;
|
||||||
|
String version = entries.get(0).getVersion();
|
||||||
|
if (StringUtils.isBlank(version)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(dependency.getVersion())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (VersionUtil.compareVersion(version, dependency.getVersion()) < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
if (unsatisfiedDependencies.size() > 0) {
|
||||||
|
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), Joiner.on(",").join(Lists.transform(unsatisfiedDependencies, ModManifestEntry::getUniqueID)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}), item -> item != null);
|
||||||
|
if (dependencyErrors.iterator().hasNext()) {
|
||||||
|
CommonLogic.showConfirmDialog(root, R.string.error,
|
||||||
|
Joiner.on(";").join(dependencyErrors),
|
||||||
|
((dialog, which) -> {
|
||||||
|
if (which == DialogAction.POSITIVE) {
|
||||||
|
returnCallback.accept(true);
|
||||||
|
} else {
|
||||||
|
returnCallback.accept(false);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
returnCallback.accept(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkContentpacks(ImmutableListMultimap<String, ModManifestEntry> installedModMap, Consumer<Boolean> returnCallback) {
|
||||||
|
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
|
||||||
|
ModManifestEntry dependency = mod.getContentPackFor();
|
||||||
|
if (dependency != null) {
|
||||||
|
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||||
|
if (entries.size() != 1)
|
||||||
|
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
|
||||||
|
String version = entries.get(0).getVersion();
|
||||||
|
if (!StringUtils.isBlank(version)) {
|
||||||
|
if (StringUtils.isBlank(dependency.getVersion())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (VersionUtil.compareVersion(version, dependency.getVersion()) < 0) {
|
||||||
|
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}), item -> item != null);
|
||||||
|
if (dependencyErrors.iterator().hasNext()) {
|
||||||
|
CommonLogic.showConfirmDialog(root, R.string.error,
|
||||||
|
Joiner.on(";").join(dependencyErrors),
|
||||||
|
((dialog, which) -> {
|
||||||
|
if (which == DialogAction.POSITIVE) {
|
||||||
|
returnCallback.accept(true);
|
||||||
|
} else {
|
||||||
|
returnCallback.accept(false);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
returnCallback.accept(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.widget.EditText;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.zane.smapiinstaller.R;
|
import com.zane.smapiinstaller.R;
|
||||||
import com.zane.smapiinstaller.logic.CommonLogic;
|
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||||
|
import com.zane.smapiinstaller.utils.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -44,7 +45,7 @@ public class ConfigEditFragment extends Fragment {
|
||||||
}
|
}
|
||||||
configPath = this.getArguments().getString("configPath");
|
configPath = this.getArguments().getString("configPath");
|
||||||
if(configPath != null) {
|
if(configPath != null) {
|
||||||
String fileText = CommonLogic.getFileText(new File(configPath));
|
String fileText = FileUtils.getFileText(new File(configPath));
|
||||||
if(fileText != null) {
|
if(fileText != null) {
|
||||||
editText.setText(fileText);
|
editText.setText(fileText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,15 @@ class ConfigViewModel extends ViewModel {
|
||||||
|
|
||||||
ConfigViewModel(View root) {
|
ConfigViewModel(View root) {
|
||||||
this.modList = ModAssetsManager.findAllInstalledMods();
|
this.modList = ModAssetsManager.findAllInstalledMods();
|
||||||
Collections.sort(this.modList, (a, b)-> a.getName().compareTo(b.getName()));
|
Collections.sort(this.modList, (a, b)-> {
|
||||||
|
if(a.getContentPackFor() != null && b.getContentPackFor() == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(b.getContentPackFor() != null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return a.getName().compareTo(b.getName());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.zane.smapiinstaller.ui.download;
|
package com.zane.smapiinstaller.ui.download;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
@ -131,7 +130,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
||||||
}
|
}
|
||||||
File file = new File(context.getCacheDir(), downloadableContent.getName() + ".zip");
|
File file = new File(context.getCacheDir(), downloadableContent.getName() + ".zip");
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
if (!StringUtils.equalsIgnoreCase(CommonLogic.getFileHash(file), downloadableContent.getHash())) {
|
if (!StringUtils.equalsIgnoreCase(com.zane.smapiinstaller.utils.FileUtils.getFileHash(file), downloadableContent.getHash())) {
|
||||||
file.delete();
|
file.delete();
|
||||||
} else {
|
} else {
|
||||||
unpackLogic(context, file, modManifestEntry);
|
unpackLogic(context, file, modManifestEntry);
|
||||||
|
@ -173,7 +172,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
||||||
}
|
}
|
||||||
downloading.set(false);
|
downloading.set(false);
|
||||||
File downloadedFile = response.body();
|
File downloadedFile = response.body();
|
||||||
String hash = CommonLogic.getFileHash(downloadedFile);
|
String hash = com.zane.smapiinstaller.utils.FileUtils.getFileHash(downloadedFile);
|
||||||
if (!StringUtils.equalsIgnoreCase(hash, downloadableContent.getHash())) {
|
if (!StringUtils.equalsIgnoreCase(hash, downloadableContent.getHash())) {
|
||||||
CommonLogic.showAlertDialog(itemView, R.string.error, R.string.error_failed_to_download);
|
CommonLogic.showAlertDialog(itemView, R.string.error, R.string.error_failed_to_download);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.zane.smapiinstaller.ui.install;
|
package com.zane.smapiinstaller.ui.install;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.DialogAction;
|
||||||
import com.afollestad.materialdialogs.GravityEnum;
|
import com.afollestad.materialdialogs.GravityEnum;
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
import com.zane.smapiinstaller.R;
|
import com.zane.smapiinstaller.R;
|
||||||
|
@ -38,6 +40,19 @@ public class InstallFragment extends Fragment {
|
||||||
|
|
||||||
@OnClick(R.id.button_install)
|
@OnClick(R.id.button_install)
|
||||||
void Install() {
|
void Install() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
CommonLogic.showConfirmDialog(root, R.string.confirm, R.string.android_version_confirm, ((dialog, which) -> {
|
||||||
|
if(which == DialogAction.POSITIVE) {
|
||||||
|
installLogic();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
installLogic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installLogic() {
|
||||||
new MaterialDialog.Builder(context).title(R.string.install_progress_title).content(R.string.extracting_package).contentGravity(GravityEnum.CENTER)
|
new MaterialDialog.Builder(context).title(R.string.install_progress_title).content(R.string.extracting_package).contentGravity(GravityEnum.CENTER)
|
||||||
.progress(false, 100, true).cancelable(false).cancelListener(dialog -> {
|
.progress(false, 100, true).cancelable(false).cancelListener(dialog -> {
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.zane.smapiinstaller.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class FileUtils {
|
||||||
|
public static String getFileText(File file) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = new FileInputStream(file);
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
|
return CharStreams.toString(reader);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getLocalAsset(Context context, String filename) throws IOException {
|
||||||
|
File file = new File(context.getFilesDir(), filename);
|
||||||
|
if (file.exists()) {
|
||||||
|
return new FileInputStream(file);
|
||||||
|
}
|
||||||
|
return context.getAssets().open(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getFileJson(File file, Type type) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = new FileInputStream(file);
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
|
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||||
|
gsonBuilder.setLenient();
|
||||||
|
return gsonBuilder.create().fromJson(CharStreams.toString(reader), type);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getFileJson(File file, Class<T> tClass) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = new FileInputStream(file);
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
|
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||||
|
gsonBuilder.setLenient();
|
||||||
|
return gsonBuilder.create().fromJson(CharStreams.toString(reader), tClass);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeAssetJson(Context context, String filename, Object content) {
|
||||||
|
try {
|
||||||
|
String tmpFilename = filename + ".tmp";
|
||||||
|
File file = new File(context.getFilesDir(), tmpFilename);
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(file);
|
||||||
|
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
|
||||||
|
writer.write(new Gson().toJson(content));
|
||||||
|
} finally {
|
||||||
|
org.zeroturnaround.zip.commons.FileUtils.moveFile(file, new File(context.getFilesDir(), filename));
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getAssetJson(Context context, String filename, Class<T> tClass) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = getLocalAsset(context, filename);
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
|
return new Gson().fromJson(CharStreams.toString(reader), tClass);
|
||||||
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getAssetJson(Context context, String filename, Type type) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = getLocalAsset(context, filename);
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
|
return new Gson().fromJson(CharStreams.toString(reader), type);
|
||||||
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getAssetBytes(Context context, String filename) {
|
||||||
|
try {
|
||||||
|
try (InputStream inputStream = getLocalAsset(context, filename)) {
|
||||||
|
return ByteStreams.toByteArray(inputStream);
|
||||||
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toPrettyPath(String path) {
|
||||||
|
return StringUtils.removeStart(path, Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileHash(Context context, String filename) {
|
||||||
|
try (InputStream inputStream = getLocalAsset(context, filename)) {
|
||||||
|
return Hashing.sha256().hashBytes(ByteStreams.toByteArray(inputStream)).toString();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileHash(File file) {
|
||||||
|
try (InputStream inputStream = new FileInputStream(file)) {
|
||||||
|
return Hashing.sha256().hashBytes(ByteStreams.toByteArray(inputStream)).toString();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.zane.smapiinstaller.utils;
|
||||||
|
|
||||||
|
import com.google.common.base.CharMatcher;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VersionUtil {
|
||||||
|
private static int parseVersionSection(String version) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(version);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
List<String> list = Splitter.on("-").splitToList(version);
|
||||||
|
switch (list.get(0).toLowerCase()) {
|
||||||
|
case "alpha":
|
||||||
|
return -2;
|
||||||
|
case "beta":
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
private static boolean isZero(List<String> versionSections) {
|
||||||
|
return !Iterables.filter(versionSections, version -> {
|
||||||
|
try {
|
||||||
|
int i = Integer.parseInt(version);
|
||||||
|
if (i == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).iterator().hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareVersion(String versionA, String versionB) {
|
||||||
|
List<String> versionSectionsA = Splitter.on(".").splitToList(versionA);
|
||||||
|
List<String> versionSectionsB = Splitter.on(".").splitToList(versionB);
|
||||||
|
for (int i = 0; i < versionSectionsA.size(); i++) {
|
||||||
|
if (versionSectionsB.size() <= i) {
|
||||||
|
if(isZero(versionSectionsA.subList(i, versionSectionsA.size()))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int compare = Integer.compare(parseVersionSection(versionSectionsA.get(i)), parseVersionSection(versionSectionsB.get(i)));
|
||||||
|
if(compare != 0)
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,4 +52,5 @@
|
||||||
<string name="progress">進度</string>
|
<string name="progress">進度</string>
|
||||||
<string name="downloading">正在下載: %d KB / %d KB</string>
|
<string name="downloading">正在下載: %d KB / %d KB</string>
|
||||||
<string name="menu_about">關於</string>
|
<string name="menu_about">關於</string>
|
||||||
|
<string name="android_version_confirm">你的系統版本過老,可能會導致0Harmony無效,建議升級到安卓6及以上版本</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -52,4 +52,5 @@
|
||||||
<string name="progress">進度</string>
|
<string name="progress">進度</string>
|
||||||
<string name="downloading">正在下載: %d KB / %d KB</string>
|
<string name="downloading">正在下載: %d KB / %d KB</string>
|
||||||
<string name="menu_about">關於</string>
|
<string name="menu_about">關於</string>
|
||||||
|
<string name="android_version_confirm">你的系統版本過老,可能會導致0Harmony無效,建議升級到安卓6及以上版本</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -52,4 +52,5 @@
|
||||||
<string name="progress">进度</string>
|
<string name="progress">进度</string>
|
||||||
<string name="downloading">正在下载: %d KB / %d KB</string>
|
<string name="downloading">正在下载: %d KB / %d KB</string>
|
||||||
<string name="menu_about">关于</string>
|
<string name="menu_about">关于</string>
|
||||||
|
<string name="android_version_confirm">你的系统版本过老,可能会导致0Harmony无效,建议升级到安卓6及以上版本</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -55,4 +55,5 @@
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
<!-- TODO: Remove or change this placeholder text -->
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
<string name="menu_about">About</string>
|
<string name="menu_about">About</string>
|
||||||
|
<string name="android_version_confirm">You device system version is too old for MonoMod, this may leads to crash of 0Harmony framework, update to Android M or later if possible</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue