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 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;
}

View File

@ -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<ProgressNotification> 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();
});
}
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);
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 {
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) {
e.printStackTrace();
progress.dlFail();
}
removeNotification(progress);
}
private void processZip(InputStream in, OutputStream out, boolean inject)

View File

@ -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);
}

View File

@ -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();
}