convert more to kotlin
Signed-off-by: androidacy-user <opensource@androidacy.com>pull/27/head
parent
3cf96fef71
commit
b20a9fcced
@ -1,115 +1,123 @@
|
|||||||
package com.fox2code.mmm.utils;
|
package com.fox2code.mmm.utils
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName
|
||||||
import android.content.Context;
|
import android.content.Context
|
||||||
import android.content.Intent;
|
import android.content.DialogInterface
|
||||||
import android.content.pm.PackageManager;
|
import android.content.Intent
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri;
|
import android.net.Uri
|
||||||
import android.os.Bundle;
|
import android.widget.Toast
|
||||||
import android.widget.Toast;
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.app.ActivityOptionsCompat
|
||||||
|
import androidx.core.util.Supplier
|
||||||
|
import com.fox2code.mmm.Constants
|
||||||
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
class ExternalHelper private constructor() {
|
||||||
import androidx.core.app.ActivityOptionsCompat;
|
private var fallback: ComponentName? = null
|
||||||
import androidx.core.util.Supplier;
|
private var label: CharSequence? = null
|
||||||
|
private var multi = false
|
||||||
import com.fox2code.mmm.Constants;
|
fun refreshHelper(context: Context) {
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler;
|
val intent = Intent(
|
||||||
|
FOX_MMM_OPEN_EXTERNAL,
|
||||||
import java.util.List;
|
Uri.parse("https://very-invalid-prefix-for-testing.androidacy.com")
|
||||||
|
)
|
||||||
import timber.log.Timber;
|
@Suppress("DEPRECATION") val resolveInfos =
|
||||||
|
context.packageManager.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER)
|
||||||
public final class ExternalHelper {
|
|
||||||
public static final ExternalHelper INSTANCE = new ExternalHelper();
|
|
||||||
private static final boolean TEST_MODE = false;
|
|
||||||
private static final String FOX_MMM_OPEN_EXTERNAL = "com.fox2code.mmm.utils.intent.action.OPEN_EXTERNAL";
|
|
||||||
private static final String FOX_MMM_EXTRA_REPO_ID = "extra_repo_id";
|
|
||||||
private ComponentName fallback;
|
|
||||||
private CharSequence label;
|
|
||||||
private boolean multi;
|
|
||||||
|
|
||||||
private ExternalHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshHelper(Context context) {
|
|
||||||
Intent intent = new Intent(FOX_MMM_OPEN_EXTERNAL, Uri.parse("https://fox2code.com/module.zip"));
|
|
||||||
List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
|
|
||||||
if (resolveInfos.isEmpty()) {
|
if (resolveInfos.isEmpty()) {
|
||||||
Timber.i("No external provider installed!");
|
Timber.i("No external provider installed!")
|
||||||
label = TEST_MODE ? "External" : null;
|
label = if (TEST_MODE) "External" else null
|
||||||
multi = TEST_MODE;
|
multi = TEST_MODE
|
||||||
fallback = null;
|
fallback = null
|
||||||
} else {
|
} else {
|
||||||
ResolveInfo resolveInfo = resolveInfos.get(0);
|
val resolveInfo = resolveInfos[0]
|
||||||
Timber.i("Found external provider: %s", resolveInfo.activityInfo.packageName);
|
Timber.i("Found external provider: %s", resolveInfo.activityInfo.packageName)
|
||||||
fallback = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
|
fallback =
|
||||||
label = resolveInfo.loadLabel(context.getPackageManager());
|
ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)
|
||||||
multi = resolveInfos.size() >= 2;
|
label = resolveInfo.loadLabel(context.packageManager)
|
||||||
|
multi = resolveInfos.size >= 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean openExternal(Context context, Uri uri, String repoId) {
|
fun openExternal(context: Context, uri: Uri?, repoId: String?): Boolean {
|
||||||
if (label == null)
|
if (label == null) return false
|
||||||
return false;
|
val param =
|
||||||
Bundle param = ActivityOptionsCompat.makeCustomAnimation(context, android.R.anim.fade_in, android.R.anim.fade_out).toBundle();
|
ActivityOptionsCompat.makeCustomAnimation(context, com.google.android.material.R.anim.abc_fade_in, com.google.android.material.R.anim.abc_fade_out).toBundle()
|
||||||
Intent intent = new Intent(FOX_MMM_OPEN_EXTERNAL, uri);
|
var intent = Intent(FOX_MMM_OPEN_EXTERNAL, uri)
|
||||||
intent.setFlags(IntentHelper.FLAG_GRANT_URI_PERMISSION);
|
intent.flags = IntentHelper.FLAG_GRANT_URI_PERMISSION
|
||||||
intent.putExtra(FOX_MMM_EXTRA_REPO_ID, repoId);
|
intent.putExtra(FOX_MMM_EXTRA_REPO_ID, repoId)
|
||||||
if (multi) {
|
if (multi) {
|
||||||
intent = Intent.createChooser(intent, label);
|
intent = Intent.createChooser(intent, label)
|
||||||
} else {
|
} else {
|
||||||
intent.putExtra(Constants.EXTRA_FADE_OUT, true);
|
intent.putExtra(Constants.EXTRA_FADE_OUT, true)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (multi) {
|
if (multi) {
|
||||||
context.startActivity(intent);
|
context.startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
context.startActivity(intent, param);
|
context.startActivity(intent, param)
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
} catch (
|
} catch (e: ActivityNotFoundException) {
|
||||||
ActivityNotFoundException e) {
|
Timber.e(e)
|
||||||
Timber.e(e);
|
|
||||||
}
|
}
|
||||||
if (fallback != null) {
|
if (fallback != null) {
|
||||||
if (multi) {
|
if (multi) {
|
||||||
intent = new Intent(FOX_MMM_OPEN_EXTERNAL, uri);
|
intent = Intent(FOX_MMM_OPEN_EXTERNAL, uri)
|
||||||
intent.putExtra(FOX_MMM_EXTRA_REPO_ID, repoId);
|
intent.putExtra(FOX_MMM_EXTRA_REPO_ID, repoId)
|
||||||
intent.putExtra(Constants.EXTRA_FADE_OUT, true);
|
intent.putExtra(Constants.EXTRA_FADE_OUT, true)
|
||||||
}
|
}
|
||||||
intent.setComponent(fallback);
|
intent.component = fallback
|
||||||
try {
|
try {
|
||||||
context.startActivity(intent, param);
|
context.startActivity(intent, param)
|
||||||
return true;
|
return true
|
||||||
} catch (
|
} catch (e: ActivityNotFoundException) {
|
||||||
ActivityNotFoundException e) {
|
Timber.e(e)
|
||||||
Timber.e(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
public void injectButton(AlertDialog.Builder builder, Supplier<Uri> uriSupplier, String repoId) {
|
fun injectButton(builder: AlertDialog.Builder, uriSupplier: Supplier<Uri?>, repoId: String?) {
|
||||||
if (label == null)
|
if (label == null) return
|
||||||
return;
|
builder.setNeutralButton(label) { dialog: DialogInterface, _: Int ->
|
||||||
builder.setNeutralButton(label, (dialog, button) -> {
|
val context = (dialog as Dialog).context
|
||||||
Context context = ((Dialog) dialog).getContext();
|
object : Thread("Async downloader") {
|
||||||
new Thread("Async downloader") {
|
override fun run() {
|
||||||
@Override
|
val uri = uriSupplier.get()
|
||||||
public void run() {
|
if (uri == null) {
|
||||||
final Uri uri = uriSupplier.get();
|
UiThreadHandler.run {
|
||||||
if (uri == null)
|
Toast.makeText(
|
||||||
return;
|
context,
|
||||||
UiThreadHandler.run(() -> {
|
"Failed to get uri",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
UiThreadHandler.run {
|
||||||
if (!openExternal(context, uri, repoId)) {
|
if (!openExternal(context, uri, repoId)) {
|
||||||
Toast.makeText(context, "Failed to launch external activity", Toast.LENGTH_SHORT).show();
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Failed to launch external activity",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}.start();
|
}.start()
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val INSTANCE = ExternalHelper()
|
||||||
|
private const val TEST_MODE = false
|
||||||
|
private const val FOX_MMM_OPEN_EXTERNAL =
|
||||||
|
"com.fox2code.mmm.utils.intent.action.OPEN_EXTERNAL"
|
||||||
|
private const val FOX_MMM_EXTRA_REPO_ID = "extra_repo_id"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,13 @@
|
|||||||
package com.fox2code.mmm.utils;
|
package com.fox2code.mmm.utils
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
class FastException private constructor() : RuntimeException() {
|
||||||
|
@Synchronized
|
||||||
public final class FastException extends RuntimeException {
|
override fun fillInStackTrace(): Throwable {
|
||||||
public static final FastException INSTANCE = new FastException();
|
return this
|
||||||
|
}
|
||||||
private FastException() {}
|
|
||||||
|
|
||||||
@NonNull
|
companion object {
|
||||||
@Override
|
@JvmField
|
||||||
public synchronized Throwable fillInStackTrace() {
|
val INSTANCE = FastException()
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,25 +1,29 @@
|
|||||||
package com.fox2code.mmm.utils;
|
package com.fox2code.mmm.utils
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent
|
||||||
import android.content.Context;
|
import android.content.Context
|
||||||
import android.content.Intent;
|
import android.content.Intent
|
||||||
|
import com.fox2code.mmm.MainActivity
|
||||||
|
import java.util.concurrent.ThreadLocalRandom
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
import com.fox2code.mmm.MainActivity;
|
enum class ProcessHelper {
|
||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public enum ProcessHelper {
|
|
||||||
;
|
;
|
||||||
private static final int sPendingIntentId = ThreadLocalRandom.current().nextInt(100, 1000000 + 1);
|
|
||||||
|
|
||||||
public static void restartApplicationProcess(Context context) {
|
companion object {
|
||||||
Intent mStartActivity = new Intent(context, MainActivity.class);
|
private val sPendingIntentId = ThreadLocalRandom.current().nextInt(100, 1000000 + 1)
|
||||||
mStartActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
@JvmStatic
|
||||||
PendingIntent mPendingIntent = PendingIntent.getActivity(context, sPendingIntentId,
|
fun restartApplicationProcess(context: Context) {
|
||||||
mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
val mStartActivity = Intent(context, MainActivity::class.java)
|
||||||
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
mStartActivity.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
|
val mPendingIntent = PendingIntent.getActivity(
|
||||||
System.exit(0); // Exit app process
|
context, sPendingIntentId,
|
||||||
|
mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||||
|
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] = mPendingIntent
|
||||||
|
exitProcess(0) // Exit app process
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,79 +1,76 @@
|
|||||||
package com.fox2code.mmm.utils;
|
package com.fox2code.mmm.utils
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager that want both to be thread safe and not to worry about thread safety
|
* Manager that want both to be thread safe and not to worry about thread safety
|
||||||
* {@link #scan()} and {@link #update(UpdateListener)} can be called from multiple
|
* [.scan] and [.update] can be called from multiple
|
||||||
* thread at the same time, {@link #scanInternal(UpdateListener)} will only be
|
* thread at the same time, [.scanInternal] will only be
|
||||||
* called from one thread at a time only.
|
* called from one thread at a time only.
|
||||||
*/
|
*/
|
||||||
public abstract class SyncManager {
|
abstract class SyncManager {
|
||||||
private static final UpdateListener NO_OP = value -> {};
|
@JvmField
|
||||||
protected final Object syncLock = new Object();
|
protected val syncLock = Any()
|
||||||
private boolean syncing;
|
private var syncing = false
|
||||||
private long lastSync;
|
private var lastSync: Long = 0
|
||||||
|
fun scanAsync() {
|
||||||
public final void scanAsync() {
|
if (!syncing) {
|
||||||
if (!this.syncing) {
|
Thread({ this.scan() }, "Scan Thread").start()
|
||||||
new Thread(this::scan, "Scan Thread").start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void scan() {
|
fun scan() {
|
||||||
this.update(null);
|
update(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiThread friendly method
|
// MultiThread friendly method
|
||||||
public final void update(@Nullable UpdateListener updateListener) {
|
fun update(updateListener: UpdateListener?) {
|
||||||
if (updateListener == null) updateListener = NO_OP;
|
@Suppress("NAME_SHADOWING") var updateListener = updateListener
|
||||||
if (!this.syncing) {
|
if (updateListener == null) updateListener = NO_OP
|
||||||
|
if (!syncing) {
|
||||||
// Do scan
|
// Do scan
|
||||||
synchronized (this.syncLock) {
|
synchronized(syncLock) {
|
||||||
if (System.currentTimeMillis() < this.lastSync + 50L)
|
if (System.currentTimeMillis() < lastSync + 50L) return // Skip sync if it was synced too recently
|
||||||
return; // Skip sync if it was synced too recently
|
syncing = true
|
||||||
this.syncing = true;
|
|
||||||
try {
|
try {
|
||||||
this.scanInternal(updateListener);
|
scanInternal(updateListener)
|
||||||
} finally {
|
} finally {
|
||||||
this.lastSync = System.currentTimeMillis();
|
lastSync = System.currentTimeMillis()
|
||||||
this.syncing = false;
|
syncing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Wait for current scan
|
// Wait for current scan
|
||||||
synchronized (this.syncLock) {
|
synchronized(syncLock) { Thread.yield() }
|
||||||
Thread.yield();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause execution until the scan is completed if one is currently running
|
// Pause execution until the scan is completed if one is currently running
|
||||||
public final void afterScan() {
|
fun afterScan() {
|
||||||
if (this.syncing) synchronized (this.syncLock) { Thread.yield(); }
|
if (syncing) synchronized(syncLock) { Thread.yield() }
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void runAfterScan(Runnable runnable) {
|
fun runAfterScan(runnable: Runnable) {
|
||||||
synchronized (this.syncLock) {
|
synchronized(syncLock) { runnable.run() }
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void afterUpdate() {
|
fun afterUpdate() {
|
||||||
if (this.syncing) synchronized (this.syncLock) { Thread.yield(); }
|
if (syncing) synchronized(syncLock) { Thread.yield() }
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void runAfterUpdate(Runnable runnable) {
|
fun runAfterUpdate(runnable: Runnable) {
|
||||||
synchronized (this.syncLock) {
|
synchronized(syncLock) { runnable.run() }
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method can't be called twice at the same time.
|
// This method can't be called twice at the same time.
|
||||||
protected abstract void scanInternal(@NonNull UpdateListener updateListener);
|
protected abstract fun scanInternal(updateListener: UpdateListener)
|
||||||
|
interface UpdateListener {
|
||||||
|
fun update(value: Double)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val NO_OP: UpdateListener = object : UpdateListener {
|
||||||
|
override fun update(value: Double) {
|
||||||
|
|
||||||
public interface UpdateListener {
|
}
|
||||||
void update(double value);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue