diff --git a/app_pojavlauncher/src/main/AndroidManifest.xml b/app_pojavlauncher/src/main/AndroidManifest.xml
index 457e0cbfd..c08be997c 100644
--- a/app_pojavlauncher/src/main/AndroidManifest.xml
+++ b/app_pojavlauncher/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
android:name="android.hardware.type.pc"
android:required="false" />
+
@@ -82,6 +83,7 @@
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:theme="@style/Theme.AppCompat.DayNight.Dialog" />
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
index 76a05254d..c88f2120a 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
@@ -31,6 +31,7 @@ import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.SelectAuthFragment;
+import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment;
@@ -53,6 +54,7 @@ public class LauncherActivity extends BaseActivity {
private ImageButton mSettingsButton, mDeleteAccountButton;
private ProgressLayout mProgressLayout;
private ProgressServiceKeeper mProgressServiceKeeper;
+ private ModloaderInstallTracker mInstallTracker;
/* Allows to switch from one button "type" to another */
private final FragmentManager.FragmentLifecycleCallbacks mFragmentCallbackListener = new FragmentManager.FragmentLifecycleCallbacks() {
@@ -167,6 +169,8 @@ public class LauncherActivity extends BaseActivity {
new AsyncVersionList().getVersionList(versions -> ExtraCore.setValue(ExtraConstants.RELEASE_TABLE, versions), false);
+ mInstallTracker = new ModloaderInstallTracker(this);
+
mProgressLayout.observe(ProgressLayout.DOWNLOAD_MINECRAFT);
mProgressLayout.observe(ProgressLayout.UNPACK_RUNTIME);
mProgressLayout.observe(ProgressLayout.INSTALL_MODPACK);
@@ -174,6 +178,18 @@ public class LauncherActivity extends BaseActivity {
mProgressLayout.observe(ProgressLayout.DOWNLOAD_VERSION_LIST);
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mInstallTracker.attach();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mInstallTracker.detach();
+ }
+
@Override
public boolean setFullscreen() {
return false;
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/ModloaderInstallTracker.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/ModloaderInstallTracker.java
new file mode 100644
index 000000000..8ec11e3fa
--- /dev/null
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/ModloaderInstallTracker.java
@@ -0,0 +1,106 @@
+package net.kdt.pojavlaunch.modloaders.modpacks;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+import net.kdt.pojavlaunch.modloaders.modpacks.api.ModLoader;
+
+import java.io.File;
+
+/**
+ * This class is meant to track the availability of a modloader that is ready to be installed (as a result of modpack installation)
+ * It is needed because having all this logic spread over LauncherActivity would be clumsy, and I think that this is the best way to
+ * ensure that the modloader installer will run, even if the user does not receive the notification or something else happens
+ */
+public class ModloaderInstallTracker implements SharedPreferences.OnSharedPreferenceChangeListener {
+ private final SharedPreferences mSharedPreferences;
+ private final Activity mActivity;
+
+ /**
+ * Create a ModInstallTracker object. This must be done in the Activity's onCreate method.
+ * @param activity the host activity
+ */
+ public ModloaderInstallTracker(Activity activity) {
+ mActivity = activity;
+ mSharedPreferences = getPreferences(activity);
+
+ }
+
+ /**
+ * Attach the ModloaderInstallTracker to the current Activity. Must be done in the Activity's
+ * onResume method
+ */
+ public void attach() {
+ mSharedPreferences.registerOnSharedPreferenceChangeListener(this);
+ runCheck();
+ }
+
+ /**
+ * Detach the ModloaderInstallTracker from the current Activity. Must be done in the Activity's
+ * onPause method
+ */
+ public void detach() {
+ mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String prefName) {
+ if(!"modLoaderAvailable".equals(prefName)) return;
+ runCheck();
+ }
+
+ @SuppressLint("ApplySharedPref")
+ private void runCheck() {
+ if(!mSharedPreferences.getBoolean("modLoaderAvailable", false)) return;
+ SharedPreferences.Editor editor = mSharedPreferences.edit().putBoolean("modLoaderAvailable", false);
+ if(!editor.commit()) editor.apply();
+ ModLoader modLoader = deserializeModLoader(mSharedPreferences);
+ File modInstallFile = deserializeInstallFile(mSharedPreferences);
+ if(modLoader == null || modInstallFile == null) return;
+ startModInstallation(modLoader, modInstallFile);
+ }
+
+ private void startModInstallation(ModLoader modLoader, File modInstallFile) {
+ Intent installIntent = modLoader.getInstallationIntent(mActivity, modInstallFile);
+ mActivity.startActivity(installIntent);
+ }
+
+ private static SharedPreferences getPreferences(Context context) {
+ return context.getSharedPreferences("modloader_info", Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Store the data necessary to start a ModLoader installation for the tracker to start the installer
+ * sometime.
+ * @param context the Context
+ * @param modLoader the ModLoader to store
+ * @param modInstallFile the installer jar to store
+ */
+ @SuppressLint("ApplySharedPref")
+ public static void saveModLoader(Context context, ModLoader modLoader, File modInstallFile) {
+ SharedPreferences.Editor editor = getPreferences(context).edit();
+ editor.putInt("modLoaderType", modLoader.modLoaderType);
+ editor.putString("modLoaderVersion", modLoader.modLoaderVersion);
+ editor.putString("minecraftVersion", modLoader.minecraftVersion);
+ editor.putString("modInstallerJar", modInstallFile.getAbsolutePath());
+ editor.putBoolean("modLoaderAvailable", true);
+ editor.commit();
+ }
+
+ private static ModLoader deserializeModLoader(SharedPreferences sharedPreferences) {
+ if(!sharedPreferences.contains("modLoaderType") ||
+ !sharedPreferences.contains("modLoaderVersion") ||
+ !sharedPreferences.contains("minecraftVersion")) return null;
+ return new ModLoader(sharedPreferences.getInt("modLoaderType", -1),
+ sharedPreferences.getString("modLoaderVersion", ""),
+ sharedPreferences.getString("minecraftVersion", ""));
+ }
+
+ private static File deserializeInstallFile(SharedPreferences sharedPreferences) {
+ if(!sharedPreferences.contains("modInstallerJar")) return null;
+ return new File(sharedPreferences.getString("modInstallerJar", ""));
+ }
+}
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackApi.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackApi.java
index 46fe7caed..ff9f9c67e 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackApi.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackApi.java
@@ -40,25 +40,7 @@ public interface ModpackApi {
PojavApplication.sExecutorService.execute(() -> {
ModLoader loaderInfo = installMod(modDetail, selectedVersion);
if (loaderInfo == null) return;
-
- loaderInfo.getDownloadTask(new ModloaderDownloadListener() {
- @Override
- public void onDownloadFinished(File downloadedFile) {
- Intent intent = loaderInfo.getInstallationIntent(context, downloadedFile);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
- }
-
- @Override
- public void onDataNotAvailable() {
- Toast.makeText(context, "Version gathering failed", Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onDownloadError(Exception e) {
- Toast.makeText(context, "download failed", Toast.LENGTH_SHORT).show();
- }
- }).run();
+ loaderInfo.getDownloadTask(new NotificationDownloadListener(context, loaderInfo)).run();
});
}
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java
new file mode 100644
index 000000000..34d12ad1a
--- /dev/null
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java
@@ -0,0 +1,66 @@
+package net.kdt.pojavlaunch.modloaders.modpacks.api;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+
+import androidx.core.app.NotificationCompat;
+
+import net.kdt.pojavlaunch.LauncherActivity;
+import net.kdt.pojavlaunch.R;
+import net.kdt.pojavlaunch.Tools;
+import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
+import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker;
+
+import java.io.File;
+
+public class NotificationDownloadListener implements ModloaderDownloadListener {
+
+ private final NotificationCompat.Builder mNotificationBuilder;
+ private final NotificationManager mNotificationManager;
+ private final Context mContext;
+ private final ModLoader mModLoader;
+
+ public NotificationDownloadListener(Context context, ModLoader modLoader) {
+ mModLoader = modLoader;
+ mContext = context.getApplicationContext();
+ mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotificationBuilder = new NotificationCompat.Builder(context, "channel_id")
+ .setContentTitle(context.getString(R.string.modpack_install_notification_title))
+ .setSmallIcon(R.drawable.notif_icon);
+ }
+
+ @Override
+ public void onDownloadFinished(File downloadedFile) {
+ ModloaderInstallTracker.saveModLoader(mContext, mModLoader, downloadedFile);
+ Intent mainActivityIntent = new Intent(mContext, LauncherActivity.class);
+ Tools.runOnUiThread(()->sendIntentNotification(mainActivityIntent, R.string.modpack_install_notification_success));
+ }
+
+ @Override
+ public void onDataNotAvailable() {
+ Tools.runOnUiThread(()->sendEmptyNotification(R.string.modpack_install_notification_data_not_available));
+ }
+
+ @Override
+ public void onDownloadError(Exception e) {
+ Tools.runOnUiThread(()->sendEmptyNotification(R.string.modpack_install_notification_download_failed));
+ }
+
+ private void sendIntentNotification(Intent intent, int contentText) {
+ PendingIntent pendingInstallIntent =
+ PendingIntent.getActivity(mContext, 0,
+ intent, Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0);
+
+ mNotificationBuilder.setContentText(mContext.getText(contentText));
+ mNotificationBuilder.setContentIntent(pendingInstallIntent);
+ mNotificationManager.notify(3, mNotificationBuilder.build());
+ }
+
+ private void sendEmptyNotification(int contentText) {
+ mNotificationBuilder.setContentText(mContext.getText(contentText));
+ mNotificationManager.notify(3, mNotificationBuilder.build());
+ }
+}
diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml
index 5958bd3eb..facea4483 100644
--- a/app_pojavlauncher/src/main/res/values/strings.xml
+++ b/app_pojavlauncher/src/main/res/values/strings.xml
@@ -418,4 +418,8 @@
Downloading mods (%.2f MB / %.2f MB)
Downloading mods (File %d out of %d)
Applying overrides (%d/%d)
+ Pojav Modpack Installer
+ Click here to finish modpack installation
+ Failed to download mod loader information
+ Failed to download the mod loader files