From 646a10d9bfdf465c0e48214a760719b0e9c08ec2 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 29 Dec 2018 17:49:41 +0800 Subject: [PATCH] Use foreground service for downloading modules --- app/src/full/AndroidManifest.xml | 4 +- app/src/full/java/a/j.java | 4 +- .../java/com/topjohnwu/magisk/ClassMap.java | 2 + .../magisk/adapters/ReposAdapter.java | 21 ++++++-- .../components/ProgressNotification.java | 21 ++++++-- .../DownloadModuleService.java} | 52 ++++++++++++++----- .../topjohnwu/magisk/utils/DownloadApp.java | 4 +- app/src/full/res/values/strings.xml | 1 + .../topjohnwu/core/container/BaseModule.java | 40 +++++++++++--- .../com/topjohnwu/core/container/Module.java | 16 ++++++ .../com/topjohnwu/core/container/Repo.java | 26 ++++++++++ 11 files changed, 160 insertions(+), 31 deletions(-) rename app/src/full/java/com/topjohnwu/magisk/{utils/DownloadModule.java => services/DownloadModuleService.java} (59%) diff --git a/app/src/full/AndroidManifest.xml b/app/src/full/AndroidManifest.xml index 58fe76ab0..20dd8c3fd 100644 --- a/app/src/full/AndroidManifest.xml +++ b/app/src/full/AndroidManifest.xml @@ -6,7 +6,7 @@ - + + + - DownloadModule.exec((BaseActivity) context, repo, true)) + startDownload((BaseActivity) context, repo, true)) .setNeutralButton(R.string.download, (d, i) -> - DownloadModule.exec((BaseActivity) context, repo, false)) + startDownload((BaseActivity) context, repo, false)) .setNegativeButton(R.string.no_thanks, null) .show(); }); } + private void startDownload(BaseActivity activity, Repo repo, Boolean install) { + activity.runWithExternalRW(() -> { + Intent intent = new Intent(activity, ClassMap.get(DownloadModuleService.class)) + .putExtra("repo", repo).putExtra("install", install); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.startForegroundService(intent); + } else { + activity.startService(intent); + } + }); + } + public void notifyDBChanged() { if (repoCursor != null) repoCursor.close(); diff --git a/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java b/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java index 35b91457c..cf35a1948 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/ProgressNotification.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk.components; +import android.app.Notification; import android.widget.Toast; import com.topjohnwu.core.App; @@ -13,6 +14,7 @@ import androidx.core.app.NotificationManagerCompat; public class ProgressNotification implements DownloadProgressListener { private NotificationManagerCompat mgr; private NotificationCompat.Builder builder; + private Notification notification; private long prevTime; public ProgressNotification(String title) { @@ -35,12 +37,23 @@ public class ProgressNotification implements DownloadProgressListener { } } - public NotificationCompat.Builder getNotification() { + public NotificationCompat.Builder getNotificationBuilder() { return builder; } + public Notification getNotification() { + return notification; + } + public void update() { - mgr.notify(hashCode(), builder.build()); + notification = builder.build(); + mgr.notify(hashCode(), notification); + } + + private void lastUpdate() { + notification = builder.build(); + mgr.cancel(hashCode()); + mgr.notify(notification.hashCode(), notification); } public void dlDone() { @@ -48,7 +61,7 @@ public class ProgressNotification implements DownloadProgressListener { .setContentText(App.self.getString(R.string.download_complete)) .setSmallIcon(R.drawable.ic_check_circle) .setOngoing(false); - update(); + lastUpdate(); } public void dlFail() { @@ -56,7 +69,7 @@ public class ProgressNotification implements DownloadProgressListener { .setContentText(App.self.getString(R.string.download_file_error)) .setSmallIcon(R.drawable.ic_cancel) .setOngoing(false); - update(); + lastUpdate(); } public void dismiss() { diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java b/app/src/full/java/com/topjohnwu/magisk/services/DownloadModuleService.java similarity index 59% rename from app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java rename to app/src/full/java/com/topjohnwu/magisk/services/DownloadModuleService.java index ebf642467..7c7e25b0b 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/DownloadModule.java +++ b/app/src/full/java/com/topjohnwu/magisk/services/DownloadModuleService.java @@ -1,17 +1,20 @@ -package com.topjohnwu.magisk.utils; +package com.topjohnwu.magisk.services; +import android.app.Service; import android.content.Intent; import android.net.Uri; -import android.os.AsyncTask; +import android.os.IBinder; +import android.widget.Toast; -import com.topjohnwu.core.App; import com.topjohnwu.core.Const; import com.topjohnwu.core.container.Repo; +import com.topjohnwu.core.utils.Utils; import com.topjohnwu.magisk.ClassMap; import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.components.BaseActivity; +import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.ProgressNotification; import com.topjohnwu.net.Networking; +import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; import java.io.BufferedOutputStream; @@ -24,16 +27,38 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -public class DownloadModule { +import androidx.annotation.Nullable; - public static void exec(BaseActivity activity, Repo repo, boolean install) { - activity.runWithExternalRW(() -> AsyncTask.THREAD_POOL_EXECUTOR.execute( - () -> dlProcessInstall(repo, install))); +public class DownloadModuleService extends Service { + + private boolean running = false; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; } - private static void dlProcessInstall(Repo repo, boolean install) { + @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; + } + + 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()); try { InputStream in = Networking.get(repo.getZipUrl()) .setDownloadProgressListener(progress) @@ -41,13 +66,13 @@ public class DownloadModule { removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output))); if (install) { progress.dismiss(); - Intent intent = new Intent(App.self, ClassMap.get(FlashActivity.class)); + 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); - App.self.startActivity(intent); + startActivity(intent); } else { - progress.getNotification().setContentTitle(output.getName()); + progress.getNotificationBuilder().setContentTitle(output.getName()); progress.dlDone(); } } catch (Exception e) { @@ -56,7 +81,7 @@ public class DownloadModule { } } - private static void removeTopFolder(InputStream in, OutputStream out) throws IOException { + private void removeTopFolder(InputStream in, OutputStream out) throws IOException { try (ZipInputStream zin = new ZipInputStream(in); ZipOutputStream zout = new ZipOutputStream(out)) { ZipEntry entry; @@ -73,5 +98,4 @@ public class DownloadModule { } } } - } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java index 2c8274fde..4aa6cd123 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/DownloadApp.java @@ -65,7 +65,7 @@ public class DownloadApp { File patched = apk; App app = App.self; if (!App.self.getPackageName().equals(BuildConfig.APPLICATION_ID)) { - progress.getNotification() + progress.getNotificationBuilder() .setProgress(0, 0, true) .setContentTitle(app.getString(R.string.hide_manager_title)) .setContentText(""); @@ -89,7 +89,7 @@ public class DownloadApp { @Override public void onDownloadComplete(File apk, ProgressNotification progress) { App app = App.self; - progress.getNotification() + progress.getNotificationBuilder() .setProgress(0, 0, true) .setContentTitle(app.getString(R.string.restore_img_msg)) .setContentText(""); diff --git a/app/src/full/res/values/strings.xml b/app/src/full/res/values/strings.xml index 9e8492368..ac61e9790 100644 --- a/app/src/full/res/values/strings.xml +++ b/app/src/full/res/values/strings.xml @@ -126,6 +126,7 @@ Running environment setup… Downloading %1$s This feature will not work without permission to write external storage. + Download one module at a time. General diff --git a/core/src/main/java/com/topjohnwu/core/container/BaseModule.java b/core/src/main/java/com/topjohnwu/core/container/BaseModule.java index 167f84447..00ea53fb3 100644 --- a/core/src/main/java/com/topjohnwu/core/container/BaseModule.java +++ b/core/src/main/java/com/topjohnwu/core/container/BaseModule.java @@ -2,12 +2,14 @@ package com.topjohnwu.core.container; import android.content.ContentValues; import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; import java.util.List; import androidx.annotation.NonNull; -public abstract class BaseModule implements Comparable { +public abstract class BaseModule implements Comparable, Parcelable { private String mId, mName, mVersion, mAuthor, mDescription; private int mVersionCode = -1, minMagiskVersion = -1; @@ -26,6 +28,37 @@ public abstract class BaseModule implements Comparable { minMagiskVersion = c.getInt(c.getColumnIndex("minMagisk")); } + protected BaseModule(Parcel p) { + mId = p.readString(); + mName = p.readString(); + mVersion = p.readString(); + mAuthor = p.readString(); + mDescription = p.readString(); + mVersionCode = p.readInt(); + minMagiskVersion = p.readInt(); + } + + @Override + public int compareTo(@NonNull BaseModule module) { + return this.getName().toLowerCase().compareTo(module.getName().toLowerCase()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mId); + dest.writeString(mName); + dest.writeString(mVersion); + dest.writeString(mAuthor); + dest.writeString(mDescription); + dest.writeInt(mVersionCode); + dest.writeInt(minMagiskVersion); + } + private String nonNull(String s) { return s == null ? "" : s; } @@ -119,9 +152,4 @@ public abstract class BaseModule implements Comparable { public int getMinMagiskVersion() { return minMagiskVersion; } - - @Override - public int compareTo(@NonNull BaseModule module) { - return this.getName().toLowerCase().compareTo(module.getName().toLowerCase()); - } } diff --git a/core/src/main/java/com/topjohnwu/core/container/Module.java b/core/src/main/java/com/topjohnwu/core/container/Module.java index 48ff50ab4..406f26b72 100644 --- a/core/src/main/java/com/topjohnwu/core/container/Module.java +++ b/core/src/main/java/com/topjohnwu/core/container/Module.java @@ -1,5 +1,8 @@ package com.topjohnwu.core.container; +import android.os.Parcel; +import android.os.Parcelable; + import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.io.SuFile; @@ -32,6 +35,19 @@ public class Module extends BaseModule { mUpdated = mUpdateFile.exists(); } + public static final Parcelable.Creator CREATOR = new Creator() { + /* It won't be used at any place */ + @Override + public Module createFromParcel(Parcel source) { + return null; + } + + @Override + public Module[] newArray(int size) { + return null; + } + }; + public void createDisableFile() { mEnable = !mDisableFile.createNewFile(); } diff --git a/core/src/main/java/com/topjohnwu/core/container/Repo.java b/core/src/main/java/com/topjohnwu/core/container/Repo.java index 8db237a28..3ac31bdab 100644 --- a/core/src/main/java/com/topjohnwu/core/container/Repo.java +++ b/core/src/main/java/com/topjohnwu/core/container/Repo.java @@ -2,6 +2,8 @@ package com.topjohnwu.core.container; import android.content.ContentValues; import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; import com.topjohnwu.core.Const; import com.topjohnwu.core.utils.Logger; @@ -23,6 +25,30 @@ public class Repo extends BaseModule { mLastUpdate = new Date(c.getLong(c.getColumnIndex("last_update"))); } + public Repo(Parcel p) { + super(p); + mLastUpdate = new Date(p.readLong()); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public Repo createFromParcel(Parcel source) { + return new Repo(source); + } + + @Override + public Repo[] newArray(int size) { + return new Repo[size]; + } + }; + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(mLastUpdate.getTime()); + } + public void update() throws IllegalRepoException { String props[] = Utils.dlString(getPropUrl()).split("\\n"); try {