From 6128c24f969cf81a0e8bf3f680201a9c72d88b58 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 10 Apr 2019 02:00:48 -0400 Subject: [PATCH] Drastically improve module download service --- .../main/java/com/topjohnwu/magisk/App.java | 10 ++- .../components/DownloadModuleService.java | 88 +++++++++++++------ .../magisk/components/UpdateCheckService.java | 2 +- .../uicomponents/ProgressNotification.java | 11 ++- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/App.java b/app/src/main/java/com/topjohnwu/magisk/App.java index 293975b30..92fc95cac 100644 --- a/app/src/main/java/com/topjohnwu/magisk/App.java +++ b/app/src/main/java/com/topjohnwu/magisk/App.java @@ -33,7 +33,7 @@ public class App extends Application implements Application.ActivityLifecycleCal public SharedPreferences prefs; public MagiskDB mDB; public RepoDatabaseHelper repoDB; - public BaseActivity foreground; + private volatile BaseActivity foreground; static { Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER | Shell.FLAG_USE_MAGISK_BUSYBOX); @@ -68,6 +68,10 @@ public class App extends Application implements Application.ActivityLifecycleCal LocaleManager.setLocale(this); } + public static BaseActivity foreground() { + return self.foreground; + } + @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {} @@ -75,12 +79,12 @@ public class App extends Application implements Application.ActivityLifecycleCal public void onActivityStarted(@NonNull Activity activity) {} @Override - public void onActivityResumed(@NonNull Activity activity) { + public synchronized void onActivityResumed(@NonNull Activity activity) { foreground = (BaseActivity) activity; } @Override - public void onActivityPaused(@NonNull Activity activity) { + public synchronized void onActivityPaused(@NonNull Activity activity) { foreground = null; } diff --git a/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java b/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java index 7e0788d51..a17333cb8 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java @@ -1,20 +1,20 @@ package com.topjohnwu.magisk.components; +import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.net.Uri; import android.os.IBinder; -import android.widget.Toast; import androidx.annotation.Nullable; +import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.container.Repo; +import com.topjohnwu.magisk.uicomponents.Notifications; import com.topjohnwu.magisk.uicomponents.ProgressNotification; -import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -25,13 +25,15 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class DownloadModuleService extends Service { - private boolean running = false; + private List notifications; @Nullable @Override @@ -39,46 +41,82 @@ public class DownloadModuleService extends Service { return null; } + @Override + public void onCreate() { + notifications = new ArrayList<>(); + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (flags == 0 && running) { - Utils.toast(R.string.dl_one_module, Toast.LENGTH_LONG); - } else { - running = true; - Shell.EXECUTOR.execute(() -> { - Repo repo = intent.getParcelableExtra("repo"); - boolean install = intent.getBooleanExtra("install", false); - dlProcessInstall(repo, install); - stopSelf(); - }); - } + Shell.EXECUTOR.execute(() -> { + Repo repo = intent.getParcelableExtra("repo"); + boolean install = intent.getBooleanExtra("install", false); + dlProcessInstall(repo, install); + }); return START_REDELIVER_INTENT; } + @Override + public synchronized void onTaskRemoved(Intent rootIntent) { + for (ProgressNotification n : notifications) { + Notifications.mgr.cancel(n.hashCode()); + } + notifications.clear(); + } + + private synchronized void addNotification(ProgressNotification n) { + if (notifications.isEmpty()) { + // Start foreground + startForeground(n.hashCode(), n.getNotification()); + } + notifications.add(n); + } + + private synchronized void removeNotification(ProgressNotification n) { + notifications.remove(n); + if (notifications.isEmpty()) { + // No more tasks, stop service + stopForeground(true); + stopSelf(); + } else { + // Pick another notification as our foreground notification + n = notifications.get(0); + startForeground(n.hashCode(), n.getNotification()); + } + } + private void dlProcessInstall(Repo repo, boolean install) { File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename()); ProgressNotification progress = new ProgressNotification(output.getName()); - startForeground(progress.hashCode(), progress.getNotification()); + addNotification(progress); try { InputStream in = Networking.get(repo.getZipUrl()) .setDownloadProgressListener(progress) .execForInputStream().getResult(); OutputStream out = new BufferedOutputStream(new FileOutputStream(output)); processZip(in, out, repo.isNewInstaller()); - if (install) { - progress.dismiss(); - Intent intent = new Intent(this, ClassMap.get(FlashActivity.class)); - intent.setData(Uri.fromFile(output)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP); - startActivity(intent); - } else { - progress.dlDone(); + Intent intent = new Intent(this, ClassMap.get(FlashActivity.class)); + intent.setData(Uri.fromFile(output)) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP); + synchronized (getApplication()) { + if (install && App.foreground() != null && + !(App.foreground() instanceof FlashActivity)) { + /* Only start flashing if there is a foreground activity and the + * user is not also flashing another module at the same time */ + App.foreground().startActivity(intent); + } else { + /* Or else we preset a notification notifying that we are done */ + PendingIntent pi = PendingIntent.getActivity(this, progress.hashCode(), intent, + PendingIntent.FLAG_UPDATE_CURRENT); + progress.dlDone(pi); + } } } catch (Exception e) { e.printStackTrace(); progress.dlFail(); } + removeNotification(progress); } private void processZip(InputStream in, OutputStream out, boolean inject) diff --git a/app/src/main/java/com/topjohnwu/magisk/components/UpdateCheckService.java b/app/src/main/java/com/topjohnwu/magisk/components/UpdateCheckService.java index d76738f13..79d6241a4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/UpdateCheckService.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/UpdateCheckService.java @@ -15,7 +15,7 @@ public class UpdateCheckService extends DelegateWorker { @NonNull @Override public ListenableWorker.Result doWork() { - if (App.self.foreground == null) { + if (App.foreground() == null) { Shell.getShell(); CheckUpdates.check(this::onCheckDone); } diff --git a/app/src/main/java/com/topjohnwu/magisk/uicomponents/ProgressNotification.java b/app/src/main/java/com/topjohnwu/magisk/uicomponents/ProgressNotification.java index fedd2d01f..19b1ddcd7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/uicomponents/ProgressNotification.java +++ b/app/src/main/java/com/topjohnwu/magisk/uicomponents/ProgressNotification.java @@ -1,6 +1,8 @@ package com.topjohnwu.magisk.uicomponents; import android.app.Notification; +import android.app.PendingIntent; +import android.content.Intent; import android.widget.Toast; import androidx.core.app.NotificationCompat; @@ -55,10 +57,17 @@ public class ProgressNotification implements DownloadProgressListener { } public void dlDone() { + dlDone(PendingIntent.getActivity(App.self, hashCode(), + new Intent(), PendingIntent.FLAG_UPDATE_CURRENT)); + } + + public void dlDone(PendingIntent intent) { builder.setProgress(0, 0, false) .setContentText(App.self.getString(R.string.download_complete)) .setSmallIcon(android.R.drawable.stat_sys_download_done) - .setOngoing(false); + .setContentIntent(intent) + .setOngoing(false) + .setAutoCancel(true); lastUpdate(); }