Drastically improve module download service

This commit is contained in:
topjohnwu 2019-04-10 02:00:48 -04:00
parent d9c58f307f
commit 6128c24f96
4 changed files with 81 additions and 30 deletions

View File

@ -33,7 +33,7 @@ public class App extends Application implements Application.ActivityLifecycleCal
public SharedPreferences prefs; public SharedPreferences prefs;
public MagiskDB mDB; public MagiskDB mDB;
public RepoDatabaseHelper repoDB; public RepoDatabaseHelper repoDB;
public BaseActivity foreground; private volatile BaseActivity foreground;
static { static {
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER | Shell.FLAG_USE_MAGISK_BUSYBOX); 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); LocaleManager.setLocale(this);
} }
public static BaseActivity foreground() {
return self.foreground;
}
@Override @Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {} 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) {} public void onActivityStarted(@NonNull Activity activity) {}
@Override @Override
public void onActivityResumed(@NonNull Activity activity) { public synchronized void onActivityResumed(@NonNull Activity activity) {
foreground = (BaseActivity) activity; foreground = (BaseActivity) activity;
} }
@Override @Override
public void onActivityPaused(@NonNull Activity activity) { public synchronized void onActivityPaused(@NonNull Activity activity) {
foreground = null; foreground = null;
} }

View File

@ -1,20 +1,20 @@
package com.topjohnwu.magisk.components; package com.topjohnwu.magisk.components;
import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.IBinder; import android.os.IBinder;
import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.ClassMap;
import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Repo; import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.uicomponents.Notifications;
import com.topjohnwu.magisk.uicomponents.ProgressNotification; import com.topjohnwu.magisk.uicomponents.ProgressNotification;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking; import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.ShellUtils;
@ -25,13 +25,15 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
public class DownloadModuleService extends Service { public class DownloadModuleService extends Service {
private boolean running = false; private List<ProgressNotification> notifications;
@Nullable @Nullable
@Override @Override
@ -39,46 +41,82 @@ public class DownloadModuleService extends Service {
return null; return null;
} }
@Override
public void onCreate() {
notifications = new ArrayList<>();
}
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { 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(() -> { Shell.EXECUTOR.execute(() -> {
Repo repo = intent.getParcelableExtra("repo"); Repo repo = intent.getParcelableExtra("repo");
boolean install = intent.getBooleanExtra("install", false); boolean install = intent.getBooleanExtra("install", false);
dlProcessInstall(repo, install); dlProcessInstall(repo, install);
stopSelf();
}); });
}
return START_REDELIVER_INTENT; 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) { private void dlProcessInstall(Repo repo, boolean install) {
File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename()); File output = new File(Const.EXTERNAL_PATH, repo.getDownloadFilename());
ProgressNotification progress = new ProgressNotification(output.getName()); ProgressNotification progress = new ProgressNotification(output.getName());
startForeground(progress.hashCode(), progress.getNotification()); addNotification(progress);
try { try {
InputStream in = Networking.get(repo.getZipUrl()) InputStream in = Networking.get(repo.getZipUrl())
.setDownloadProgressListener(progress) .setDownloadProgressListener(progress)
.execForInputStream().getResult(); .execForInputStream().getResult();
OutputStream out = new BufferedOutputStream(new FileOutputStream(output)); OutputStream out = new BufferedOutputStream(new FileOutputStream(output));
processZip(in, out, repo.isNewInstaller()); processZip(in, out, repo.isNewInstaller());
if (install) {
progress.dismiss();
Intent intent = new Intent(this, ClassMap.get(FlashActivity.class)); Intent intent = new Intent(this, ClassMap.get(FlashActivity.class));
intent.setData(Uri.fromFile(output)) intent.setData(Uri.fromFile(output))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP); .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
startActivity(intent); 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 { } else {
progress.dlDone(); /* 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) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
progress.dlFail(); progress.dlFail();
} }
removeNotification(progress);
} }
private void processZip(InputStream in, OutputStream out, boolean inject) private void processZip(InputStream in, OutputStream out, boolean inject)

View File

@ -15,7 +15,7 @@ public class UpdateCheckService extends DelegateWorker {
@NonNull @NonNull
@Override @Override
public ListenableWorker.Result doWork() { public ListenableWorker.Result doWork() {
if (App.self.foreground == null) { if (App.foreground() == null) {
Shell.getShell(); Shell.getShell();
CheckUpdates.check(this::onCheckDone); CheckUpdates.check(this::onCheckDone);
} }

View File

@ -1,6 +1,8 @@
package com.topjohnwu.magisk.uicomponents; package com.topjohnwu.magisk.uicomponents;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.widget.Toast; import android.widget.Toast;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
@ -55,10 +57,17 @@ public class ProgressNotification implements DownloadProgressListener {
} }
public void dlDone() { 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) builder.setProgress(0, 0, false)
.setContentText(App.self.getString(R.string.download_complete)) .setContentText(App.self.getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done) .setSmallIcon(android.R.drawable.stat_sys_download_done)
.setOngoing(false); .setContentIntent(intent)
.setOngoing(false)
.setAutoCancel(true);
lastUpdate(); lastUpdate();
} }