From 326eee8c8370163520ace3616ac87e1248f6b4d0 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 12 Jun 2019 03:29:38 -0700 Subject: [PATCH] Migrate a lot of classes to Kotlin --- .../magisk/ui/base/ActivityResultListener.kt | 7 - .../topjohnwu/magisk/ui/base/IBaseLeanback.kt | 11 -- .../magisk/ui/base/MagiskActivity.kt | 46 ++++-- .../magisk/ui/base/MagiskLeanbackActivity.kt | 64 -------- .../magisk/ui/module/ModulesFragment.kt | 10 +- .../magisk/ui/module/ReposFragment.kt | 18 ++- .../java/com/topjohnwu/magisk/utils/XList.kt | 7 +- .../topjohnwu/magisk/view/MarkDownWindow.java | 67 --------- .../topjohnwu/magisk/view/MarkDownWindow.kt | 54 +++++++ .../magisk/view/ProgressNotification.java | 85 ----------- .../magisk/view/ProgressNotification.kt | 73 ++++++++++ .../topjohnwu/magisk/view/SnackbarMaker.java | 48 ------ .../topjohnwu/magisk/view/SnackbarMaker.kt | 46 ++++++ .../view/dialogs/CustomAlertDialog.java | 137 ------------------ .../magisk/view/dialogs/CustomAlertDialog.kt | 113 +++++++++++++++ .../view/dialogs/FingerprintAuthDialog.java | 108 -------------- .../view/dialogs/FingerprintAuthDialog.kt | 88 +++++++++++ .../view/dialogs/InstallMethodDialog.java | 100 ------------- .../view/dialogs/InstallMethodDialog.kt | 90 ++++++++++++ .../view/dialogs/MagiskInstallDialog.java | 50 ------- .../view/dialogs/MagiskInstallDialog.kt | 45 ++++++ .../view/dialogs/ManagerInstallDialog.java | 28 ---- .../view/dialogs/ManagerInstallDialog.kt | 23 +++ .../magisk/view/dialogs/UninstallDialog.java | 61 -------- .../magisk/view/dialogs/UninstallDialog.kt | 58 ++++++++ 25 files changed, 649 insertions(+), 788 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/base/ActivityResultListener.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/base/IBaseLeanback.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskLeanbackActivity.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/ActivityResultListener.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/ActivityResultListener.kt deleted file mode 100644 index 16d963403..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/ActivityResultListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.topjohnwu.magisk.ui.base - -import android.content.Intent - -interface ActivityResultListener { - fun onActivityResult(resultCode: Int, data: Intent?) -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/IBaseLeanback.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/IBaseLeanback.kt deleted file mode 100644 index 8008284a4..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/IBaseLeanback.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.topjohnwu.magisk.ui.base - -import android.content.Intent - -interface IBaseLeanback { - - fun runWithExternalRW(callback: Runnable) - fun runWithPermissions(vararg permissions: String, callback: Runnable) - fun startActivityForResult(intent: Intent, requestCode: Int, listener: ActivityResultListener) - -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt index f70398d18..df6050c75 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/MagiskActivity.kt @@ -1,11 +1,13 @@ package com.topjohnwu.magisk.ui.base +import android.Manifest import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle import androidx.annotation.CallSuper import androidx.appcompat.app.AppCompatDelegate +import androidx.collection.SparseArrayCompat import androidx.core.net.toUri import androidx.databinding.ViewDataBinding import androidx.fragment.app.Fragment @@ -17,6 +19,7 @@ import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.ncapdevi.fragnav.FragNavController import com.ncapdevi.fragnav.FragNavTransactionOptions +import com.skoumal.teanity.view.TeanityActivity import com.skoumal.teanity.viewevents.ViewEvent import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.model.events.BackPressEvent @@ -28,16 +31,20 @@ import com.topjohnwu.magisk.model.navigation.Navigator import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder import com.topjohnwu.magisk.utils.LocaleManager import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.magisk.utils.set import timber.log.Timber import kotlin.reflect.KClass +typealias RequestCallback = MagiskActivity<*, *>.(Int, Intent?) -> Unit abstract class MagiskActivity : - MagiskLeanbackActivity(), FragNavController.RootFragmentListener, - Navigator, FragNavController.TransactionListener { + TeanityActivity(), FragNavController.RootFragmentListener, + Navigator, FragNavController.TransactionListener { override val numberOfRootFragments: Int get() = baseFragments.size override val baseFragments: List> = listOf() + private val resultCallbacks = SparseArrayCompat() + protected open val defaultPosition: Int = 0 @@ -188,19 +195,23 @@ abstract class MagiskActivity?, - token: PermissionToken? - ) = request.onShowRationale(permissions.orEmpty().map { it.name }) - }) - .check() + permissions: MutableList, + token: PermissionToken + ) = token.continuePermissionRequest() + }).check() + } + + fun withExternalRW(builder: PermissionRequestBuilder.() -> Unit) { + withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, builder = builder) } private fun FragNavTransactionOptions.Builder.customAnimations(options: MagiskAnimBuilder) = @@ -210,4 +221,21 @@ abstract class MagiskActivity : - TeanityActivity(), IBaseLeanback { - - private val resultListeners = SparseArrayCompat() - - @Deprecated("Permissions will be checked in a different streamlined way") - fun runWithExternalRW(callback: () -> Unit) = runWithExternalRW(Runnable { callback() }) - - @Deprecated("Permissions will be checked in a different streamlined way") - override fun runWithExternalRW(callback: Runnable) { - runWithPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, callback = callback) - } - - @Deprecated("Permissions will be checked in a different streamlined way") - override fun runWithPermissions(vararg permissions: String, callback: Runnable) { - Dexter.withActivity(this) - .withPermissions(*permissions) - .withListener(object : MultiplePermissionsListener { - override fun onPermissionsChecked(report: MultiplePermissionsReport?) { - if (report?.areAllPermissionsGranted() == true) { - Const.EXTERNAL_PATH.mkdirs() - callback.run() - } - } - - override fun onPermissionRationaleShouldBeShown( - permissions: MutableList?, - token: PermissionToken? - ) = Unit - }) - .check() - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - resultListeners.get(requestCode)?.apply { - resultListeners.remove(requestCode) - onActivityResult(resultCode, data) - } - } - - override fun startActivityForResult( - intent: Intent, - requestCode: Int, - listener: ActivityResultListener - ) { - resultListeners.put(requestCode, listener) - startActivityForResult(intent, requestCode) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt index 146e5fcd8..929afaf4d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt @@ -85,10 +85,12 @@ class ModulesFragment : MagiskFragment( } private fun selectFile() { - magiskActivity.runWithExternalRW { - val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.type = "application/zip" - startActivityForResult(intent, Const.ID.FETCH_ZIP) + magiskActivity.withExternalRW { + onSuccess { + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.type = "application/zip" + startActivityForResult(intent, Const.ID.FETCH_ZIP) + } } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt index 7cb14796f..06b808037 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt @@ -74,20 +74,22 @@ class ReposFragment : MagiskFragment(), } private fun openChangelog(item: Repo) { - MarkDownWindow.show(context, null, item.detailUrl) + MarkDownWindow.show(requireActivity(), null, item.detailUrl) } private fun installModule(item: Repo) { val context = magiskActivity fun download(install: Boolean) { - context.runWithExternalRW { - val intent = Intent(activity, ClassMap[DownloadModuleService::class.java]) - .putExtra("repo", item).putExtra("install", install) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) //hmm, service starts itself in foreground, this seems unnecessary - } else { - context.startService(intent) + context.withExternalRW { + onSuccess { + val intent = Intent(activity, ClassMap[DownloadModuleService::class.java]) + .putExtra("repo", item).putExtra("install", install) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt index fd4ddc2e5..6b065b573 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt @@ -1,5 +1,6 @@ package com.topjohnwu.magisk.utils +import androidx.collection.SparseArrayCompat import androidx.databinding.ObservableList import com.skoumal.teanity.extensions.subscribeK import com.skoumal.teanity.util.DiffObservableList @@ -76,4 +77,8 @@ fun ObservableList.copyNewInputInto( val addedValues = sender?.slice(positionStart until positionEnd).orEmpty() target.addAll(addedValues) } -}) \ No newline at end of file +}) + +operator fun SparseArrayCompat.set(key: Int, value: E) { + put(key, value) +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.java b/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.java deleted file mode 100644 index 8a7b4f244..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.topjohnwu.magisk.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; - -import androidx.appcompat.app.AlertDialog; - -import com.topjohnwu.magisk.R; -import com.topjohnwu.net.Networking; -import com.topjohnwu.net.ResponseListener; - -import java.io.InputStream; -import java.util.Scanner; - -import ru.noties.markwon.Markwon; -import ru.noties.markwon.html.HtmlPlugin; -import ru.noties.markwon.image.ImagesPlugin; -import ru.noties.markwon.image.svg.SvgPlugin; - -public class MarkDownWindow { - - public static void show(Context activity, String title, String url) { - Networking.get(url).getAsString(new Listener(activity, title)); - } - - public static void show(Context activity, String title, InputStream is) { - try (Scanner s = new Scanner(is, "UTF-8")) { - s.useDelimiter("\\A"); - new Listener(activity, title).onResponse(s.next()); - } - } - - static class Listener implements ResponseListener { - - Context activity; - String title; - - Listener(Context a, String t) { - activity = a; - title = t; - } - - @Override - public void onResponse(String md) { - Markwon markwon = Markwon.builder(activity) - .usePlugin(HtmlPlugin.create()) - .usePlugin(ImagesPlugin.create(activity)) - .usePlugin(SvgPlugin.create(activity.getResources())) - .build(); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setTitle(title); - View mv = LayoutInflater.from(activity).inflate(R.layout.markdown_window, null); - TextView tv = mv.findViewById(R.id.md_txt); - try { - markwon.setMarkdown(tv, md); - } catch (ExceptionInInitializerError e) { - //Nothing we can do about this error other than show error message - tv.setText(R.string.download_file_error); - } - alert.setView(mv); - alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss()); - alert.show(); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt b/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt new file mode 100644 index 000000000..6f5de3ab1 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/MarkDownWindow.kt @@ -0,0 +1,54 @@ +package com.topjohnwu.magisk.view + +import android.content.Context +import android.view.LayoutInflater +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import com.topjohnwu.magisk.R +import com.topjohnwu.net.Networking +import com.topjohnwu.net.ResponseListener +import ru.noties.markwon.Markwon +import ru.noties.markwon.html.HtmlPlugin +import ru.noties.markwon.image.ImagesPlugin +import ru.noties.markwon.image.svg.SvgPlugin +import java.io.InputStream +import java.util.* + +object MarkDownWindow { + + fun show(activity: Context, title: String?, url: String) { + Networking.get(url).getAsString(Listener(activity, title)) + } + + fun show(activity: Context, title: String?, input: InputStream) { + Scanner(input, "UTF-8").use { + it.useDelimiter("\\A") + Listener(activity, title).onResponse(it.next()) + } + } + + internal class Listener(var activity: Context, var title: String?) : ResponseListener { + + override fun onResponse(md: String) { + val markwon = Markwon.builder(activity) + .usePlugin(HtmlPlugin.create()) + .usePlugin(ImagesPlugin.create(activity)) + .usePlugin(SvgPlugin.create(activity.resources)) + .build() + val alert = AlertDialog.Builder(activity) + alert.setTitle(title) + val mv = LayoutInflater.from(activity).inflate(R.layout.markdown_window, null) + val tv = mv.findViewById(R.id.md_txt) + try { + markwon.setMarkdown(tv, md) + } catch (e: ExceptionInInitializerError) { + //Nothing we can do about this error other than show error message + tv.setText(R.string.download_file_error) + } + + alert.setView(mv) + alert.setNegativeButton(R.string.close) { dialog, _ -> dialog.dismiss() } + alert.show() + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.java b/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.java deleted file mode 100644 index 282b66b97..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.topjohnwu.magisk.view; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Intent; -import android.widget.Toast; - -import androidx.core.app.NotificationCompat; - -import com.topjohnwu.magisk.App; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.net.DownloadProgressListener; - -public class ProgressNotification implements DownloadProgressListener { - - private NotificationCompat.Builder builder; - private Notification notification; - private long prevTime; - - public ProgressNotification(String title) { - builder = Notifications.progress(title); - prevTime = System.currentTimeMillis(); - update(); - Utils.INSTANCE.toast(App.self.getString(R.string.downloading_toast, title), Toast.LENGTH_SHORT); - } - - @Override - public void onProgress(long bytesDownloaded, long totalBytes) { - long cur = System.currentTimeMillis(); - if (cur - prevTime >= 1000) { - prevTime = cur; - int progress = (int) (bytesDownloaded * 100 / totalBytes); - builder.setProgress(100, progress, false); - builder.setContentText(progress + "%"); - update(); - } - } - - public NotificationCompat.Builder getNotificationBuilder() { - return builder; - } - - public Notification getNotification() { - return notification; - } - - public void update() { - notification = builder.build(); - Notifications.mgr.notify(hashCode(), notification); - } - - private void lastUpdate() { - notification = builder.build(); - Notifications.mgr.cancel(hashCode()); - Notifications.mgr.notify(notification.hashCode(), notification); - } - - 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) - .setContentIntent(intent) - .setOngoing(false) - .setAutoCancel(true); - lastUpdate(); - } - - public void dlFail() { - builder.setProgress(0, 0, false) - .setContentText(App.self.getString(R.string.download_file_error)) - .setSmallIcon(android.R.drawable.stat_notify_error) - .setOngoing(false); - lastUpdate(); - } - - public void dismiss() { - Notifications.mgr.cancel(hashCode()); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.kt b/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.kt new file mode 100644 index 000000000..8f8460c09 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/ProgressNotification.kt @@ -0,0 +1,73 @@ +package com.topjohnwu.magisk.view + +import android.app.Notification +import android.app.PendingIntent +import android.content.Intent +import android.widget.Toast + +import androidx.core.app.NotificationCompat + +import com.topjohnwu.magisk.App +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.net.DownloadProgressListener + +class ProgressNotification(title: String) : DownloadProgressListener { + + val notificationBuilder: NotificationCompat.Builder = Notifications.progress(title) + lateinit var notification: Notification + private set + private var prevTime: Long = 0 + + init { + prevTime = System.currentTimeMillis() + update() + Utils.toast(App.self.getString(R.string.downloading_toast, title), Toast.LENGTH_SHORT) + } + + override fun onProgress(bytesDownloaded: Long, totalBytes: Long) { + val cur = System.currentTimeMillis() + if (cur - prevTime >= 1000) { + prevTime = cur + val progress = (bytesDownloaded * 100 / totalBytes).toInt() + notificationBuilder.setProgress(100, progress, false) + notificationBuilder.setContentText("$progress%") + update() + } + } + + fun update() { + notification = notificationBuilder.build() + Notifications.mgr.notify(hashCode(), notification) + } + + private fun lastUpdate() { + Notifications.mgr.cancel(hashCode()) + notification = notificationBuilder.build().apply { + Notifications.mgr.notify(hashCode(), this) + } + } + + fun dlDone(intent: PendingIntent = PendingIntent.getActivity(App.self, hashCode(), + Intent(), PendingIntent.FLAG_UPDATE_CURRENT)) { + notificationBuilder.setProgress(0, 0, false) + .setContentText(App.self.getString(R.string.download_complete)) + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setContentIntent(intent) + .setOngoing(false) + .setAutoCancel(true) + lastUpdate() + } + + fun dlFail() { + notificationBuilder.setProgress(0, 0, false) + .setContentText(App.self.getString(R.string.download_file_error)) + .setSmallIcon(android.R.drawable.stat_notify_error) + .setOngoing(false) + lastUpdate() + } + + fun dismiss() { + Notifications.mgr.cancel(hashCode()) + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.java b/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.java deleted file mode 100644 index 5884824e1..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.topjohnwu.magisk.view; - -import android.app.Activity; -import android.net.Uri; -import android.view.View; -import android.widget.TextView; - -import androidx.annotation.StringRes; - -import com.google.android.material.snackbar.Snackbar; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.XAndroidKt; - -public class SnackbarMaker { - - public static Snackbar make(Activity activity, CharSequence text, int duration) { - View view = activity.findViewById(android.R.id.content); - return make(view, text, duration); - } - - public static Snackbar make(Activity activity, @StringRes int resId, int duration) { - return make(activity, activity.getString(resId), duration); - } - - public static Snackbar make(View view, CharSequence text, int duration) { - Snackbar snack = Snackbar.make(view, text, duration); - setup(snack); - return snack; - } - - public static Snackbar make(View view, @StringRes int resId, int duration) { - Snackbar snack = Snackbar.make(view, resId, duration); - setup(snack); - return snack; - } - - private static void setup(Snackbar snack) { - TextView text = snack.getView().findViewById(com.google.android.material.R.id.snackbar_text); - text.setMaxLines(Integer.MAX_VALUE); - } - - public static void showUri(Activity activity, Uri uri) { - make(activity, activity.getString(R.string.internal_storage, - "/Download/" + XAndroidKt.getFileName(uri)), - Snackbar.LENGTH_LONG) - .setAction(R.string.ok, (v)->{}).show(); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.kt b/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.kt new file mode 100644 index 000000000..7dd57e947 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/SnackbarMaker.kt @@ -0,0 +1,46 @@ +package com.topjohnwu.magisk.view + +import android.app.Activity +import android.net.Uri +import android.view.View +import android.widget.TextView +import androidx.annotation.StringRes +import com.google.android.material.snackbar.Snackbar +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.utils.fileName + +object SnackbarMaker { + + fun make(activity: Activity, text: CharSequence, duration: Int): Snackbar { + val view = activity.findViewById(android.R.id.content) + return make(view, text, duration) + } + + fun make(activity: Activity, @StringRes resId: Int, duration: Int): Snackbar { + return make(activity, activity.getString(resId), duration) + } + + fun make(view: View, text: CharSequence, duration: Int): Snackbar { + val snack = Snackbar.make(view, text, duration) + setup(snack) + return snack + } + + fun make(view: View, @StringRes resId: Int, duration: Int): Snackbar { + val snack = Snackbar.make(view, resId, duration) + setup(snack) + return snack + } + + private fun setup(snack: Snackbar) { + val text = snack.view.findViewById(com.google.android.material.R.id.snackbar_text) + text.maxLines = Integer.MAX_VALUE + } + + fun showUri(activity: Activity, uri: Uri) { + make(activity, activity.getString(R.string.internal_storage, + "/Download/" + uri.fileName), + Snackbar.LENGTH_LONG) + .setAction(R.string.ok) { }.show() + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java deleted file mode 100644 index 2dd8a501c..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.content.Context; -import android.content.DialogInterface; -import android.view.LayoutInflater; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.annotation.StyleRes; -import androidx.appcompat.app.AlertDialog; - -import com.topjohnwu.magisk.databinding.AlertDialogBinding; - -public class CustomAlertDialog extends AlertDialog.Builder { - - private DialogInterface.OnClickListener positiveListener; - private DialogInterface.OnClickListener negativeListener; - private DialogInterface.OnClickListener neutralListener; - - protected AlertDialog dialog; - protected AlertDialogBinding binding; - - { - binding = AlertDialogBinding.inflate(LayoutInflater.from(getContext())); - super.setView(binding.getRoot()); - binding.message.setVisibility(View.GONE); - binding.negative.setVisibility(View.GONE); - binding.positive.setVisibility(View.GONE); - binding.neutral.setVisibility(View.GONE); - binding.buttonPanel.setVisibility(View.GONE); - } - - public CustomAlertDialog(@NonNull Context context) { - super(context); - } - - public CustomAlertDialog(@NonNull Context context, @StyleRes int themeResId) { - super(context, themeResId); - } - - @Override - public CustomAlertDialog setView(int layoutResId) { return this; } - - @Override - public CustomAlertDialog setView(View view) { return this; } - - @Override - public CustomAlertDialog setMessage(@Nullable CharSequence message) { - binding.message.setVisibility(View.VISIBLE); - binding.message.setText(message); - return this; - } - - @Override - public CustomAlertDialog setMessage(@StringRes int messageId) { - return setMessage(getContext().getString(messageId)); - } - - @Override - public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) { - binding.buttonPanel.setVisibility(View.VISIBLE); - binding.positive.setVisibility(View.VISIBLE); - binding.positive.setText(text); - positiveListener = listener; - binding.positive.setOnClickListener(v -> { - if (positiveListener != null) { - positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE); - } - dialog.dismiss(); - }); - return this; - } - - @Override - public CustomAlertDialog setPositiveButton(@StringRes int textId, DialogInterface.OnClickListener listener) { - return setPositiveButton(getContext().getString(textId), listener); - } - - @Override - public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) { - binding.buttonPanel.setVisibility(View.VISIBLE); - binding.negative.setVisibility(View.VISIBLE); - binding.negative.setText(text); - negativeListener = listener; - binding.negative.setOnClickListener(v -> { - if (negativeListener != null) { - negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); - } - dialog.dismiss(); - }); - return this; - } - - @Override - public CustomAlertDialog setNegativeButton(@StringRes int textId, DialogInterface.OnClickListener listener) { - return setNegativeButton(getContext().getString(textId), listener); - } - - @Override - public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) { - binding.buttonPanel.setVisibility(View.VISIBLE); - binding.neutral.setVisibility(View.VISIBLE); - binding.neutral.setText(text); - neutralListener = listener; - binding.neutral.setOnClickListener(v -> { - if (neutralListener != null) { - neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL); - } - dialog.dismiss(); - }); - return this; - } - - @Override - public CustomAlertDialog setNeutralButton(@StringRes int textId, DialogInterface.OnClickListener listener) { - return setNeutralButton(getContext().getString(textId), listener); - } - - @Override - public AlertDialog create() { - dialog = super.create(); - return dialog; - } - - @Override - public AlertDialog show() { - create(); - dialog.show(); - return dialog; - } - - public void dismiss() { - dialog.dismiss(); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.kt new file mode 100644 index 000000000..bce39bba8 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/CustomAlertDialog.kt @@ -0,0 +1,113 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.content.Context +import android.content.DialogInterface +import android.view.LayoutInflater +import android.view.View +import androidx.annotation.StringRes +import androidx.annotation.StyleRes +import androidx.appcompat.app.AlertDialog + +import com.topjohnwu.magisk.databinding.AlertDialogBinding + +open class CustomAlertDialog : AlertDialog.Builder { + + private var positiveListener: DialogInterface.OnClickListener? = null + private var negativeListener: DialogInterface.OnClickListener? = null + private var neutralListener: DialogInterface.OnClickListener? = null + + protected var dialog: AlertDialog? = null + protected var binding: AlertDialogBinding = + AlertDialogBinding.inflate(LayoutInflater.from(context)) + + init { + super.setView(binding.root) + binding.message.visibility = View.GONE + binding.negative.visibility = View.GONE + binding.positive.visibility = View.GONE + binding.neutral.visibility = View.GONE + binding.buttonPanel.visibility = View.GONE + } + + constructor(context: Context) : super(context) + + constructor(context: Context, @StyleRes themeResId: Int) : super(context, themeResId) + + override fun setView(layoutResId: Int): CustomAlertDialog { + return this + } + + override fun setView(view: View): CustomAlertDialog { + return this + } + + override fun setMessage(message: CharSequence?): CustomAlertDialog { + binding.message.visibility = View.VISIBLE + binding.message.text = message + return this + } + + override fun setMessage(@StringRes messageId: Int): CustomAlertDialog { + return setMessage(context.getString(messageId)) + } + + override fun setPositiveButton(text: CharSequence, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + binding.buttonPanel.visibility = View.VISIBLE + binding.positive.visibility = View.VISIBLE + binding.positive.text = text + positiveListener = listener + binding.positive.setOnClickListener { + positiveListener?.onClick(dialog, DialogInterface.BUTTON_POSITIVE) + dialog?.dismiss() + } + return this + } + + override fun setPositiveButton(@StringRes textId: Int, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + return setPositiveButton(context.getString(textId), listener) + } + + override fun setNegativeButton(text: CharSequence, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + binding.buttonPanel.visibility = View.VISIBLE + binding.negative.visibility = View.VISIBLE + binding.negative.text = text + negativeListener = listener + binding.negative.setOnClickListener { + negativeListener?.onClick(dialog, DialogInterface.BUTTON_NEGATIVE) + dialog?.dismiss() + } + return this + } + + override fun setNegativeButton(@StringRes textId: Int, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + return setNegativeButton(context.getString(textId), listener) + } + + override fun setNeutralButton(text: CharSequence, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + binding.buttonPanel.visibility = View.VISIBLE + binding.neutral.visibility = View.VISIBLE + binding.neutral.text = text + neutralListener = listener + binding.neutral.setOnClickListener { + neutralListener?.onClick(dialog, DialogInterface.BUTTON_NEUTRAL) + dialog?.dismiss() + } + return this + } + + override fun setNeutralButton(@StringRes textId: Int, listener: DialogInterface.OnClickListener?): CustomAlertDialog { + return setNeutralButton(context.getString(textId), listener) + } + + override fun create(): AlertDialog { + return super.create().apply { dialog = this } + } + + override fun show(): AlertDialog { + return create().apply { show() } + } + + fun dismiss() { + dialog?.dismiss() + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java deleted file mode 100644 index e429b80bf..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.hardware.fingerprint.FingerprintManager; -import android.os.Build; -import android.view.Gravity; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; - -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.FingerprintHelper; -import com.topjohnwu.magisk.utils.Utils; - -@TargetApi(Build.VERSION_CODES.M) -public class FingerprintAuthDialog extends CustomAlertDialog { - - private final Runnable callback; - @Nullable - private Runnable failureCallback; - private DialogFingerprintHelper helper; - - public FingerprintAuthDialog(@NonNull Activity activity, @NonNull Runnable onSuccess) { - super(activity); - callback = onSuccess; - Drawable fingerprint = activity.getResources().getDrawable(R.drawable.ic_fingerprint); - fingerprint.setBounds(0, 0, Utils.INSTANCE.dpInPx(50), Utils.INSTANCE.dpInPx(50)); - Resources.Theme theme = activity.getTheme(); - TypedArray ta = theme.obtainStyledAttributes(new int[] {R.attr.imageColorTint}); - fingerprint.setTint(ta.getColor(0, Color.GRAY)); - ta.recycle(); - binding.message.setCompoundDrawables(null, null, null, fingerprint); - binding.message.setCompoundDrawablePadding(Utils.INSTANCE.dpInPx(20)); - binding.message.setGravity(Gravity.CENTER); - setMessage(R.string.auth_fingerprint); - setNegativeButton(R.string.close, (d, w) -> { - helper.cancel(); - if (failureCallback != null) { - failureCallback.run(); - } - }); - setOnCancelListener(d -> { - helper.cancel(); - if (failureCallback != null) { - failureCallback.run(); - } - }); - try { - helper = new DialogFingerprintHelper(); - } catch (Exception ignored) { - ignored.printStackTrace(); - } - } - - public FingerprintAuthDialog(@NonNull Activity activity, @NonNull Runnable onSuccess, @NonNull Runnable onFailure) { - this(activity, onSuccess); - failureCallback = onFailure; - } - - @Override - public AlertDialog show() { - create(); - if (helper == null) { - dialog.dismiss(); - Utils.INSTANCE.toast(R.string.auth_fail, Toast.LENGTH_SHORT); - } else { - helper.authenticate(); - dialog.show(); - } - return dialog; - } - - class DialogFingerprintHelper extends FingerprintHelper { - - DialogFingerprintHelper() throws Exception {} - - @Override - public void onAuthenticationError(int errorCode, CharSequence errString) { - binding.message.setTextColor(Color.RED); - binding.message.setText(errString); - } - - @Override - public void onAuthenticationHelp(int helpCode, CharSequence helpString) { - binding.message.setTextColor(Color.RED); - binding.message.setText(helpString); - } - - @Override - public void onAuthenticationFailed() { - binding.message.setTextColor(Color.RED); - binding.message.setText(R.string.auth_fail); - } - - @Override - public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { - dismiss(); - callback.run(); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt new file mode 100644 index 000000000..e11b5a6bf --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/FingerprintAuthDialog.kt @@ -0,0 +1,88 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.annotation.TargetApi +import android.app.Activity +import android.graphics.Color +import android.hardware.fingerprint.FingerprintManager +import android.os.Build +import android.view.Gravity +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.utils.FingerprintHelper +import com.topjohnwu.magisk.utils.Utils + +@TargetApi(Build.VERSION_CODES.M) +class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit) + : CustomAlertDialog(activity) { + + private var failureCallback: (() -> Unit)? = null + private var helper: DialogFingerprintHelper? = null + + init { + val fingerprint = ContextCompat.getDrawable(activity, R.drawable.ic_fingerprint) + fingerprint?.setBounds(0, 0, Utils.dpInPx(50), Utils.dpInPx(50)) + val theme = activity.theme + val ta = theme.obtainStyledAttributes(intArrayOf(R.attr.imageColorTint)) + fingerprint?.setTint(ta.getColor(0, Color.GRAY)) + ta.recycle() + binding.message.setCompoundDrawables(null, null, null, fingerprint) + binding.message.compoundDrawablePadding = Utils.dpInPx(20) + binding.message.gravity = Gravity.CENTER + setMessage(R.string.auth_fingerprint) + setNegativeButton(R.string.close) { _, _ -> + helper?.cancel() + failureCallback?.invoke() + } + setOnCancelListener { + helper?.cancel() + failureCallback?.invoke() + } + runCatching { + helper = DialogFingerprintHelper() + } + + } + + constructor(activity: Activity, onSuccess: () -> Unit, onFailure: () -> Unit) + : this(activity, onSuccess) { + failureCallback = onFailure + } + + override fun show(): AlertDialog { + return create().apply { + if (helper == null) { + dismiss() + Utils.toast(R.string.auth_fail, Toast.LENGTH_SHORT) + } else { + helper?.authenticate() + show() + } + } + } + + internal inner class DialogFingerprintHelper @Throws(Exception::class) + constructor() : FingerprintHelper() { + + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + binding.message.setTextColor(Color.RED) + binding.message.text = errString + } + + override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) { + binding.message.setTextColor(Color.RED) + binding.message.text = helpString + } + + override fun onAuthenticationFailed() { + binding.message.setTextColor(Color.RED) + binding.message.setText(R.string.auth_fail) + } + + override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { + dismiss() + callback() + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.java deleted file mode 100644 index d88cf15cb..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.app.Activity; -import android.content.Intent; -import android.widget.Toast; - -import androidx.appcompat.app.AlertDialog; - -import com.google.android.material.snackbar.Snackbar; -import com.topjohnwu.magisk.ClassMap; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Info; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.ui.base.IBaseLeanback; -import com.topjohnwu.magisk.ui.flash.FlashActivity; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.view.ProgressNotification; -import com.topjohnwu.magisk.view.SnackbarMaker; -import com.topjohnwu.net.Networking; - -import java.io.File; -import java.util.List; - -class InstallMethodDialog extends AlertDialog.Builder { - - InstallMethodDialog(Ctxt activity, List options) { - super(activity); - setTitle(R.string.select_method); - setItems(options.toArray(new String[0]), (dialog, idx) -> { - Intent intent; - switch (idx) { - case 1: - patchBoot(activity); - break; - case 0: - downloadOnly(activity); - break; - case 2: - intent = new Intent(activity, ClassMap.get(FlashActivity.class)) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK); - activity.startActivity(intent); - break; - case 3: - installInactiveSlot(activity); - break; - default: - } - }); - } - - private void patchBoot(Ctxt activity) { - activity.runWithExternalRW(() -> { - Utils.INSTANCE.toast(R.string.patch_file_msg, Toast.LENGTH_LONG); - Intent intent = new Intent(Intent.ACTION_GET_CONTENT) - .setType("*/*") - .addCategory(Intent.CATEGORY_OPENABLE); - activity.startActivityForResult(intent, Const.ID.SELECT_BOOT, - (resultCode, data) -> { - if (resultCode == Activity.RESULT_OK && data != null) { - Intent i = new Intent(activity, ClassMap.get(FlashActivity.class)) - .setData(data.getData()) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_FILE); - activity.startActivity(i); - } - }); - }); - } - - private void downloadOnly(Ctxt activity) { - activity.runWithExternalRW(() -> { - String filename = Utils.INSTANCE.fmt("Magisk-v%s(%d).zip", - Info.remoteMagiskVersionString, Info.remoteMagiskVersionCode); - File zip = new File(Const.EXTERNAL_PATH, filename); - ProgressNotification progress = new ProgressNotification(filename); - Networking.get(Info.magiskLink) - .setDownloadProgressListener(progress) - .setErrorHandler((conn, e) -> progress.dlFail()) - .getAsFile(zip, f -> { - progress.dlDone(); - SnackbarMaker.make(activity, - activity.getString(R.string.internal_storage, "/Download/" + filename), - Snackbar.LENGTH_LONG).show(); - }); - }); - } - - private void installInactiveSlot(Ctxt activity) { - new CustomAlertDialog(activity) - .setTitle(R.string.warning) - .setMessage(R.string.install_inactive_slot_msg) - .setCancelable(true) - .setPositiveButton(R.string.yes, (d, i) -> { - Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class)) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT); - activity.startActivity(intent); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt new file mode 100644 index 000000000..b6f649ea6 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/InstallMethodDialog.kt @@ -0,0 +1,90 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.app.Activity +import android.content.Intent +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import com.google.android.material.snackbar.Snackbar +import com.topjohnwu.magisk.ClassMap +import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.Info +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.ui.base.MagiskActivity +import com.topjohnwu.magisk.ui.flash.FlashActivity +import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.magisk.view.ProgressNotification +import com.topjohnwu.magisk.view.SnackbarMaker +import com.topjohnwu.net.Networking +import java.io.File + +internal class InstallMethodDialog(activity: MagiskActivity<*, *>, options: List) : AlertDialog.Builder(activity) { + + init { + setTitle(R.string.select_method) + setItems(options.toTypedArray()) { _, idx -> + when (idx) { + 0 -> downloadOnly(activity) + 1 -> patchBoot(activity) + 2 -> { + val intent = Intent(activity, ClassMap[FlashActivity::class.java]) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK) + activity.startActivity(intent) + } + 3 -> installInactiveSlot(activity) + } + } + } + + private fun patchBoot(activity: MagiskActivity<*, *>) { + activity.withExternalRW { + onSuccess { + Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG) + val intent = Intent(Intent.ACTION_GET_CONTENT) + .setType("*/*") + .addCategory(Intent.CATEGORY_OPENABLE) + activity.startActivityForResult(intent, Const.ID.SELECT_BOOT) { resultCode, data -> + if (resultCode == Activity.RESULT_OK && data != null) { + val i = Intent(this, ClassMap[FlashActivity::class.java]) + .setData(data.data) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_FILE) + startActivity(i) + } + } + } + } + } + + private fun downloadOnly(activity: MagiskActivity<*, *>) { + activity.withExternalRW { + onSuccess { + val filename = "Magisk-v${Info.remoteMagiskVersionString}" + + "(${Info.remoteMagiskVersionCode}).zip" + val zip = File(Const.EXTERNAL_PATH, filename) + val progress = ProgressNotification(filename) + Networking.get(Info.magiskLink) + .setDownloadProgressListener(progress) + .setErrorHandler { _, _ -> progress.dlFail() } + .getAsFile(zip) { + progress.dlDone() + SnackbarMaker.make(activity, + activity.getString(R.string.internal_storage, "/Download/$filename"), + Snackbar.LENGTH_LONG).show() + } + } + } + } + + private fun installInactiveSlot(activity: MagiskActivity<*, *>) { + CustomAlertDialog(activity) + .setTitle(R.string.warning) + .setMessage(R.string.install_inactive_slot_msg) + .setCancelable(true) + .setPositiveButton(R.string.yes) { _, _ -> + val intent = Intent(activity, ClassMap[FlashActivity::class.java]) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT) + activity.startActivity(intent) + } + .setNegativeButton(R.string.no_thanks, null) + .show() + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.java deleted file mode 100644 index 6426162b3..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.app.Activity; -import android.net.Uri; -import android.text.TextUtils; - -import com.topjohnwu.magisk.Info; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.ui.base.IBaseLeanback; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.view.MarkDownWindow; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; - -import java.util.ArrayList; -import java.util.List; - -public class MagiskInstallDialog extends CustomAlertDialog { - public MagiskInstallDialog(Ctxt a) { - super(a); - String filename = Utils.INSTANCE.fmt("Magisk-v%s(%d).zip", - Info.remoteMagiskVersionString, Info.remoteMagiskVersionCode); - setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk))); - setMessage(a.getString(R.string.repo_install_msg, filename)); - setCancelable(true); - setPositiveButton(R.string.install, (d, i) -> { - List options = new ArrayList<>(); - options.add(a.getString(R.string.download_zip_only)); - options.add(a.getString(R.string.select_patch_file)); - if (Shell.rootAccess()) { - options.add(a.getString(R.string.direct_install)); - String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update"); - if (!s.isEmpty() && Boolean.parseBoolean(s)) { - options.add(a.getString(R.string.install_inactive_slot)); - } - } - new InstallMethodDialog(a, options).show(); - }); - if (!TextUtils.isEmpty(Info.magiskNoteLink)) { - setNeutralButton(R.string.release_notes, (d, i) -> { - if (Info.magiskNoteLink.contains("forum.xda-developers")) { - // Open forum links in browser - Utils.INSTANCE.openLink(a, Uri.parse(Info.magiskNoteLink)); - } else { - MarkDownWindow.show(a, null, Info.magiskNoteLink); - } - }); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.kt new file mode 100644 index 000000000..395ff1938 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/MagiskInstallDialog.kt @@ -0,0 +1,45 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.net.Uri +import android.text.TextUtils +import com.topjohnwu.magisk.Info +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.ui.base.MagiskActivity +import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.magisk.view.MarkDownWindow +import com.topjohnwu.superuser.Shell +import com.topjohnwu.superuser.ShellUtils +import java.util.* + +class MagiskInstallDialog(a: MagiskActivity<*, *>) : CustomAlertDialog(a) { + init { + val filename = "Magisk v${Info.remoteMagiskVersionString}" + + "(${Info.remoteMagiskVersionCode})" + setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.magisk))) + setMessage(a.getString(R.string.repo_install_msg, filename)) + setCancelable(true) + setPositiveButton(R.string.install) { _, _ -> + val options = ArrayList() + options.add(a.getString(R.string.download_zip_only)) + options.add(a.getString(R.string.select_patch_file)) + if (Shell.rootAccess()) { + options.add(a.getString(R.string.direct_install)) + val s = ShellUtils.fastCmd("grep_prop ro.build.ab_update") + if (s.isNotEmpty() && s.toBoolean()) { + options.add(a.getString(R.string.install_inactive_slot)) + } + } + InstallMethodDialog(a, options).show() + } + if (!TextUtils.isEmpty(Info.magiskNoteLink)) { + setNeutralButton(R.string.release_notes) { _, _ -> + if (Info.magiskNoteLink.contains("forum.xda-developers")) { + // Open forum links in browser + Utils.openLink(a, Uri.parse(Info.magiskNoteLink)) + } else { + MarkDownWindow.show(a, null, Info.magiskNoteLink) + } + } + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.java deleted file mode 100644 index 80828bfd4..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.app.Activity; -import android.text.TextUtils; - -import androidx.annotation.NonNull; - -import com.topjohnwu.magisk.Info; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.DownloadApp; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.view.MarkDownWindow; - -public class ManagerInstallDialog extends CustomAlertDialog { - - public ManagerInstallDialog(@NonNull Activity a) { - super(a); - String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)", - Info.remoteManagerVersionString, Info.remoteManagerVersionCode); - setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name))); - setMessage(a.getString(R.string.repo_install_msg, name)); - setCancelable(true); - setPositiveButton(R.string.install, (d, i) -> DownloadApp.upgrade(name)); - if (!TextUtils.isEmpty(Info.managerNoteLink)) { - setNeutralButton(R.string.app_changelog, (d, i) -> MarkDownWindow.show(a, null, Info.managerNoteLink)); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt new file mode 100644 index 000000000..db5a2250e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt @@ -0,0 +1,23 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.app.Activity +import com.topjohnwu.magisk.Info +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.utils.DownloadApp +import com.topjohnwu.magisk.view.MarkDownWindow + +class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) { + + init { + val name = "MagiskManager v${Info.remoteManagerVersionString}" + + "(${Info.remoteManagerVersionCode})" + setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name))) + setMessage(a.getString(R.string.repo_install_msg, name)) + setCancelable(true) + setPositiveButton(R.string.install) { _, _ -> DownloadApp.upgrade(name) } + if (Info.managerNoteLink.isNotEmpty()) { + setNeutralButton(R.string.app_changelog) { _, _ -> + MarkDownWindow.show(a, null, Info.managerNoteLink) } + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.java deleted file mode 100644 index 53892f0d5..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.topjohnwu.magisk.view.dialogs; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.text.TextUtils; -import android.widget.Toast; - -import androidx.annotation.NonNull; - -import com.topjohnwu.magisk.ClassMap; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.Info; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.ui.flash.FlashActivity; -import com.topjohnwu.magisk.utils.Utils; -import com.topjohnwu.magisk.view.ProgressNotification; -import com.topjohnwu.net.Networking; -import com.topjohnwu.superuser.Shell; - -import java.io.File; - -public class UninstallDialog extends CustomAlertDialog { - - public UninstallDialog(@NonNull Activity activity) { - super(activity); - setTitle(R.string.uninstall_magisk_title); - setMessage(R.string.uninstall_magisk_msg); - setNeutralButton(R.string.restore_img, (d, i) -> { - ProgressDialog dialog = ProgressDialog.show(activity, - activity.getString(R.string.restore_img), - activity.getString(R.string.restore_img_msg)); - Shell.su("restore_imgs").submit(result -> { - dialog.cancel(); - if (result.isSuccess()) { - Utils.INSTANCE.toast(R.string.restore_done, Toast.LENGTH_SHORT); - } else { - Utils.INSTANCE.toast(R.string.restore_fail, Toast.LENGTH_LONG); - } - }); - }); - if (!TextUtils.isEmpty(Info.uninstallerLink)) { - setPositiveButton(R.string.complete_uninstall, (d, i) -> { - File zip = new File(activity.getFilesDir(), "uninstaller.zip"); - ProgressNotification progress = new ProgressNotification(zip.getName()); - Networking.get(Info.uninstallerLink) - .setDownloadProgressListener(progress) - .setErrorHandler(((conn, e) -> progress.dlFail())) - .getAsFile(zip, f -> { - progress.dismiss(); - Intent intent = new Intent(activity, ClassMap.get(FlashActivity.class)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .setData(Uri.fromFile(f)) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL); - activity.startActivity(intent); - }); - }); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.kt new file mode 100644 index 000000000..e49698c1d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/UninstallDialog.kt @@ -0,0 +1,58 @@ +package com.topjohnwu.magisk.view.dialogs + +import android.app.Activity +import android.app.ProgressDialog +import android.content.Intent +import android.net.Uri +import android.text.TextUtils +import android.widget.Toast + +import com.topjohnwu.magisk.ClassMap +import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.Info +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.ui.flash.FlashActivity +import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.magisk.view.ProgressNotification +import com.topjohnwu.net.Networking +import com.topjohnwu.superuser.Shell + +import java.io.File + +class UninstallDialog(activity: Activity) : CustomAlertDialog(activity) { + + init { + setTitle(R.string.uninstall_magisk_title) + setMessage(R.string.uninstall_magisk_msg) + setNeutralButton(R.string.restore_img) { _, _ -> + val dialog = ProgressDialog.show(activity, + activity.getString(R.string.restore_img), + activity.getString(R.string.restore_img_msg)) + Shell.su("restore_imgs").submit { result -> + dialog.cancel() + if (result.isSuccess) { + Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT) + } else { + Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG) + } + } + } + if (!TextUtils.isEmpty(Info.uninstallerLink)) { + setPositiveButton(R.string.complete_uninstall) { d, i -> + val zip = File(activity.filesDir, "uninstaller.zip") + val progress = ProgressNotification(zip.name) + Networking.get(Info.uninstallerLink) + .setDownloadProgressListener(progress) + .setErrorHandler { _, _ -> progress.dlFail() } + .getAsFile(zip) { f -> + progress.dismiss() + val intent = Intent(activity, ClassMap[FlashActivity::class.java]) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setData(Uri.fromFile(f)) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL) + activity.startActivity(intent) + } + } + } + } +}