mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-13 06:39:54 -04:00
feat: Implement caching of SHA1's and fall back to old loading bar when offline (#13)
This commit is contained in:
commit
29b9e2233f
@ -9,6 +9,7 @@ import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@ -276,6 +277,10 @@ public class mcAccountSpinner extends AppCompatSpinner implements AdapterView.On
|
||||
}
|
||||
|
||||
private void performLogin(MinecraftAccount minecraftAccount){
|
||||
// Logging in when there's no internet is useless. This should really be turned into a network callback though.
|
||||
if(!Tools.isOnline(getContext())){
|
||||
return;
|
||||
}
|
||||
if(minecraftAccount.isLocal()) return;
|
||||
|
||||
mLoginBarPaint.setColor(getResources().getColor(R.color.minebutton_color));
|
||||
|
@ -21,6 +21,8 @@ import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -1429,6 +1431,18 @@ public final class Tools {
|
||||
OBSOLETE_RESOURCES_PATH = DIR_GAME_NEW + "/resources";
|
||||
}
|
||||
|
||||
private static NetworkInfo getActiveNetworkInfo(Context ctx) {
|
||||
ConnectivityManager connMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
|
||||
return networkInfo; // This can return null when there is no wifi or data connected
|
||||
}
|
||||
|
||||
public static boolean isOnline(Context ctx) {
|
||||
NetworkInfo info = getActiveNetworkInfo(ctx);
|
||||
if(info == null) return false;
|
||||
return (info.isConnected());
|
||||
}
|
||||
|
||||
public static boolean isDemoProfile(Context ctx){
|
||||
MinecraftAccount currentProfile = PojavProfile.getCurrentProfileContent(ctx, null);
|
||||
return currentProfile != null && currentProfile.isDemo();
|
||||
|
@ -76,14 +76,18 @@ public class DownloadMirror {
|
||||
* @param urlInput The original (Mojang) URL for the download
|
||||
* @return the length of the file denoted by the URL in bytes, or -1 if not available
|
||||
*/
|
||||
public static long getContentLengthMirrored(int downloadClass, String urlInput) throws IOException {
|
||||
long length = DownloadUtils.getContentLength(getMirrorMapping(downloadClass, urlInput));
|
||||
if(length < 1) {
|
||||
Log.w("DownloadMirror", "Unable to get content length from mirror");
|
||||
Log.i("DownloadMirror", "Falling back to default source");
|
||||
return DownloadUtils.getContentLength(urlInput);
|
||||
}else {
|
||||
return length;
|
||||
public static long getContentLengthMirrored(int downloadClass, String urlInput){
|
||||
try {
|
||||
long length = DownloadUtils.getContentLength(getMirrorMapping(downloadClass, urlInput));
|
||||
if (length < 1) {
|
||||
Log.w("DownloadMirror", "Unable to get content length from mirror");
|
||||
Log.i("DownloadMirror", "Falling back to default source");
|
||||
return DownloadUtils.getContentLength(urlInput);
|
||||
} else {
|
||||
return length;
|
||||
}
|
||||
} catch (IOException ignored) { // If error happens, fallback to old file counter instead of size. This shouldn't really happen unless offline though.
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@ package net.kdt.pojavlaunch.tasks;
|
||||
import static net.kdt.pojavlaunch.PojavApplication.sExecutorService;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -25,9 +28,12 @@ import net.kdt.pojavlaunch.value.DependentLibrary;
|
||||
import net.kdt.pojavlaunch.value.MinecraftClientInfo;
|
||||
import net.kdt.pojavlaunch.value.MinecraftLibraryArtifact;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -56,6 +62,7 @@ public class MinecraftDownloader {
|
||||
private static final ThreadLocal<byte[]> sThreadLocalDownloadBuffer = new ThreadLocal<>();
|
||||
|
||||
private boolean isLocalProfile = false;
|
||||
private boolean isOnline;
|
||||
|
||||
/**
|
||||
* Start the game version download process on the global executor service.
|
||||
@ -65,11 +72,13 @@ public class MinecraftDownloader {
|
||||
* @param listener The download status listener
|
||||
*/
|
||||
public void start(@Nullable Activity activity, @Nullable JMinecraftVersionList.Version version,
|
||||
@NonNull String realVersion, // this was there for a reason
|
||||
@NonNull String realVersion,
|
||||
@NonNull AsyncMinecraftDownloader.DoneListener listener) {
|
||||
if(activity != null){
|
||||
isLocalProfile = Tools.isLocalProfile(activity);
|
||||
isOnline = Tools.isOnline(activity);
|
||||
Tools.switchDemo(Tools.isDemoProfile(activity));
|
||||
|
||||
} else {
|
||||
isLocalProfile = true;
|
||||
Tools.switchDemo(true);
|
||||
@ -77,14 +86,32 @@ public class MinecraftDownloader {
|
||||
|
||||
sExecutorService.execute(() -> {
|
||||
try {
|
||||
if(isLocalProfile){
|
||||
throw new RuntimeException("Download failed. Please make sure you are logged in with a Microsoft Account.");
|
||||
}
|
||||
if(isLocalProfile || !isOnline) {
|
||||
String versionMessage = realVersion; // Use provided version unless we find its a modded instance
|
||||
|
||||
// See if provided version is a modded version and if that version depends on another jar, check for presence of both jar's .json.
|
||||
try {
|
||||
// This reads the .json associated with the provided version. If it fails, we can assume it's not installed.
|
||||
File providedJsonFile = new File(Tools.DIR_HOME_VERSION + "/" + realVersion + "/" + realVersion + ".json");
|
||||
JMinecraftVersionList.Version providedJson = Tools.GLOBAL_GSON.fromJson(Tools.read(providedJsonFile.getAbsolutePath()), JMinecraftVersionList.Version.class);
|
||||
|
||||
// This checks if running modded version that depends on other jars, so we use that for the error message.
|
||||
File vanillaJsonFile = new File(Tools.DIR_HOME_VERSION + "/" + providedJson.inheritsFrom + "/" + providedJson.inheritsFrom + ".json");
|
||||
versionMessage = providedJson.inheritsFrom != null ? providedJson.inheritsFrom : versionMessage;
|
||||
|
||||
// Ensure they're both not some 0 byte corrupted json
|
||||
if (providedJsonFile.length() == 0 || vanillaJsonFile.exists() && vanillaJsonFile.length() == 0){
|
||||
throw new RuntimeException("Minecraft "+versionMessage+ " is needed by " +realVersion); }
|
||||
|
||||
listener.onDownloadDone();
|
||||
} catch (Exception e) {
|
||||
String tryagain = !isOnline ? "Please ensure you have an internet connection" : "Please try again on your Microsoft Account";
|
||||
Tools.showErrorRemote(versionMessage + " is not currently installed. "+ tryagain, e);
|
||||
}
|
||||
}else {
|
||||
downloadGame(activity, version, realVersion);
|
||||
listener.onDownloadDone();
|
||||
}catch (UnknownHostException e){
|
||||
Log.i("DownloadMirror", e.toString());
|
||||
Tools.showErrorRemote("Can't download Minecraft, no internet connection found", e);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
listener.onDownloadFailed(e);
|
||||
}
|
||||
@ -473,18 +500,49 @@ public class MinecraftDownloader {
|
||||
* Since Minecraft libraries are stored in maven repositories, try to use
|
||||
* this when downloading libraries without hashes in the json.
|
||||
*/
|
||||
private void tryGetLibrarySha1() {
|
||||
private void tryGetLibrarySha1() throws IOException {
|
||||
File sha1CacheDir = new File(Tools.DIR_CACHE + "/sha1hashes");
|
||||
File cacheFile = new File(sha1CacheDir.getAbsolutePath() + FileUtils.getFileName(mTargetUrl) + ".sha");
|
||||
|
||||
// Only use cache when its offline. No point in having cache invalidation now!
|
||||
if (!isOnline || !LauncherPreferences.PREF_CHECK_LIBRARY_SHA) { // Well not only offlines..this setting speeds up launch times at least!
|
||||
try (BufferedReader cacheFileReader = new BufferedReader(new FileReader(cacheFile))) {
|
||||
mTargetSha1 = cacheFileReader.readLine();
|
||||
if (mTargetSha1 != null) {
|
||||
Log.i("MinecraftDownloader", "Reading Hash from cache: " + mTargetSha1 + " from " + cacheFile);
|
||||
} else if (cacheFile.exists()) {
|
||||
Log.i("MinecraftDownloader", "Deleting invalid hash from cache: " + cacheFile);
|
||||
cacheFile.delete();
|
||||
}
|
||||
} catch (FileNotFoundException ignored) {
|
||||
mTargetSha1 = null;
|
||||
Log.w("MinecraftDownloader", "Failed to read hash for " + cacheFile);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String resultHash = null;
|
||||
try {
|
||||
resultHash = downloadSha1();
|
||||
// The hash is a 40-byte download.
|
||||
mInternetUsageCounter.getAndAdd(40);
|
||||
}catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
Log.i("MinecraftDownloader", "Failed to download hash", e);
|
||||
if (cacheFile.exists() && new BufferedReader(new FileReader(cacheFile)).readLine() == null) {
|
||||
Log.i("MinecraftDownloader", "Deleting failed hash download from cache: " + cacheFile);
|
||||
cacheFile.delete();
|
||||
}
|
||||
}
|
||||
if(resultHash != null) {
|
||||
Log.i("MinecraftDownloader", "Got hash: "+resultHash+ " for "+FileUtils.getFileName(mTargetUrl));
|
||||
if (resultHash != null) {
|
||||
Log.i("MinecraftDownloader", "Got hash: " + resultHash + " for " + FileUtils.getFileName(mTargetUrl));
|
||||
mTargetSha1 = resultHash;
|
||||
if (!sha1CacheDir.exists()) {
|
||||
sha1CacheDir.mkdir(); // If mkdir() fails, something went wrong with initializing /data/data/. mkdirs() isn't used on purpose
|
||||
}
|
||||
try (FileWriter writeHash = new FileWriter(cacheFile)) {
|
||||
Log.i("MinecraftDownloader", "Saving hash: " + resultHash + " for " + FileUtils.getFileName(mTargetUrl) + " to " + cacheFile);
|
||||
writeHash.write(resultHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,12 @@ public class DownloadUtils {
|
||||
FileUtils.ensureParentDirectory(out);
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(out)) {
|
||||
download(url, fileOutputStream);
|
||||
} catch (IOException e) {
|
||||
if (out.length() < 1) { // Only delete it if file is 0 bytes cause this file might already be downloaded and something else went wrong.
|
||||
Log.i("DownloadUtils", "Cleaning up failed download: " + out.getAbsolutePath());
|
||||
out.delete();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user