various improvements

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/89/head
androidacy-user 2 years ago
parent 706a83a9e1
commit 9f7a5f5838

@ -48,6 +48,8 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<!-- wifi -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- be gay do crime -->
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<application
android:name=".MainApplication"

@ -44,7 +44,7 @@ class AppUpdateManager private constructor() {
lastChecked < System.currentTimeMillis() - 60000L
) return force && peekShouldUpdate()
synchronized(updateLock) {
if (BuildConfig.DEBUG) Timber.d("Checking for app updates")
if (MainApplication.forceDebugLogging) Timber.d("Checking for app updates")
if (lastChecked != this.lastChecked) return peekShouldUpdate()
// make a request to https://production-api.androidacy.com/amm/updates/check with appVersionCode and token/device_id/client_id
var token = AndroidacyRepoData.token
@ -59,7 +59,7 @@ class AppUpdateManager private constructor() {
val response = doHttpGet(url, false)
// convert response to string
val responseString = String(response, Charsets.UTF_8)
if (BuildConfig.DEBUG) Timber.d("Response: $responseString")
if (MainApplication.forceDebugLogging) Timber.d("Response: $responseString")
// json response has a boolean shouldUpdate and an int latestVersion
JSONObject(responseString).let {
if (it.getBoolean("shouldUpdate")) {
@ -105,7 +105,7 @@ class AppUpdateManager private constructor() {
@Throws(IOException::class)
private fun parseCompatibilityFlags(inputStream: InputStream) {
compatDataId.clear()
if (BuildConfig.DEBUG) Timber.d("Not implemented")
if (MainApplication.forceDebugLogging) Timber.d("Not implemented")
}
fun getCompatibilityFlags(moduleId: String): Int {

@ -9,6 +9,7 @@ enum class Constants {
;
companion object {
const val EXTRA_DOWNLOAD_TITLE: String = "Download"
const val MAGISK_VER_CODE_FLAT_MODULES = 19000
const val MAGISK_VER_CODE_UTIL_INSTALL = 20400
const val MAGISK_VER_CODE_PATH_SUPPORT = 21000

@ -22,9 +22,9 @@ class CrashHandler : AppCompatActivity() {
@Suppress("DEPRECATION")
@SuppressLint("RestrictedApi")
override fun onCreate(savedInstanceState: Bundle?) {
Timber.i("CrashHandler.onCreate(%s)", savedInstanceState)
if (MainApplication.forceDebugLogging) Timber.i("CrashHandler.onCreate(%s)", savedInstanceState)
// log intent with extras
if (BuildConfig.DEBUG) Timber.d("CrashHandler.onCreate: intent=%s", intent)
if (MainApplication.forceDebugLogging) Timber.d("CrashHandler.onCreate: intent=%s", intent)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crash_handler)
// set crash_details MaterialTextView to the exception passed in the intent or unknown if null

@ -7,12 +7,15 @@ package com.fox2code.mmm
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.text.Editable
@ -26,6 +29,7 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsAnimationCompat
@ -53,8 +57,10 @@ import com.fox2code.mmm.repo.RepoManager
import com.fox2code.mmm.repo.RepoModule
import com.fox2code.mmm.settings.SettingsActivity
import com.fox2code.mmm.utils.ExternalHelper
import com.fox2code.mmm.utils.IntentHelper
import com.fox2code.mmm.utils.RuntimeUtils
import com.fox2code.mmm.utils.SyncManager
import com.fox2code.mmm.utils.io.Files
import com.fox2code.mmm.utils.io.net.Http.Companion.cleanDnsCache
import com.fox2code.mmm.utils.io.net.Http.Companion.hasWebView
import com.fox2code.mmm.utils.room.ReposListDatabase
@ -64,9 +70,15 @@ import com.google.android.material.elevation.SurfaceColors
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputEditText
import com.topjohnwu.superuser.io.SuFileInputStream
import ly.count.android.sdk.Countly
import ly.count.android.sdk.ModuleFeedback
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.nio.file.Files.*
import java.sql.Timestamp
@ -91,6 +103,94 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
private var rebootFab: FloatingActionButton? = null
private var initMode = false
private var runtimeUtils: RuntimeUtils? = null
var callback: IntentHelper.Companion.OnFileReceivedCallback? = null
var destination: File? = null
@SuppressLint("SdCardPath")
val getContent = this.registerForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
if (uri == null) {
Timber.d("invalid uri received")
callback?.onReceived(destination, null, IntentHelper.RESPONSE_ERROR)
return@registerForActivityResult
}
if (MainApplication.forceDebugLogging) Timber.i("FilePicker returned %s", uri)
if ("http" == uri.scheme || "https" == uri.scheme) {
callback?.onReceived(destination, uri, IntentHelper.RESPONSE_URL)
return@registerForActivityResult
}
if (ContentResolver.SCHEME_FILE == uri.scheme) {
Toast.makeText(
this@MainActivity, R.string.file_picker_wierd, Toast.LENGTH_SHORT
).show()
}
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
var success = false
try {
if (ContentResolver.SCHEME_FILE == uri.scheme) {
var path = uri.path
if (path!!.startsWith("/sdcard/")) { // Fix file paths
path =
Environment.getExternalStorageDirectory().absolutePath + path.substring(
7
)
}
inputStream = SuFileInputStream.open(
File(path).absoluteFile
)
} else {
inputStream = this.contentResolver.openInputStream(uri)
}
// check if the file is a zip
if (inputStream == null) {
Toast.makeText(
this@MainActivity, R.string.file_picker_failure, Toast.LENGTH_SHORT
).show()
callback?.onReceived(
destination,
uri,
IntentHelper.RESPONSE_ERROR
)
return@registerForActivityResult
}
// check if the file is a zip by reading the first 4 bytes
val bytes = ByteArray(4)
inputStream.read(bytes, 0, 4)
if (!(bytes[0] == 0x50.toByte() && bytes[1] == 0x4B.toByte() && bytes[2] == 0x03.toByte() && bytes[3] == 0x04.toByte())) {
Toast.makeText(
this@MainActivity, R.string.file_picker_not_zip, Toast.LENGTH_SHORT
).show()
Timber.e("File is not a zip! Expected 0x504B0304, got %02X%02X%02X%02X", bytes[0], bytes[1], bytes[2], bytes[3])
callback?.onReceived(
destination,
uri,
IntentHelper.RESPONSE_ERROR
)
return@registerForActivityResult
}
outputStream = FileOutputStream(destination)
Files.copy(inputStream, outputStream)
if (MainApplication.forceDebugLogging) Timber.i("File saved at %s", destination)
success = true
} catch (e: Exception) {
Timber.e(e)
Toast.makeText(
this@MainActivity, R.string.file_picker_failure, Toast.LENGTH_SHORT
).show()
} finally {
Files.closeSilently(inputStream)
Files.closeSilently(outputStream)
if (!success && destination?.exists() == true && !destination!!.delete()) Timber.e("Failed to delete artifact!")
}
callback?.onReceived(
destination,
uri,
if (success) IntentHelper.RESPONSE_FILE else IntentHelper.RESPONSE_ERROR
)
}
init {
moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE)
@ -246,7 +346,10 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
} as Map<String, Any>?, 1)
Thread {
if (moduleViewListBuilder.setQueryChange(query)) {
Timber.i("Query submit: %s on offline list", query)
if (MainApplication.forceDebugLogging) Timber.i(
"Query submit: %s on offline list",
query
)
Thread(
{ moduleViewListBuilder.applyTo(moduleList!!, moduleViewAdapter!!) },
"Query update thread"
@ -254,7 +357,10 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
// same for online list
if (moduleViewListBuilderOnline.setQueryChange(query)) {
Timber.i("Query submit: %s on online list", query)
if (MainApplication.forceDebugLogging) Timber.i(
"Query submit: %s on online list",
query
)
Thread({
moduleViewListBuilderOnline.applyTo(
moduleListOnline!!, moduleViewAdapterOnline!!
@ -275,7 +381,10 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
} as Map<String, Any>?, 1)
Thread {
if (moduleViewListBuilder.setQueryChange(query)) {
Timber.i("Query submit: %s on offline list", query)
if (MainApplication.forceDebugLogging) Timber.i(
"Query submit: %s on offline list",
query
)
Thread(
{ moduleViewListBuilder.applyTo(moduleList!!, moduleViewAdapter!!) },
"Query update thread"
@ -283,7 +392,10 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
// same for online list
if (moduleViewListBuilderOnline.setQueryChange(query)) {
Timber.i("Query submit: %s on online list", query)
if (MainApplication.forceDebugLogging) Timber.i(
"Query submit: %s on online list",
query
)
Thread({
moduleViewListBuilderOnline.applyTo(
moduleListOnline!!, moduleViewAdapterOnline!!
@ -478,7 +590,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
MainApplication.INSTANCE!!.resetUpdateModule()
tryGetMagiskPathAsync(object : InstallerInitializer.Callback {
override fun onPathReceived(path: String?) {
Timber.i("Got magisk path: %s", path)
if (MainApplication.forceDebugLogging) Timber.i("Got magisk path: %s", path)
if (peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND) {
if (!InstallerInitializer.isKsu) {
moduleViewListBuilder.addNotification(
@ -508,14 +620,14 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
fun commonNext() {
if (BuildConfig.DEBUG) {
if (BuildConfig.DEBUG) Timber.d("Common next")
if (MainApplication.forceDebugLogging) Timber.d("Common next")
moduleViewListBuilder.addNotification(NotificationType.DEBUG)
}
NotificationType.NO_INTERNET.autoAdd(moduleViewListBuilderOnline)
val progressIndicator = progressIndicator!!
// hide progress bar is repo-manager says we have no internet
if (!RepoManager.getINSTANCE()!!.hasConnectivity()) {
Timber.i("No connection, hiding progress")
if (MainApplication.forceDebugLogging) Timber.i("No connection, hiding progress")
runOnUiThread {
progressIndicator.visibility = View.GONE
progressIndicator.isIndeterminate = false
@ -524,7 +636,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
val context: Context = this@MainActivity
if (runtimeUtils!!.waitInitialSetupFinished(context, this@MainActivity)) {
if (BuildConfig.DEBUG) Timber.d("waiting...")
if (MainApplication.forceDebugLogging) Timber.d("waiting...")
return
}
swipeRefreshBlocker = System.currentTimeMillis() + 5000L
@ -541,8 +653,8 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
}
moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter!!)
Timber.i("Scanning for modules!")
if (BuildConfig.DEBUG) Timber.i("Initialize Update")
if (MainApplication.forceDebugLogging) Timber.i("Scanning for modules!")
if (MainApplication.forceDebugLogging) Timber.i("Initialize Update")
val max = instance!!.getUpdatableModuleCount()
if (RepoManager.getINSTANCE()!!.customRepoManager != null && RepoManager.getINSTANCE()!!.customRepoManager!!.needUpdate()) {
Timber.w("Need update on create")
@ -550,9 +662,9 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
Timber.w("CustomRepoManager is null")
}
// update compat metadata
if (BuildConfig.DEBUG) Timber.i("Check Update Compat")
if (MainApplication.forceDebugLogging) Timber.i("Check Update Compat")
appUpdateManager.checkUpdateCompat()
if (BuildConfig.DEBUG) Timber.i("Check Update")
if (MainApplication.forceDebugLogging) Timber.i("Check Update")
// update repos
if (hasWebView()) {
val updateListener: SyncManager.UpdateListener =
@ -588,11 +700,11 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
// Compatibility data still needs to be updated
val appUpdateManager = appUpdateManager
if (BuildConfig.DEBUG) Timber.i("Check App Update")
if (MainApplication.forceDebugLogging) Timber.i("Check App Update")
if (BuildConfig.ENABLE_AUTO_UPDATER && appUpdateManager.checkUpdate(true)) moduleViewListBuilder.addNotification(
NotificationType.UPDATE_AVAILABLE
)
if (BuildConfig.DEBUG) Timber.i("Check Json Update")
if (MainApplication.forceDebugLogging) Timber.i("Check Json Update")
if (max != 0) {
var current = 0
for (localModuleInfo in instance!!.modules.values) {
@ -601,7 +713,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
// the reasoning is that remote repos are considered "validated" while local modules are not
// for instance, a potential attacker could hijack a perfectly legitimate module and inject an updateJson with a malicious update - thereby bypassing any checks repos may have, without anyone noticing until it's too late
if (localModuleInfo.updateJson != null && localModuleInfo.flags and ModuleInfo.FLAG_MM_REMOTE_MODULE == 0) {
if (BuildConfig.DEBUG) Timber.i(localModuleInfo.id)
if (MainApplication.forceDebugLogging) Timber.i(localModuleInfo.id)
try {
localModuleInfo.checkModuleUpdate()
} catch (e: Exception) {
@ -618,7 +730,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
}
}
if (BuildConfig.DEBUG) Timber.i("Apply")
if (MainApplication.forceDebugLogging) Timber.i("Apply")
RepoManager.getINSTANCE()
?.runAfterUpdate { moduleViewListBuilderOnline.appendRemoteModules() }
moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter!!)
@ -626,13 +738,13 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
moduleViewListBuilderOnline.applyTo(moduleListOnline, moduleViewAdapterOnline!!)
// if moduleViewListBuilderOnline has the upgradeable notification, show a badge on the online repo nav item
if (MainApplication.INSTANCE!!.modulesHaveUpdates) {
Timber.i("Applying badge")
if (MainApplication.forceDebugLogging) Timber.i("Applying badge")
Handler(Looper.getMainLooper()).post {
val badge = bottomNavigationView.getOrCreateBadge(R.id.online_menu_item)
badge.isVisible = true
badge.number = MainApplication.INSTANCE!!.updateModuleCount
badge.applyTheme(MainApplication.INSTANCE!!.theme)
Timber.i("Badge applied")
if (MainApplication.forceDebugLogging) Timber.i("Badge applied")
}
}
runOnUiThread {
@ -640,7 +752,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
progressIndicator.visibility = View.GONE
}
maybeShowUpgrade()
Timber.i("Finished app opening state!")
if (MainApplication.forceDebugLogging) Timber.i("Finished app opening state!")
}
}, true)
// if system lang is not in MainApplication.supportedLocales, show a snackbar to ask user to help translate
@ -660,16 +772,19 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
Handler(Looper.getMainLooper()).postDelayed({
showFeedback()
}, 5000)
Timber.i("Should show feedback")
if (MainApplication.forceDebugLogging) Timber.i("Should show feedback")
} else {
Timber.i("Should not show feedback")
if (MainApplication.forceDebugLogging) Timber.i("Should not show feedback")
}
}
private fun showFeedback() {
Countly.sharedInstance().feedback()
.getAvailableFeedbackWidgets { retrievedWidgets, error ->
Timber.i("Got feedback widgets: %s", retrievedWidgets.size)
if (MainApplication.forceDebugLogging) Timber.i(
"Got feedback widgets: %s",
retrievedWidgets.size
)
if (error == null) {
if (retrievedWidgets.size > 0) {
val feedbackWidget = retrievedWidgets[0]
@ -730,7 +845,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
swipeRefreshLayout!!.isRefreshing = false
return // Do not double scan
}
if (BuildConfig.DEBUG) Timber.i("Refresh")
if (MainApplication.forceDebugLogging) Timber.i("Refresh")
progressIndicator!!.visibility = View.VISIBLE
progressIndicator!!.setProgressCompat(0, false)
swipeRefreshBlocker = System.currentTimeMillis() + 5000L
@ -764,16 +879,16 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
} else {
// Compatibility data still needs to be updated
val appUpdateManager = appUpdateManager
if (BuildConfig.DEBUG) Timber.i("Check App Update")
if (MainApplication.forceDebugLogging) Timber.i("Check App Update")
if (BuildConfig.ENABLE_AUTO_UPDATER && appUpdateManager.checkUpdate(true)) moduleViewListBuilder.addNotification(
NotificationType.UPDATE_AVAILABLE
)
if (BuildConfig.DEBUG) Timber.i("Check Json Update")
if (MainApplication.forceDebugLogging) Timber.i("Check Json Update")
if (max != 0) {
var current = 0
for (localModuleInfo in instance!!.modules.values) {
if (localModuleInfo.updateJson != null && localModuleInfo.flags and ModuleInfo.FLAG_MM_REMOTE_MODULE == 0) {
if (BuildConfig.DEBUG) Timber.i(localModuleInfo.id)
if (MainApplication.forceDebugLogging) Timber.i(localModuleInfo.id)
try {
localModuleInfo.checkModuleUpdate()
} catch (e: Exception) {
@ -790,7 +905,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
}
}
}
if (BuildConfig.DEBUG) Timber.i("Apply")
if (MainApplication.forceDebugLogging) Timber.i("Apply")
runOnUiThread {
progressIndicator!!.visibility = View.GONE
swipeRefreshLayout!!.isRefreshing = false
@ -811,7 +926,7 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
// wait for up to 10 seconds for AndroidacyRepoData to be initialized
var i: Int
if (AndroidacyRepoData.instance.isEnabled && AndroidacyRepoData.instance.memberLevel == null) {
if (BuildConfig.DEBUG) Timber.d("Member level is null, waiting for it to be initialized")
if (MainApplication.forceDebugLogging) Timber.d("Member level is null, waiting for it to be initialized")
i = 0
while (AndroidacyRepoData.instance.memberLevel == null && i < 20) {
i++
@ -830,28 +945,28 @@ class MainActivity : AppCompatActivity(), OnRefreshListener, OverScrollHelper {
runtimeUtils!!.showUpgradeSnackbar(this, this)
} else {
if (!AndroidacyRepoData.instance.isEnabled) {
Timber.i("AndroidacyRepoData is disabled, not showing upgrade snackbar 1")
if (MainApplication.forceDebugLogging) Timber.i("AndroidacyRepoData is disabled, not showing upgrade snackbar 1")
} else if (AndroidacyRepoData.instance.memberLevel != "Guest") {
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"AndroidacyRepoData is not Guest, not showing upgrade snackbar 1. Level: %s",
AndroidacyRepoData.instance.memberLevel
)
} else {
Timber.i("Unknown error, not showing upgrade snackbar 1")
if (MainApplication.forceDebugLogging) Timber.i("Unknown error, not showing upgrade snackbar 1")
}
}
} else if (AndroidacyRepoData.instance.isEnabled && AndroidacyRepoData.instance.memberLevel == "Guest") {
runtimeUtils!!.showUpgradeSnackbar(this, this)
} else {
if (!AndroidacyRepoData.instance.isEnabled) {
Timber.i("AndroidacyRepoData is disabled, not showing upgrade snackbar 2")
if (MainApplication.forceDebugLogging) Timber.i("AndroidacyRepoData is disabled, not showing upgrade snackbar 2")
} else if (AndroidacyRepoData.instance.memberLevel != "Guest") {
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"AndroidacyRepoData is not Guest, not showing upgrade snackbar 2. Level: %s",
AndroidacyRepoData.instance.memberLevel
)
} else {
Timber.i("Unknown error, not showing upgrade snackbar 2")
if (MainApplication.forceDebugLogging) Timber.i("Unknown error, not showing upgrade snackbar 2")
}
}
}

@ -250,6 +250,18 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
if (INSTANCE == null) INSTANCE = this
relPackageName = this.packageName
super.onCreate()
var output = Shell.cmd("echo $(id -u)").exec().out[0]
if (output != null) {
output = output.trim { it <= ' ' }
if (forceDebugLogging) Timber.d("UID: %s", output)
if (output == "0") {
if (forceDebugLogging) Timber.d("Root access granted")
setHasGottenRootAccess(true)
} else {
if (forceDebugLogging) Timber.d("Root access or we're not uid 0. Current uid: %s", output)
setHasGottenRootAccess(false)
}
}
if (!callbacksRegistered) {
try {
registerActivityLifecycleCallbacks(this)
@ -260,7 +272,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
}
// Initialize Timber
configTimber()
Timber.i(
if (forceDebugLogging) Timber.i(
"Starting AMM version %s (%d) - commit %s",
BuildConfig.VERSION_NAME,
BuildConfig.VERSION_CODE,
@ -275,13 +287,13 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
fileUtils.ensureCacheDirs()
fileUtils.ensureURLHandler(this)
}
if (BuildConfig.DEBUG) Timber.d("Initializing AMM")
if (BuildConfig.DEBUG) Timber.d("Started from background: %s", !isInForeground)
if (BuildConfig.DEBUG) Timber.d("AMM is running in debug mode")
if (forceDebugLogging) Timber.d("Initializing AMM")
if (forceDebugLogging) Timber.d("Started from background: %s", !isInForeground)
if (forceDebugLogging) Timber.d("AMM is running in debug mode")
// analytics
if (BuildConfig.DEBUG) Timber.d("Initializing countly")
if (forceDebugLogging) Timber.d("Initializing countly")
if (!analyticsAllowed()) {
if (BuildConfig.DEBUG) Timber.d("countly is not allowed")
if (forceDebugLogging) Timber.d("countly is not allowed")
} else {
val config = CountlyConfig(
this,
@ -344,9 +356,9 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
fontRequestEmojiCompatConfig.setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL)
val emojiCompat = EmojiCompat.init(fontRequestEmojiCompatConfig)
Thread({
Timber.i("Loading emoji compat...")
if (forceDebugLogging) Timber.i("Loading emoji compat...")
emojiCompat.load()
Timber.i("Emoji compat loaded!")
if (forceDebugLogging) Timber.i("Emoji compat loaded!")
}, "Emoji compat init.").start()
}
@Suppress("KotlinConstantConditions") if ((BuildConfig.ANDROIDACY_CLIENT_ID == "")) {
@ -386,7 +398,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
// make sure the directory exists
if (!dataDir.exists()) {
if (!dataDir.mkdirs()) {
if (BuildConfig.DEBUG) Timber.w(
if (forceDebugLogging) Timber.w(
"Failed to create directory %s", dataDir
)
}
@ -397,7 +409,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
// create the directory if it doesn't exist
if (!dataDir.exists()) {
if (!dataDir.mkdirs()) {
if (BuildConfig.DEBUG) Timber.w("Failed to create directory %s", dataDir)
if (forceDebugLogging) Timber.w("Failed to create directory %s", dataDir)
}
}
}
@ -422,12 +434,12 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
val activityManager = this.getSystemService(ACTIVITY_SERVICE) as ActivityManager
val appProcesses = activityManager.runningAppProcesses
if (appProcesses == null) {
if (BuildConfig.DEBUG) Timber.d("appProcesses is null")
if (forceDebugLogging) Timber.d("appProcesses is null")
return false
}
val packageName = this.packageName
for (appProcess in appProcesses) {
if (BuildConfig.DEBUG) Timber.d(
if (forceDebugLogging) Timber.d(
"Process: %s, Importance: %d", appProcess.processName, appProcess.importance
)
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
@ -456,6 +468,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
}
class ReleaseTree : Timber.Tree() {
@SuppressLint("LogNotTimber")
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
// basically silently drop all logs below error, and write the rest to logcat
@Suppress("NAME_SHADOWING") var message = message
@ -463,12 +476,20 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
// prepend [TAINTED] to the message
message = "[TAINTED] $message"
}
if (priority >= Log.ERROR) {
if (t != null) {
Log.println(priority, tag, message)
t.printStackTrace()
} else {
Log.println(priority, tag, message)
if (forceDebugLogging) {
if (priority >= Log.DEBUG) {
when(priority) {
Log.DEBUG -> Log.d(tag, message, t)
Log.INFO -> Log.i(tag, message, t)
Log.WARN -> Log.w(tag, message, t)
Log.ERROR -> Log.e(tag, message, t)
Log.ASSERT -> Log.wtf(tag, message, t)
}
t?.printStackTrace()
}
} else {
if (priority >= Log.ERROR) {
Log.e(tag, message, t)
}
}
}
@ -476,6 +497,8 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
companion object {
var forceDebugLogging: Boolean = BuildConfig.DEBUG || getSharedPreferences("mmm")?.getBoolean("pref_force_debug_logging", false) ?: false
// Warning! Locales that don't exist will crash the app
// Anything that is commented out is supported but the translation is not complete to at least 60%
@JvmField
@ -522,7 +545,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
}
// prewarm shell
Shell.getShell {
// do nothing
if (forceDebugLogging) Timber.d("Shell prewarmed")
}
val random = Random()
do {
@ -574,8 +597,32 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
mSharedPrefs!![name] = sharedPreferences
sharedPreferences
} catch (e: Exception) {
Timber.e(e, "Failed to create encrypted shared preferences")
mContext!!.getSharedPreferences(name, MODE_PRIVATE)
// try again five times, with a 250ms delay between each try. if we still can't get the shared preferences, throw an exception
var i = 0
while (i < 5) {
try {
Thread.sleep(250)
} catch (ignored: InterruptedException) {
}
try {
val masterKey =
MasterKey.Builder(mContext!!).setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val sharedPreferences = EncryptedSharedPreferences.create(
mContext,
name,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
mSharedPrefs!![name] = sharedPreferences
return sharedPreferences
} catch (e: Exception) {
Timber.e(e, "Failed to get shared preferences")
}
i++
}
throw IllegalStateException("Failed to get shared preferences")
}
}
@ -683,7 +730,7 @@ class MainApplication : Application(), Configuration.Provider, ActivityLifecycle
// should not have been shown in 14 days and only 1 in 5 chance
val randChance = Random().nextInt(5)
val lastShown = getSharedPreferences("mmm")!!.getLong("last_feedback", 0)
if (BuildConfig.DEBUG) Timber.d("Last feedback shown: %d, randChance: %d", lastShown, randChance)
if (forceDebugLogging) Timber.d("Last feedback shown: %d, randChance: %d", lastShown, randChance)
return System.currentTimeMillis() - lastShown > 1209600000 && randChance == 0
}
}

@ -205,7 +205,7 @@ enum class NotificationType(
val module = File(
compatActivity.cacheDir, "installer" + File.separator + "module.zip"
)
IntentHelper.openFileTo(compatActivity, module, object :
IntentHelper.openFileTo(module, object :
OnFileReceivedCallback {
override fun onReceived(

@ -196,31 +196,31 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
// On debug builds, log when a switch is toggled
if (BuildConfig.DEBUG) {
(Objects.requireNonNull<Any>(view.findViewById(R.id.setup_background_update_check)) as MaterialSwitch).setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Automatic update Check: %s",
isChecked
)
}
setupCrashReporting.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Crash Reporting: %s",
isChecked
)
}
(Objects.requireNonNull<Any>(view.findViewById(R.id.setup_crash_reporting_pii)) as MaterialSwitch).setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Crash Reporting PII: %s",
isChecked
)
}
(Objects.requireNonNull<Any>(view.findViewById(R.id.setup_androidacy_repo)) as MaterialSwitch).setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Androidacy Repo: %s",
isChecked
)
}
(Objects.requireNonNull<Any>(view.findViewById(R.id.setup_magisk_alt_repo)) as MaterialSwitch).setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Magisk Alt Repo: %s",
isChecked
)
@ -301,11 +301,11 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
).show()
return@setOnClickListener
}
Timber.i("Setup button clicked")
if (MainApplication.forceDebugLogging) Timber.i("Setup button clicked")
// get instance of editor
if (BuildConfig.DEBUG) Timber.d("Saving preferences")
if (MainApplication.forceDebugLogging) Timber.d("Saving preferences")
val editor = prefs.edit()
if (BuildConfig.DEBUG) Timber.d("Got editor: %s", editor)
if (MainApplication.forceDebugLogging) Timber.d("Got editor: %s", editor)
// Set the Automatic update check pref
editor.putBoolean(
"pref_background_update_check", (Objects.requireNonNull<Any>(
@ -347,7 +347,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
)
) as MaterialSwitch).isChecked
)
if (BuildConfig.DEBUG) Timber.d("Saving preferences")
if (MainApplication.forceDebugLogging) Timber.d("Saving preferences")
// now basically do the same thing for room db
val db = Room.databaseBuilder(
applicationContext,
@ -356,7 +356,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
val androidacyRepoRoom = andRepoView.isChecked
val magiskAltRepoRoom = magiskAltRepoView.isChecked
val reposListDao = db.reposListDao()
if (BuildConfig.DEBUG) Timber.d(reposListDao.getAll().toString())
if (MainApplication.forceDebugLogging) Timber.d(reposListDao.getAll().toString())
val androidacyRepoRoomObj = reposListDao.getById("androidacy_repo")
val magiskAltRepoRoomObj = reposListDao.getById("magisk_alt_repo")
reposListDao.setEnabled(androidacyRepoRoomObj.id, androidacyRepoRoom)
@ -366,11 +366,11 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
// Commit the changes
editor.commit()
// Log the changes
if (BuildConfig.DEBUG) Timber.d("Setup finished. Preferences: %s", prefs.all)
if (BuildConfig.DEBUG) Timber.d("Androidacy repo: %s", androidacyRepoRoom)
if (BuildConfig.DEBUG) Timber.d("Magisk Alt repo: %s", magiskAltRepoRoom)
if (MainApplication.forceDebugLogging) Timber.d("Setup finished. Preferences: %s", prefs.all)
if (MainApplication.forceDebugLogging) Timber.d("Androidacy repo: %s", androidacyRepoRoom)
if (MainApplication.forceDebugLogging) Timber.d("Magisk Alt repo: %s", magiskAltRepoRoom)
// log last shown setup
if (BuildConfig.DEBUG) Timber.d("Last shown setup: %s", prefs.getString("last_shown_setup", "v0"))
if (MainApplication.forceDebugLogging) Timber.d("Last shown setup: %s", prefs.getString("last_shown_setup", "v0"))
// Restart the activity
MainActivity.doSetupRestarting = true
val pendingIntent = PendingIntent.getActivity(
@ -391,7 +391,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
// unselect the cancel button because it's selected by default
cancelButton.isSelected = false
cancelButton.setOnClickListener { _: View? ->
Timber.i("Cancel button clicked")
if (MainApplication.forceDebugLogging) Timber.i("Cancel button clicked")
// close the app
finish()
}
@ -450,7 +450,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
// creates the room database
private fun createDatabases() {
val thread = Thread {
if (BuildConfig.DEBUG) Timber.d("Creating databases")
if (MainApplication.forceDebugLogging) Timber.d("Creating databases")
val startTime = System.currentTimeMillis()
val appContext = MainApplication.INSTANCE!!.applicationContext
val db = Room.databaseBuilder(appContext, ReposListDatabase::class.java, "ReposList.db")
@ -532,7 +532,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
).show()
}
} else {
if (BuildConfig.DEBUG) Timber.d("ReposList is updated with 2 entries")
if (MainApplication.forceDebugLogging) Timber.d("ReposList is updated with 2 entries")
}
// make sure modulelistcache is updated with 1 entry
if (moduleListCacheDao.getAll().size != 1) {
@ -546,12 +546,12 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
).show()
}
} else {
if (BuildConfig.DEBUG) Timber.d("ModuleListCache is updated with 1 entry")
if (MainApplication.forceDebugLogging) Timber.d("ModuleListCache is updated with 1 entry")
}
// close the databases
db.close()
db2.close()
if (BuildConfig.DEBUG) Timber.d("Databases created in %s ms", System.currentTimeMillis() - startTime)
if (MainApplication.forceDebugLogging) Timber.d("Databases created in %s ms", System.currentTimeMillis() - startTime)
}
thread.start()
}
@ -590,7 +590,7 @@ class SetupActivity : AppCompatActivity(), LanguageActivity {
val componentName = ComponentName(this, UpdateActivity::class.java)
val componentEnabledSetting = pm.getComponentEnabledSetting(componentName)
if (componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
if (BuildConfig.DEBUG) Timber.d("Disabling update activity for fdroid flavor")
if (MainApplication.forceDebugLogging) Timber.d("Disabling update activity for fdroid flavor")
// disable update activity through package manager
pm.setComponentEnabledSetting(
componentName,

@ -196,7 +196,7 @@ class AndroidacyActivity : AppCompatActivity() {
// sanitize url
@Suppress("NAME_SHADOWING") var url = request.url.toString()
url = AndroidacyUtil.hideToken(url)
Timber.i("Exiting WebView %s", url)
if (MainApplication.forceDebugLogging) Timber.i("Exiting WebView %s", url)
IntentHelper.openUri(view.context, request.url.toString())
return true
}
@ -311,17 +311,17 @@ class AndroidacyActivity : AppCompatActivity() {
override fun onProgressChanged(view: WebView, newProgress: Int) {
if (downloadMode) return
if (newProgress != 100 && prgInd.visibility != View.VISIBLE) {
Timber.i("Progress: %d, showing progress bar", newProgress)
if (MainApplication.forceDebugLogging) Timber.i("Progress: %d, showing progress bar", newProgress)
prgInd.visibility = View.VISIBLE
}
// if progress is greater than one, set indeterminate to false
if (newProgress > 1) {
Timber.i("Progress: %d, setting indeterminate to false", newProgress)
if (MainApplication.forceDebugLogging) Timber.i("Progress: %d, setting indeterminate to false", newProgress)
prgInd.isIndeterminate = false
}
prgInd.setProgress(newProgress, true)
if (newProgress == 100 && prgInd.visibility != View.GONE) {
Timber.i("Progress: %d, hiding progress bar", newProgress)
if (MainApplication.forceDebugLogging) Timber.i("Progress: %d, hiding progress bar", newProgress)
prgInd.isIndeterminate = true
prgInd.visibility = View.GONE
}
@ -332,9 +332,9 @@ class AndroidacyActivity : AppCompatActivity() {
if (downloadMode && isDownloadUrl(downloadUrl)) {
megaIntercept(pageUrl, downloadUrl)
}
Timber.i("Download mode is on")
if (MainApplication.forceDebugLogging) Timber.i("Download mode is on")
if (AndroidacyUtil.isAndroidacyLink(downloadUrl) && !backOnResume) {
Timber.i("Androidacy link detected")
if (MainApplication.forceDebugLogging) Timber.i("Androidacy link detected")
val androidacyWebAPI = androidacyWebAPI
if (androidacyWebAPI != null) {
if (!androidacyWebAPI.downloadMode) {
@ -343,12 +343,12 @@ class AndroidacyActivity : AppCompatActivity() {
// Workaround Androidacy bug
val moduleId = moduleIdOfUrl(downloadUrl)
if (megaIntercept(wbv.url, downloadUrl)) {
Timber.i("megaIntercept failure 2. Forcing onBackPress")
if (MainApplication.forceDebugLogging) Timber.i("megaIntercept failure 2. Forcing onBackPress")
// Block request as Androidacy doesn't allow duplicate requests
return@setDownloadListener
} else if (moduleId != null) {
// Download module
Timber.i("megaIntercept failure. Forcing onBackPress")
if (MainApplication.forceDebugLogging) Timber.i("megaIntercept failure. Forcing onBackPress")
finish()
}
}
@ -356,7 +356,7 @@ class AndroidacyActivity : AppCompatActivity() {
androidacyWebAPI.downloadMode = false
}
backOnResume = true
Timber.i("Exiting WebView %s", AndroidacyUtil.hideToken(downloadUrl))
if (MainApplication.forceDebugLogging) Timber.i("Exiting WebView %s", AndroidacyUtil.hideToken(downloadUrl))
for (prefix in arrayOf<String>(
"https://production-api.androidacy.com/magisk/file//",
"https://staging-api.androidacy.com/magisk/file/"
@ -365,7 +365,7 @@ class AndroidacyActivity : AppCompatActivity() {
return@setDownloadListener
}
}
IntentHelper.openCustomTab(this, downloadUrl)
IntentHelper.startDownloadUsingDownloadManager(this, downloadUrl, title)
}
})
androidacyWebAPI = AndroidacyWebAPI(this, allowInstall)
@ -452,7 +452,7 @@ class AndroidacyActivity : AppCompatActivity() {
val androidacyWebAPI = androidacyWebAPI
val moduleId = AndroidacyUtil.getModuleId(fileUrl)
if (moduleId == null) {
Timber.i("No module id?")
if (MainApplication.forceDebugLogging) Timber.i("No module id?")
// Re-open the page
webView!!.loadUrl(pageUrl + "&force_refresh=" + System.currentTimeMillis())
}
@ -503,7 +503,7 @@ class AndroidacyActivity : AppCompatActivity() {
webView!!.removeAllViews()
webView!!.destroy() // fix memory leak
}
Timber.i("onDestroy for %s", this)
if (MainApplication.forceDebugLogging) Timber.i("onDestroy for %s", this)
}
companion object {

@ -13,6 +13,7 @@ import android.widget.Toast
import com.fingerprintjs.android.fingerprint.Fingerprinter
import com.fingerprintjs.android.fingerprint.FingerprinterFactory.create
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.INSTANCE
import com.fox2code.mmm.MainApplication.Companion.getSharedPreferences
import com.fox2code.mmm.R
@ -84,7 +85,7 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
// response is JSON
val jsonObject = JSONObject(String(resp))
memberLevel = jsonObject.getString("role")
if (BuildConfig.DEBUG) Timber.d("Member level: %s", memberLevel)
if (MainApplication.forceDebugLogging) Timber.d("Member level: %s", memberLevel)
val memberPermissions = jsonObject.getJSONArray("permissions")
// set role and permissions on userInfo property
userInfo = arrayOf(
@ -209,16 +210,16 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
token =
getSharedPreferences("androidacy")?.getString("pref_androidacy_api_token", null)
if (token != null && !isValidToken(token)) {
Timber.i("Token expired or invalid, requesting new one...")
if (MainApplication.forceDebugLogging) Timber.i("Token expired or invalid, requesting new one...")
token = null
} else {
Timber.i("Using cached token")
if (MainApplication.forceDebugLogging) Timber.i("Using cached token")
}
} else if (!isValidToken(token)) {
Timber.i("Token expired, requesting new one...")
if (MainApplication.forceDebugLogging) Timber.i("Token expired, requesting new one...")
token = null
} else {
Timber.i("Using validated cached token")
if (MainApplication.forceDebugLogging) Timber.i("Using validated cached token")
}
} catch (e: IOException) {
if (shouldTimeout(e)) {
@ -228,9 +229,9 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
return false
}
if (token == null) {
Timber.i("Token is null, requesting new one...")
if (MainApplication.forceDebugLogging) Timber.i("Token is null, requesting new one...")
try {
Timber.i("Requesting new token...")
if (MainApplication.forceDebugLogging) Timber.i("Requesting new token...")
token = requestNewToken()
// Parse token
// Ensure token is valid
@ -252,7 +253,7 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
val editor = getSharedPreferences("androidacy")!!.edit()
editor.putString("pref_androidacy_api_token", token)
editor.apply()
Timber.i("Token saved to shared preference")
if (MainApplication.forceDebugLogging) Timber.i("Token saved to shared preference")
}
} catch (e: Exception) {
if (shouldTimeout(e)) {
@ -270,7 +271,7 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
@Throws(JSONException::class)
override fun populate(jsonObject: JSONObject): List<RepoModule>? {
var jsonObject = jsonObject
if (BuildConfig.DEBUG) Timber.d("AndroidacyRepoData populate start")
if (MainApplication.forceDebugLogging) Timber.d("AndroidacyRepoData populate start")
val name = jsonObject.optString("name", "Androidacy Modules Repo")
val nameForModules =
if (name.endsWith(" (Official)")) name.substring(0, name.length - 11) else name
@ -297,7 +298,7 @@ class AndroidacyRepoData(cacheRoot: File?, testMode: Boolean) : RepoData(
if (!jsonArray.isNull(i)) {
jsonObject = jsonArray.getJSONObject(i)
} else {
if (BuildConfig.DEBUG) Timber.d("Skipping null module at index %d", i)
if (MainApplication.forceDebugLogging) Timber.d("Skipping null module at index %d", i)
continue
}
} catch (e: JSONException) {

@ -32,6 +32,7 @@ import com.fox2code.mmm.utils.ExternalHelper
import com.fox2code.mmm.utils.IntentHelper.Companion.openCustomTab
import com.fox2code.mmm.utils.IntentHelper.Companion.openInstaller
import com.fox2code.mmm.utils.IntentHelper.Companion.openUrl
import com.fox2code.mmm.utils.IntentHelper.Companion.startDownloadUsingDownloadManager
import com.fox2code.mmm.utils.io.Files.Companion.readSU
import com.fox2code.mmm.utils.io.Files.Companion.writeSU
import com.fox2code.mmm.utils.io.Hashes.Companion.checkSumFormat
@ -74,7 +75,7 @@ class AndroidacyWebAPI(
checksum: String?,
canInstall: Boolean
) {
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"ModuleDialog, downloadUrl: " + hideToken(
moduleUrl!!
) + ", moduleId: " + moduleId + ", installTitle: " + installTitle + ", checksum: " + checksum + ", canInstall: " + canInstall
@ -112,7 +113,9 @@ class AndroidacyWebAPI(
.setIcon(R.drawable.ic_baseline_extension_24)
builder.setNegativeButton(R.string.download_module) { _: DialogInterface?, _: Int ->
downloadMode = true
openCustomTab(activity, moduleUrl)
startDownloadUsingDownloadManager(activity, moduleUrl, title)
// close activity
activity.runOnUiThread { activity.finishAndRemoveTask() }
}
if (canInstall) {
var hasUpdate = false
@ -174,7 +177,7 @@ class AndroidacyWebAPI(
fun notifyCompatModeRaw(value: Int) {
var value = value
if (consumedAction) return
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Androidacy Compat mode: %s", value)
if (MainApplication.forceDebugLogging) Timber.d("Androidacy Compat mode: %s", value)
notifiedCompatMode = value
if (value < 0) {
value = 0
@ -208,7 +211,7 @@ class AndroidacyWebAPI(
if (consumedAction) return
consumedAction = true
downloadMode = false
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Received openUrl request: %s", url)
if (MainApplication.forceDebugLogging) Timber.d("Received openUrl request: %s", url)
if (Uri.parse(url).scheme == "https") {
openUrl(activity, url)
}
@ -222,7 +225,7 @@ class AndroidacyWebAPI(
if (consumedAction) return
consumedAction = true
downloadMode = false
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Received openCustomTab request: %s", url)
if (MainApplication.forceDebugLogging) Timber.d("Received openCustomTab request: %s", url)
if (Uri.parse(url).scheme == "https") {
openCustomTab(activity, url)
}
@ -266,7 +269,7 @@ class AndroidacyWebAPI(
}
consumedAction = true
downloadMode = false
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Received install request: $moduleUrl $installTitle $checksum")
if (MainApplication.forceDebugLogging) Timber.d("Received install request: $moduleUrl $installTitle $checksum")
if (!isAndroidacyLink(moduleUrl)) {
forceQuitRaw("Non Androidacy module link used on Androidacy")
return

@ -178,7 +178,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
builder.setContentText(context.getString(R.string.notification_channel_background_update_description))
notificationManager.notify(NOTIFICATION_ID_ONGOING, builder.build())
} else {
if (BuildConfig.DEBUG) Timber.d("Not posting notification because of missing permission")
if (MainApplication.forceDebugLogging) Timber.d("Not posting notification because of missing permission")
}
ModuleManager.instance!!.scanAsync()
RepoManager.getINSTANCE()!!.update(null)
@ -211,7 +211,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
for (s in stringSet!!) {
if (s.startsWith(localModuleInfo.id)) {
version = s
if (BuildConfig.DEBUG) Timber.d("igV: %s", version)
if (MainApplication.forceDebugLogging) Timber.d("igV: %s", version)
break
}
}
@ -222,7 +222,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
remoteVersionCode = repoModule.moduleInfo.versionCode.toString()
}
if (version.isNotEmpty()) {
if (BuildConfig.DEBUG) Timber.d("igV found: %s", version)
if (MainApplication.forceDebugLogging) Timber.d("igV found: %s", version)
val remoteVersionCodeInt = remoteVersionCode.toInt()
val wantsVersion =
version.split(":".toRegex()).dropLastWhile { it.isEmpty() }
@ -232,23 +232,23 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
version = version.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1]
if (version.startsWith("^")) {
if (BuildConfig.DEBUG) Timber.d("igV: newer")
if (MainApplication.forceDebugLogging) Timber.d("igV: newer")
// the wantsversion and newer
if (remoteVersionCodeInt >= wantsVersion) {
if (BuildConfig.DEBUG) Timber.d("igV: skipping")
if (MainApplication.forceDebugLogging) Timber.d("igV: skipping")
// if it is, we skip it
continue
}
} else if (version.endsWith("$")) {
if (BuildConfig.DEBUG) Timber.d("igV: older")
if (MainApplication.forceDebugLogging) Timber.d("igV: older")
// this wantsversion and older
if (remoteVersionCodeInt <= wantsVersion) {
if (BuildConfig.DEBUG) Timber.d("igV: skipping")
if (MainApplication.forceDebugLogging) Timber.d("igV: skipping")
// if it is, we skip it
continue
}
} else if (wantsVersion == remoteVersionCodeInt) {
if (BuildConfig.DEBUG) Timber.d("igV: equal")
if (MainApplication.forceDebugLogging) Timber.d("igV: equal")
// if it is, we skip it
continue
}
@ -272,7 +272,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
}
}
if (moduleUpdateCount != 0) {
if (BuildConfig.DEBUG) Timber.d("Found %d updates", moduleUpdateCount)
if (MainApplication.forceDebugLogging) Timber.d("Found %d updates", moduleUpdateCount)
postNotification(context, updateableModules, moduleUpdateCount, false)
}
}
@ -286,10 +286,10 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
try {
val shouldUpdate = AppUpdateManager.appUpdateManager.checkUpdate(true)
if (shouldUpdate) {
if (BuildConfig.DEBUG) Timber.d("Found app update")
if (MainApplication.forceDebugLogging) Timber.d("Found app update")
postNotificationForAppUpdate(context)
} else {
if (BuildConfig.DEBUG) Timber.d("No app update found")
if (MainApplication.forceDebugLogging) Timber.d("No app update found")
}
} catch (e: Exception) {
Timber.e("Failed to check for app update")
@ -302,7 +302,7 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
if (BuildConfig.DEBUG) Timber.d("Removing notification")
if (MainApplication.forceDebugLogging) Timber.d("Removing notification")
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.cancel(NOTIFICATION_ID_ONGOING)
}
@ -415,11 +415,11 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
).build()
)
notificationManagerCompat.cancel(NOTIFICATION_ID_ONGOING)
if (BuildConfig.DEBUG) Timber.d("Scheduling periodic background check")
if (MainApplication.forceDebugLogging) Timber.d("Scheduling periodic background check")
// use pref_background_update_check_frequency to set frequency. value is in minutes
val frequency = MainApplication.getSharedPreferences("mmm")!!
.getInt("pref_background_update_check_frequency", 60).toLong()
if (BuildConfig.DEBUG) Timber.d("Frequency: $frequency minutes")
if (MainApplication.forceDebugLogging) Timber.d("Frequency: $frequency minutes")
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"background_checker",
ExistingPeriodicWorkPolicy.UPDATE,

@ -202,7 +202,7 @@ class InstallerActivity : AppCompatActivity() {
// Set this to the error message if it's a HTTP error
var rawModule: ByteArray?
try {
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"%s%s", if (urlMode) "Downloading: " else "Loading: ", AndroidacyUtil.hideToken(
target
)
@ -225,7 +225,7 @@ class InstallerActivity : AppCompatActivity() {
}
if (canceled) return@Runnable
if (!checksum.isNullOrEmpty()) {
Timber.i("Checking for checksum: %s", checksum.toString())
if (MainApplication.forceDebugLogging) Timber.i("Checking for checksum: %s", checksum.toString())
runOnUiThread { installerTerminal!!.addLine("- Checking file integrity") }
if (!checkSumMatch(rawModule, checksum)) {
setInstallStateFinished(false, "! File integrity check failed", "")
@ -332,7 +332,7 @@ class InstallerActivity : AppCompatActivity() {
if (canceled) return
// disable back
runOnUiThread { cancelFloatingButton!!.isEnabled = false }
Timber.i("Installing: %s", moduleCache!!.name)
if (MainApplication.forceDebugLogging) Timber.i("Installing: %s", moduleCache!!.name)
val installerController = InstallerController(
progressIndicator, installerTerminal, file!!.absoluteFile, noExtensions
)
@ -361,7 +361,7 @@ class InstallerActivity : AppCompatActivity() {
}
}
} catch (e: Exception) {
Timber.i(e)
if (MainApplication.forceDebugLogging) Timber.i(e)
}
installerMonitor = InstallerMonitor(installScript)
installJob = Shell.cmd(
@ -690,7 +690,16 @@ class InstallerActivity : AppCompatActivity() {
override fun onAddElement(s: String?) {
var s = s ?: return
if (!enabled) return
Timber.i("MSG: %s", s)
// sanitize string for logging
if (MainApplication.forceDebugLogging) {
var tempS = s
if (tempS.length > 100) tempS = tempS.substring(0, 100) + "..."
// remove ansii color codes
tempS = tempS.replace("\u001B\\[[;\\d]*m".toRegex(), "")
// remove non-printable characters and replace with ?
tempS = tempS.replace("[^\\p{Print}]".toRegex(), "?")
Timber.i("New line: %s", tempS)
}
if ("#!useExt" == s.trim { it <= ' ' } && !noExtension) {
useExt = true
return
@ -816,7 +825,7 @@ class InstallerActivity : AppCompatActivity() {
override fun onAddElement(e: String?) {
val e = e ?: return
Timber.i("Monitor: %s", e)
if (MainApplication.forceDebugLogging) Timber.i("Monitor: %s", e)
lastCommand = e
}

@ -139,7 +139,7 @@ class InstallerInitializer {
).to(output).exec().isSuccess
) {
if (BuildConfig.DEBUG) {
Timber.i("Failed to search for ramdisk")
if (MainApplication.forceDebugLogging) Timber.i("Failed to search for ramdisk")
}
if (output.size != 0) {
hsRmdsk = "false" == output[0] || "true".equals(
@ -150,8 +150,8 @@ class InstallerInitializer {
return null
}
if (BuildConfig.DEBUG) {
Timber.i("Found ramdisk: %s", output[0])
Timber.i("Searching for Magisk path. Current path: %s", mgskPth)
if (MainApplication.forceDebugLogging) Timber.i("Found ramdisk: %s", output[0])
if (MainApplication.forceDebugLogging) Timber.i("Searching for Magisk path. Current path: %s", mgskPth)
}
// reset output
output.clear()
@ -161,7 +161,7 @@ class InstallerInitializer {
)) {
mgskPth = output[0]
if (BuildConfig.DEBUG) {
Timber.i("Magisk path 1: %s", mgskPth)
if (MainApplication.forceDebugLogging) Timber.i("Magisk path 1: %s", mgskPth)
}
} else if (Shell.cmd("if [ -d /data/adb/ksu ]; then echo true; else echo false; fi", "su -V").to(
output
@ -172,7 +172,7 @@ class InstallerInitializer {
Shell.cmd("su -v").to(suVer).exec()
if (suVer.size > 0 && suVer[0].contains("ksu") || suVer[0].contains("Kernelsu", true)) {
if (BuildConfig.DEBUG) {
Timber.i("Kernelsu detected")
if (MainApplication.forceDebugLogging) Timber.i("Kernelsu detected")
}
mgskPth = "/data/adb"
isKsu = true
@ -192,9 +192,9 @@ class InstallerInitializer {
}
return null
}
Timber.i("Magisk runtime path: %s", mgskPth)
if (MainApplication.forceDebugLogging) Timber.i("Magisk runtime path: %s", mgskPth)
mgskVerCode = output[1].toInt()
Timber.i("Magisk version code: %s", mgskVerCode)
if (MainApplication.forceDebugLogging) Timber.i("Magisk version code: %s", mgskVerCode)
if (mgskVerCode >= Constants.MAGISK_VER_CODE_FLAT_MODULES && mgskVerCode < Constants.MAGISK_VER_CODE_PATH_SUPPORT && (mgskPth.isEmpty() || !File(
mgskPth
).exists())

@ -6,7 +6,6 @@ package com.fox2code.mmm.manager
import android.content.SharedPreferences
import androidx.room.Room
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.installer.InstallerInitializer.Companion.peekModulesPath
import com.fox2code.mmm.utils.SyncManager
@ -56,10 +55,10 @@ class ModuleManager private constructor() : SyncManager() {
if (!FORCE_NEED_FALLBACK && needFallback) {
Timber.e("using fallback instead.")
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Scan")
if (MainApplication.forceDebugLogging) Timber.d("Scan")
val modulesList = StringBuilder()
if (modules != null) {
Timber.i("Found %d modules on device in data", modules.size)
if (MainApplication.forceDebugLogging) Timber.i("Found %d modules on device in data", modules.size)
val db = Room.databaseBuilder(
MainApplication.INSTANCE!!,
ModuleListCacheDatabase::class.java,
@ -69,7 +68,7 @@ class ModuleManager private constructor() : SyncManager() {
if (!SuFile("/data/adb/modules/$module").isDirectory) continue // Ignore non directory files inside modules folder
// don't care about lost+found (case insensitive)
if (module.equals("lost+found", ignoreCase = true)) continue
if (BuildConfig.DEBUG) Timber.d("Found module %s", module)
if (MainApplication.forceDebugLogging) Timber.d("Found module %s", module)
var moduleInfo = moduleInfos[module]
// next, merge the module info with a record from ModuleListCache room db if it exists
// initialize modulelistcache db
@ -80,7 +79,7 @@ class ModuleManager private constructor() : SyncManager() {
moduleInfo = LocalModuleInfo(module)
}
if (moduleListCacheDao.exists(module)) {
if (BuildConfig.DEBUG) Timber.d("Found cache for %s", module)
if (MainApplication.forceDebugLogging) Timber.d("Found cache for %s", module)
val moduleListCache: ModuleListCache = moduleListCacheDao.getByCodename(module)
moduleInfo.name =
if (moduleListCache.name != "") moduleListCache.name else module
@ -130,7 +129,7 @@ class ModuleManager private constructor() : SyncManager() {
moduleInfo, "/data/adb/modules/$module/module.prop", true
)
} catch (e: Exception) {
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(e)
if (MainApplication.forceDebugLogging) Timber.d(e)
moduleInfo.flags = moduleInfo.flags or FLAG_MM_INVALID
}
moduleInfos[module] = moduleInfo
@ -140,7 +139,7 @@ class ModuleManager private constructor() : SyncManager() {
}
db.close()
} else {
Timber.i("No modules on device in data")
if (MainApplication.forceDebugLogging) Timber.i("No modules on device in data")
}
if (modulesList.isNotEmpty()) {
modulesList.deleteCharAt(modulesList.length - 1)
@ -151,12 +150,12 @@ class ModuleManager private constructor() : SyncManager() {
put("modules", modulesList.toString())
})
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Scan update")
if (MainApplication.forceDebugLogging) Timber.d("Scan update")
val modulesUpdate = SuFile("/data/adb/modules_update").list()
if (modulesUpdate != null) {
for (module in modulesUpdate) {
if (!SuFile("/data/adb/modules_update/$module").isDirectory) continue // Ignore non directory files inside modules folder
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(module)
if (MainApplication.forceDebugLogging) Timber.d(module)
var moduleInfo = moduleInfos[module]
if (moduleInfo == null) {
moduleInfo = LocalModuleInfo(module)
@ -169,17 +168,17 @@ class ModuleManager private constructor() : SyncManager() {
moduleInfo, "/data/adb/modules_update/$module/module.prop", true
)
} catch (e: Exception) {
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(e)
if (MainApplication.forceDebugLogging) Timber.d(e)
moduleInfo.flags = moduleInfo.flags or FLAG_MM_INVALID
}
}
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Finalize scan")
if (MainApplication.forceDebugLogging) Timber.d("Finalize scan")
updatableModuleCount = 0
val moduleInfoIterator = moduleInfos.values.iterator()
while (moduleInfoIterator.hasNext()) {
val moduleInfo = moduleInfoIterator.next()
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(moduleInfo.id)
if (MainApplication.forceDebugLogging) Timber.d(moduleInfo.id)
if (moduleInfo.flags and FLAG_MM_UNPROCESSED != 0) {
moduleInfoIterator.remove()
continue // Don't process fallbacks if unreferenced
@ -226,7 +225,7 @@ class ModuleManager private constructor() : SyncManager() {
}
fun setEnabledState(moduleInfo: ModuleInfo, checked: Boolean): Boolean {
if (BuildConfig.DEBUG) Timber.d("setEnabledState(%s, %s)", moduleInfo.id, checked)
if (MainApplication.forceDebugLogging) Timber.d("setEnabledState(%s, %s)", moduleInfo.id, checked)
if (moduleInfo.hasFlag(ModuleInfo.FLAG_MODULE_UPDATING) && !checked) return false
val disable = SuFile("/data/adb/modules/" + moduleInfo.id + "/disable")
if (checked) {

@ -72,7 +72,7 @@ class MarkdownActivity : AppCompatActivity() {
finish()
return
}
Timber.i("Url for markdown %s", url.toString())
if (MainApplication.forceDebugLogging) Timber.i("Url for markdown %s", url.toString())
setContentView(R.layout.markdown_view)
val markdownBackground = findViewById<ViewGroup>(R.id.markdownBackground)
val textView = findViewById<TextView>(R.id.markdownView)
@ -89,11 +89,11 @@ class MarkdownActivity : AppCompatActivity() {
if (maxApi != 0) this.addChip(MarkdownChip.MAX_SDK, parseAndroidVersion(maxApi))
Thread({
try {
Timber.i("Downloading")
if (MainApplication.forceDebugLogging) Timber.i("Downloading")
val rawMarkdown = getRawMarkdown(url)
Timber.i("Encoding")
if (MainApplication.forceDebugLogging) Timber.i("Encoding")
val markdown = String(rawMarkdown, StandardCharsets.UTF_8)
Timber.i("Done!")
if (MainApplication.forceDebugLogging) Timber.i("Done!")
runOnUiThread {
MainApplication.INSTANCE!!.markwon?.setMarkdown(
textView, MarkdownUrlLinker.urlLinkify(markdown)

@ -4,7 +4,7 @@
package com.fox2code.mmm.markdown
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import timber.log.Timber
enum class MarkdownUrlLinker {
@ -33,7 +33,7 @@ enum class MarkdownUrlLinker {
if (endDomain != -1 && endDomain < end && endCh != '>' && endCh != ')' && endCh != ']') {
linkifyTasks.add(LinkifyTask(index, end))
extra += end - index + 4
if (BuildConfig.DEBUG) Timber.d("Linkify url: %s", url.substring(end))
if (MainApplication.forceDebugLogging) Timber.d("Linkify url: %s", url.substring(end))
}
}
index = url.indexOf("https://", end)
@ -48,7 +48,7 @@ enum class MarkdownUrlLinker {
prev = linkifyTask
}
if (prev.end != url.length) stringBuilder.append(url, prev.end, url.length)
Timber.i("Added Markdown link to " + linkifyTasks.size + " urls")
if (MainApplication.forceDebugLogging) Timber.i("Added Markdown link to " + linkifyTasks.size + " urls")
return stringBuilder.toString()
}
}

@ -11,7 +11,6 @@ import android.text.Spanned
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.DrawableRes
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.INSTANCE
import com.fox2code.mmm.MainApplication.Companion.isShowcaseMode
@ -22,11 +21,11 @@ import com.fox2code.mmm.manager.ModuleInfo
import com.fox2code.mmm.manager.ModuleManager.Companion.instance
import com.fox2code.mmm.utils.ExternalHelper
import com.fox2code.mmm.utils.IntentHelper.Companion.openConfig
import com.fox2code.mmm.utils.IntentHelper.Companion.openCustomTab
import com.fox2code.mmm.utils.IntentHelper.Companion.openInstaller
import com.fox2code.mmm.utils.IntentHelper.Companion.openMarkdown
import com.fox2code.mmm.utils.IntentHelper.Companion.openUrl
import com.fox2code.mmm.utils.IntentHelper.Companion.openUrlAndroidacy
import com.fox2code.mmm.utils.IntentHelper.Companion.startDownloadUsingDownloadManager
import com.google.android.material.chip.Chip
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.noties.markwon.Markwon
@ -198,12 +197,15 @@ enum class ActionButtonType {
} else {
builder.setMessage(desc)
}
Timber.i("URL: %s", updateZipUrl)
builder.setNegativeButton(R.string.download_module) { _: DialogInterface?, _: Int ->
openCustomTab(
if (MainApplication.forceDebugLogging) Timber.i("URL: %s", updateZipUrl)
builder.setNegativeButton(R.string.download_module) { d: DialogInterface?, _: Int ->
startDownloadUsingDownloadManager(
button.context,
updateZipUrl
updateZipUrl,
moduleInfo.name,
)
// close the dialog and finish
d?.cancel()
}
if (hasRoot) {
builder.setPositiveButton(if (moduleHolder.hasUpdate()) R.string.update_module else R.string.install_module) { _: DialogInterface?, _: Int ->
@ -270,7 +272,7 @@ enum class ActionButtonType {
put("module", name ?: "null")
})
}
Timber.i(Integer.toHexString(moduleHolder.moduleInfo?.flags ?: 0))
if (MainApplication.forceDebugLogging) Timber.i(Integer.toHexString(moduleHolder.moduleInfo?.flags ?: 0))
if (!instance!!.setUninstallState(
moduleHolder.moduleInfo!!, !moduleHolder.hasFlag(
ModuleInfo.FLAG_MODULE_UNINSTALLING
@ -435,7 +437,7 @@ if (MainApplication.analyticsAllowed()) {
REMOTE {
@Suppress("NAME_SHADOWING")
override fun doAction(button: Chip, moduleHolder: ModuleHolder) {
if (BuildConfig.DEBUG) Timber.d("doAction: remote module for %s", moduleHolder.moduleInfo?.name ?: "null")
if (MainApplication.forceDebugLogging) Timber.d("doAction: remote module for %s", moduleHolder.moduleInfo?.name ?: "null")
// that module is from remote repo
val name: String? = if (moduleHolder.moduleInfo != null) {
moduleHolder.moduleInfo!!.name
@ -493,13 +495,13 @@ if (MainApplication.analyticsAllowed()) {
madb.setPositiveButton(
R.string.reinstall
) { _: DialogInterface?, _: Int ->
if (BuildConfig.DEBUG) Timber.d("Set moduleinfo to %s", moduleInfo.name)
if (MainApplication.forceDebugLogging) Timber.d("Set moduleinfo to %s", moduleInfo.name)
val name: String? = if (moduleHolder.moduleInfo != null) {
moduleHolder.moduleInfo!!.name
} else {
moduleHolder.repoModule?.moduleInfo?.name
}
if (BuildConfig.DEBUG) Timber.d("doAction: remote module for %s", name)
if (MainApplication.forceDebugLogging) Timber.d("doAction: remote module for %s", name)
if (MainApplication.analyticsAllowed()) {
Countly.sharedInstance().events().recordEvent("view_update_install", HashMap<String, Any>().apply {
put("module", name ?: "null")
@ -507,7 +509,7 @@ if (MainApplication.analyticsAllowed()) {
}
// Androidacy manage the selection between download and install
if (isAndroidacyLink(updateZipUrl)) {
if (BuildConfig.DEBUG) Timber.d("Androidacy link detected")
if (MainApplication.forceDebugLogging) Timber.d("Androidacy link detected")
openUrlAndroidacy(
button.context,
updateZipUrl,
@ -534,12 +536,14 @@ if (MainApplication.analyticsAllowed()) {
} else {
builder.setMessage(desc)
}
Timber.i("URL: %s", updateZipUrl)
builder.setNegativeButton(R.string.download_module) { _: DialogInterface?, _: Int ->
openCustomTab(
if (MainApplication.forceDebugLogging) Timber.i("URL: %s", updateZipUrl)
builder.setNegativeButton(R.string.download_module) { d: DialogInterface?, _: Int ->
startDownloadUsingDownloadManager(
button.context,
updateZipUrl
updateZipUrl,
moduleInfo.name,
)
d?.cancel()
}
if (hasRoot) {
builder.setPositiveButton(if (moduleHolder.hasUpdate()) R.string.update_module else R.string.install_module) { _: DialogInterface?, _: Int ->

@ -7,7 +7,7 @@ import android.content.Context
import android.content.pm.PackageManager
import android.view.View
import androidx.annotation.StringRes
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.INSTANCE
import com.fox2code.mmm.MainApplication.Companion.formatTime
import com.fox2code.mmm.MainApplication.Companion.getSharedPreferences
@ -117,7 +117,7 @@ class ModuleHolder : Comparable<ModuleHolder?> {
} else if (moduleInfo == null && repoModule != null) {
Type.INSTALLABLE
} else if (moduleInfo!!.versionCode < moduleInfo!!.updateVersionCode || repoModule != null && moduleInfo!!.versionCode < repoModule!!.moduleInfo.versionCode) {
Timber.i("Module %s is updateable", moduleId)
if (MainApplication.forceDebugLogging) Timber.i("Module %s is updateable", moduleId)
var ignoreUpdate = false
try {
if (getSharedPreferences("mmm")?.getStringSet(
@ -138,13 +138,13 @@ class ModuleHolder : Comparable<ModuleHolder?> {
HashSet()
)
var version = ""
if (BuildConfig.DEBUG) Timber.d(stringSetT.toString())
if (MainApplication.forceDebugLogging) Timber.d(stringSetT.toString())
// unfortunately, stringset.contains() doesn't work for partial matches
// so we have to iterate through the set
for (s in stringSetT!!) {
if (s.startsWith(moduleInfo!!.id)) {
version = s
if (BuildConfig.DEBUG) Timber.d("igV: %s", version)
if (MainApplication.forceDebugLogging) Timber.d("igV: %s", version)
break
}
}
@ -158,34 +158,34 @@ class ModuleHolder : Comparable<ModuleHolder?> {
val wantsVersion = version.split(":".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1].replace("[^0-9]".toRegex(), "").toInt()
// now find out if user wants up to and including this version, or this version and newer
if (BuildConfig.DEBUG) Timber.d("igV start with")
if (MainApplication.forceDebugLogging) Timber.d("igV start with")
version =
version.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
// this version and newer
if (version.startsWith("^")) {
if (BuildConfig.DEBUG) Timber.d("igV: newer")
if (MainApplication.forceDebugLogging) Timber.d("igV: newer")
// the wantsversion and newer
if (remoteVersionCodeInt >= wantsVersion) {
if (BuildConfig.DEBUG) Timber.d("igV: skipping")
if (MainApplication.forceDebugLogging) Timber.d("igV: skipping")
// if it is, we skip it
ignoreUpdate = true
}
} else if (version.endsWith("$")) {
if (BuildConfig.DEBUG) Timber.d("igV: older")
if (MainApplication.forceDebugLogging) Timber.d("igV: older")
// this wantsversion and older
if (remoteVersionCodeInt <= wantsVersion) {
if (BuildConfig.DEBUG) Timber.d("igV: skipping")
if (MainApplication.forceDebugLogging) Timber.d("igV: skipping")
// if it is, we skip it
ignoreUpdate = true
}
} else if (wantsVersion == remoteVersionCodeInt) {
if (BuildConfig.DEBUG) Timber.d("igV: equal")
if (MainApplication.forceDebugLogging) Timber.d("igV: equal")
// if it is, we skip it
ignoreUpdate = true
}
}
if (ignoreUpdate) {
if (BuildConfig.DEBUG) Timber.d("Module %s has update, but is ignored", moduleId)
if (MainApplication.forceDebugLogging) Timber.d("Module %s has update, but is ignored", moduleId)
Type.INSTALLABLE
} else {
INSTANCE!!.modulesHaveUpdates = true
@ -193,7 +193,7 @@ class ModuleHolder : Comparable<ModuleHolder?> {
INSTANCE!!.updateModules += moduleId
INSTANCE!!.updateModuleCount++
}
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"modulesHaveUpdates = %s, updateModuleCount = %s",
INSTANCE!!.modulesHaveUpdates,
INSTANCE!!.updateModuleCount
@ -250,16 +250,16 @@ class ModuleHolder : Comparable<ModuleHolder?> {
// set updatezipurl on moduleholder
if (localModuleInfo.updateZipUrl != null) {
if (BuildConfig.DEBUG) Timber.d("localModuleInfo: %s", localModuleInfo.updateZipUrl)
if (MainApplication.forceDebugLogging) Timber.d("localModuleInfo: %s", localModuleInfo.updateZipUrl)
updateZipUrl = localModuleInfo.updateZipUrl
}
if (repoModule != null) {
if (BuildConfig.DEBUG) Timber.d("repoModule: %s", repoModule!!.zipUrl)
if (MainApplication.forceDebugLogging) Timber.d("repoModule: %s", repoModule!!.zipUrl)
updateZipUrl = repoModule!!.zipUrl
}
// last ditch effort, try to get remoteModuleInfo from localModuleInfo
if (rInfo != null) {
if (BuildConfig.DEBUG) Timber.d("remoteModuleInfo: %s", rInfo.zipUrl)
if (MainApplication.forceDebugLogging) Timber.d("remoteModuleInfo: %s", rInfo.zipUrl)
updateZipUrl = rInfo.zipUrl
moduleInfo?.updateZipUrl = rInfo.zipUrl
}

@ -26,7 +26,6 @@ import androidx.annotation.StringRes
import androidx.cardview.widget.CardView
import androidx.core.graphics.ColorUtils
import androidx.recyclerview.widget.RecyclerView
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
import com.fox2code.mmm.manager.ModuleInfo
@ -400,7 +399,7 @@ ${getString(R.string.module_repo)} ${moduleHolder.repoName}""" + if ((repoModule
// get string value of Theme
val themeName = theme.toString()
if (theme.resources.getBoolean(R.bool.force_transparency) || themeName.contains("transparent")) {
if (BuildConfig.DEBUG) Timber.d("Theme is transparent, fixing bgColor")
if (MainApplication.forceDebugLogging) Timber.d("Theme is transparent, fixing bgColor")
bgColor = ColorUtils.setAlphaComponent(bgColor, 0x70)
}
titleText.setTextColor(fgColor)

@ -41,22 +41,22 @@ class ModuleViewListBuilder(private val activity: Activity) {
Timber.w("addNotification(null) called!")
return
} else {
Timber.i("addNotification(%s) called", notificationType)
if (MainApplication.forceDebugLogging) Timber.i("addNotification(%s) called", notificationType)
}
synchronized(updateLock) { notifications.add(notificationType) }
}
fun appendInstalledModules() {
Timber.i("appendInstalledModules() called")
if (MainApplication.forceDebugLogging) Timber.i("appendInstalledModules() called")
synchronized(updateLock) {
for (moduleHolder in mappedModuleHolders.values) {
Timber.i("zeroing module %s", moduleHolder.moduleInfo?.id)
if (MainApplication.forceDebugLogging) Timber.i("zeroing module %s", moduleHolder.moduleInfo?.id)
moduleHolder.moduleInfo = null
}
val moduleManager = instance
moduleManager?.runAfterScan {
Timber.i("A0: runAfterScan %s", moduleManager.modules.size)
Timber.i("A1: %s", moduleManager.modules.size)
if (MainApplication.forceDebugLogging) Timber.i("A0: runAfterScan %s", moduleManager.modules.size)
if (MainApplication.forceDebugLogging) Timber.i("A1: %s", moduleManager.modules.size)
for (moduleInfo in moduleManager.modules.values) {
// add the local module to the list in MainActivity
MainActivity.localModuleInfoList += moduleInfo
@ -74,10 +74,10 @@ class ModuleViewListBuilder(private val activity: Activity) {
fun appendRemoteModules() {
if (BuildConfig.DEBUG) {
Timber.i("appendRemoteModules() called")
if (MainApplication.forceDebugLogging) Timber.i("appendRemoteModules() called")
}
synchronized(updateLock) {
Timber.i("appendRemoteModules() started")
if (MainApplication.forceDebugLogging) Timber.i("appendRemoteModules() started")
val startTime = System.currentTimeMillis()
val showIncompatible = MainApplication.isShowIncompatibleModules
for (moduleHolder in mappedModuleHolders.values) {
@ -85,7 +85,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
}
val repoManager = RepoManager.getINSTANCE()
repoManager?.runAfterUpdate {
Timber.i("A2: %s", repoManager.modules.size)
if (MainApplication.forceDebugLogging) Timber.i("A2: %s", repoManager.modules.size)
val no32bitSupport = Build.SUPPORTED_32_BIT_ABIS.isEmpty()
try {
for (repoModule in repoManager.modules.values) {
@ -97,7 +97,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
continue
}
if (!repoModule.repoData.isEnabled) {
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"Repo %s is disabled, skipping module %s",
repoModule.repoData.preferenceId,
repoModule.id
@ -130,7 +130,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
// retry up to five times, waiting i * 100ms between each try
if (tries < 5) {
tries++
Timber.i("appendRemoteModules() retrying in %dms", tries * 100)
if (MainApplication.forceDebugLogging) Timber.i("appendRemoteModules() retrying in %dms", tries * 100)
Handler(Looper.getMainLooper()).postDelayed({
appendRemoteModules()
}, tries * 100.toLong())
@ -139,7 +139,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
tries = 0
}
}
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"appendRemoteModules() finished in %dms",
System.currentTimeMillis() - startTime
)
@ -247,7 +247,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
// Footer is always last
//moduleHolders.add(headerFooter[1] =
// new ModuleHolder(this.footerPx * 2, false));
Timber.i("Got " + moduleHolders.size + " entries!")
if (MainApplication.forceDebugLogging) Timber.i("Got " + moduleHolders.size + " entries!")
}
} finally {
updating = false
@ -321,7 +321,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
fun setQueryChange(query: String?): Boolean {
synchronized(queryLock) {
val newQuery = query?.trim { it <= ' ' }?.lowercase() ?: ""
Timber.i("Query change " + this.query + " -> " + newQuery)
if (MainApplication.forceDebugLogging) Timber.i("Query change " + this.query + " -> " + newQuery)
if (this.query == newQuery) return false
this.query = newQuery
}
@ -333,7 +333,7 @@ class ModuleViewListBuilder(private val activity: Activity) {
private fun notifySizeChanged(
moduleViewAdapter: ModuleViewAdapter, index: Int, oldLen: Int, newLen: Int
) {
// Timber.i("A: " + index + " " + oldLen + " " + newLen);
// if (MainApplication.forceDebugLogging) Timber.i("A: " + index + " " + oldLen + " " + newLen);
if (oldLen == newLen) {
if (newLen != 0) moduleViewAdapter.notifyItemRangeChanged(index, newLen)
} else if (oldLen < newLen) {

@ -8,6 +8,7 @@ import androidx.room.Room
import com.fox2code.mmm.AppUpdateManager.Companion.shouldForceHide
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainActivity
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.INSTANCE
import com.fox2code.mmm.R
import com.fox2code.mmm.XRepo
@ -342,7 +343,7 @@ open class RepoData(url: String, cacheRoot: File) : XRepo() {
}
}
} else {
if (BuildConfig.DEBUG) Timber.d("Metadata file not found for %s", repoModule.id)
if (MainApplication.forceDebugLogging) Timber.d("Metadata file not found for %s", repoModule.id)
}
repoModule.moduleInfo.flags =
repoModule.moduleInfo.flags or ModuleInfo.FLAG_METADATA_INVALID

@ -9,7 +9,6 @@ import android.content.DialogInterface
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainActivity
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.Companion.getSharedPreferences
@ -152,18 +151,18 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
}
for (i in repoDatas.indices) {
updateListener.update(STEP1 * (i / repoDatas.size))
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Preparing to fetch: %s", repoDatas[i].name)
if (MainApplication.forceDebugLogging) Timber.d("Preparing to fetch: %s", repoDatas[i].name)
moduleToUpdate += RepoUpdater(repoDatas[i]).also { repoUpdaters[i] = it }.fetchIndex()
// divvy the 40 of step1 to each repo
updateListener.update(STEP1 * ((i + 1) / repoDatas.size))
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Updating meta-data")
if (MainApplication.forceDebugLogging) Timber.d("Updating meta-data")
var updatedModules = 0
val allowLowQualityModules = isDisableLowQualityModuleFilter
for (i in repoUpdaters.indices) {
// Check if the repo is enabled
if (!repoUpdaters[i]!!.repoData.isEnabled) {
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Skipping disabled repo: %s",
repoUpdaters[i]!!.repoData.name
)
@ -171,7 +170,7 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
}
val repoModules = repoUpdaters[i]!!.toUpdate()
val repoData = repoDatas[i]
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Registering %s", repoData.name)
if (MainApplication.forceDebugLogging) Timber.d("Registering %s", repoData.name)
for (repoModule in repoModules!!) {
try {
if (repoModule.propUrl != null && repoModule.propUrl!!.isNotEmpty()) {
@ -229,15 +228,15 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
}
MainApplication.INSTANCE!!.repoModules.putAll(modules)
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Finishing update")
if (MainApplication.forceDebugLogging) Timber.d("Finishing update")
if (hasConnectivity()) {
for (i in repoDatas.indices) {
// If repo is not enabled, skip
if (!repoDatas[i].isEnabled) {
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Skipping ${repoDatas[i].name} because it's disabled")
if (MainApplication.forceDebugLogging) Timber.d("Skipping ${repoDatas[i].name} because it's disabled")
continue
}
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG) Timber.d("Finishing: %s", repoUpdaters[i]!!.repoData.name)
if (MainApplication.forceDebugLogging) Timber.d("Finishing: %s", repoUpdaters[i]!!.repoData.name)
isLastUpdateSuccess = repoUpdaters[i]!!.finish()
if (!isLastUpdateSuccess || modules.isEmpty()) {
Timber.e("Failed to update %s", repoUpdaters[i]!!.repoData.name)
@ -280,7 +279,7 @@ class RepoManager private constructor(mainApplication: MainApplication) : SyncMa
updateListener.update(STEP1 + (STEP2 * (i / repoUpdaters.size)))
}
}
Timber.i("Got " + modules.size + " modules!")
if (MainApplication.forceDebugLogging) Timber.i("Got " + modules.size + " modules!")
updateListener.update(STEP1 + STEP2 + STEP3)
}

@ -5,7 +5,6 @@
package com.fox2code.mmm.repo
import androidx.room.Room
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.utils.io.net.Http.Companion.doHttpGet
import com.fox2code.mmm.utils.room.ModuleListCacheDatabase
@ -37,7 +36,7 @@ class RepoUpdater(repoData2: RepoData) {
}
// if MainApplication.repoModules is not empty, return it
/*if (MainApplication.INSTANCE!!.repoModules.isNotEmpty()) {
if (BuildConfig.DEBUG) Timber.d("Returning MainApplication.repoModules for %s", repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("Returning MainApplication.repoModules for %s", repoData.preferenceId)
// convert to list for toUpdate
val toUpdateList = ArrayList<RepoModule>()
for (module in MainApplication.INSTANCE!!.repoModules) {
@ -50,7 +49,7 @@ class RepoUpdater(repoData2: RepoData) {
}*/
// if we shouldn't update, get the values from the ModuleListCache realm
if (!repoData.shouldUpdate() && repoData.preferenceId == "androidacy_repo") { // for now, only enable cache reading for androidacy repo, until we handle storing module prop file values in cache
if (BuildConfig.DEBUG) Timber.d("Fetching index from cache for %s", repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("Fetching index from cache for %s", repoData.preferenceId)
// now the above but for room
val db = Room.databaseBuilder(
MainApplication.INSTANCE!!,
@ -85,7 +84,7 @@ class RepoUpdater(repoData2: RepoData) {
)
)
}
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Fetched %d modules from cache for %s, from %s records",
(toApply as HashSet<RepoModule>).size,
repoData.preferenceId,
@ -118,11 +117,11 @@ class RepoUpdater(repoData2: RepoData) {
}
// log first 100 chars of indexRaw
indexRaw = jsonObject.toString().toByteArray()
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Index raw: %s",
String(indexRaw!!, StandardCharsets.UTF_8).subSequence(0, 100)
)
if (BuildConfig.DEBUG) Timber.d("Returning %d modules for %s", toUpdate!!.size, repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("Returning %d modules for %s", toUpdate!!.size, repoData.preferenceId)
// Return repo to update
return toUpdate!!.size
}
@ -167,11 +166,11 @@ class RepoUpdater(repoData2: RepoData) {
fun finish(): Boolean {
// If repo is not enabled we don't need to do anything, just return true
if (!repoData.isEnabled) {
if (BuildConfig.DEBUG) Timber.d("Repo %s is disabled, skipping", repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("Repo %s is disabled, skipping", repoData.preferenceId)
return true
}
val success = AtomicBoolean(false)
if (BuildConfig.DEBUG) Timber.d("Finishing update for %s", repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("Finishing update for %s", repoData.preferenceId)
if (indexRaw != null) {
// set lastUpdate
val db = Room.databaseBuilder(
@ -184,7 +183,7 @@ class RepoUpdater(repoData2: RepoData) {
db.close()
success.set(true)
} else {
if (BuildConfig.DEBUG) Timber.d("No index file found for %s", repoData.preferenceId)
if (MainApplication.forceDebugLogging) Timber.d("No index file found for %s", repoData.preferenceId)
success.set(true) // assume we're reading from cache. this may be unsafe but it's better than nothing
}
return success.get()

@ -17,7 +17,6 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
import com.fox2code.rosettax.LanguageSwitcher
@ -57,7 +56,7 @@ class AppearanceFragment : PreferenceFragmentCompat() {
val themePreference = findPreference<ListPreference>("pref_theme")
// If transparent theme(s) are set, disable monet
if (themePreference!!.value == "transparent_light") {
if (BuildConfig.DEBUG) Timber.d("disabling monet")
if (MainApplication.forceDebugLogging) Timber.d("disabling monet")
findPreference<Preference>("pref_enable_monet")!!.isEnabled = false
// Toggle monet off
(findPreference<Preference>("pref_enable_monet") as TwoStatePreference?)!!.isChecked =
@ -76,11 +75,11 @@ class AppearanceFragment : PreferenceFragmentCompat() {
Preference.SummaryProvider { _: Preference? -> themePreference.entry }
themePreference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
if (BuildConfig.DEBUG) Timber.d("refreshing activity. New value: %s", newValue)
if (MainApplication.forceDebugLogging) Timber.d("refreshing activity. New value: %s", newValue)
editor.putString("pref_theme", newValue as String).apply()
// If theme contains "transparent" then disable monet
if (newValue.toString().contains("transparent")) {
if (BuildConfig.DEBUG) Timber.d("disabling monet")
if (MainApplication.forceDebugLogging) Timber.d("disabling monet")
// Show a dialogue warning the user about issues with transparent themes and
// that blur/monet will be disabled
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.transparent_theme_dialogue_title)

@ -9,6 +9,7 @@ import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.fox2code.mmm.BuildConfig
@ -91,7 +92,7 @@ class DebugFragment : PreferenceFragmentCompat() {
}
if (!BuildConfig.DEBUG || InstallerInitializer.peekMagiskPath() == null) {
// Hide the pref_crash option if not in debug mode - stop users from purposely crashing the app
Timber.i(InstallerInitializer.peekMagiskPath())
if (MainApplication.forceDebugLogging) Timber.i(InstallerInitializer.peekMagiskPath())
findPreference<Preference?>("pref_test_crash")!!.isVisible = false
} else {
if (findPreference<Preference?>("pref_test_crash") != null && findPreference<Preference?>(
@ -206,6 +207,19 @@ class DebugFragment : PreferenceFragmentCompat() {
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_logs)))
true
}
// handle pref_force_debug_logging, which is always on in debug mode and off by default in release mode
val forceDebugLogging = findPreference<SwitchPreferenceCompat>("pref_force_debug_logging")
forceDebugLogging!!.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? ->
// set the debug logging flag
MainApplication.forceDebugLogging = newValue as Boolean
true
}
// force enable the pref_force_debug_logging if we're in debug mode and prevent users from disabling it
if (BuildConfig.DEBUG) {
forceDebugLogging.isEnabled = false
forceDebugLogging.isChecked = true
}
}
}

@ -78,7 +78,7 @@ class InfoFragment : PreferenceFragmentCompat() {
var userRepo = BuildConfig.REMOTE_URL
// remove .git
userRepo = userRepo.replace("\\.git$".toRegex(), "")
if (BuildConfig.DEBUG) Timber.d("userRepo: %s", userRepo)
if (MainApplication.forceDebugLogging) Timber.d("userRepo: %s", userRepo)
// finalUserRepo is the user/repo part of REMOTE_URL
// get everything after .com/ or .org/ or .io/ or .me/ or .net/ or .xyz/ or .tk/ or .co/ minus .git
@ -89,7 +89,7 @@ class InfoFragment : PreferenceFragmentCompat() {
linkClickable!!.summary = String.format(
getString(R.string.source_code_summary), BuildConfig.COMMIT_HASH, finalUserRepo
)
if (BuildConfig.DEBUG) Timber.d("finalUserRepo: %s", finalUserRepo)
if (MainApplication.forceDebugLogging) Timber.d("finalUserRepo: %s", finalUserRepo)
val finalUserRepo1 = userRepo
linkClickable.onPreferenceClickListener =
Preference.OnPreferenceClickListener setOnPreferenceClickListener@{ p: Preference ->

@ -13,7 +13,6 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainActivity
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
@ -76,7 +75,7 @@ class PrivacyFragment : PreferenceFragmentCompat() {
val mgr =
requireContext().getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] = mPendingIntent
if (BuildConfig.DEBUG) Timber.d("Restarting app to save crash reporting preference: %s", newValue)
if (MainApplication.forceDebugLogging) Timber.d("Restarting app to save crash reporting preference: %s", newValue)
exitProcess(0) // Exit app process
}
// Do not reverse the change if the user cancels the dialog

@ -88,7 +88,7 @@ class RepoFragment : PreferenceFragmentCompat() {
requireContext().getSystemService(ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Restarting app to save staging endpoint preference: %s",
newValue
)
@ -130,7 +130,7 @@ class RepoFragment : PreferenceFragmentCompat() {
requireContext().getSystemService(ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Restarting app to save staging endpoint preference: %s",
newValue
)
@ -315,7 +315,7 @@ class RepoFragment : PreferenceFragmentCompat() {
requireContext().getSystemService(ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Restarting app to save token preference: %s",
newValue
)
@ -405,7 +405,7 @@ class RepoFragment : PreferenceFragmentCompat() {
) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Restarting app to save token preference: %s",
newValue
)
@ -463,13 +463,13 @@ class RepoFragment : PreferenceFragmentCompat() {
customRepos.add(id)
}
}
if (BuildConfig.DEBUG) Timber.d("%d repos: %s", custRepoEntries, customRepos)
if (MainApplication.forceDebugLogging) Timber.d("%d repos: %s", custRepoEntries, customRepos)
val customRepoManager = RepoManager.getINSTANCE()!!.customRepoManager
for (i in 0 until custRepoEntries) {
// get the id of the repo at current index in customRepos
val repoData = customRepoManager!!.getRepo(customRepos[i])
// convert repoData to a json string for logging
if (BuildConfig.DEBUG) Timber.d("RepoData for %d is %s", i, repoData.toJSON())
if (MainApplication.forceDebugLogging) Timber.d("RepoData for %d is %s", i, repoData.toJSON())
setRepoData(repoData, "pref_custom_repo_$i")
if (initial) {
val preference = findPreference<Preference>("pref_custom_repo_" + i + "_delete")
@ -591,29 +591,29 @@ class RepoFragment : PreferenceFragmentCompat() {
before: Int,
count: Int
) {
Timber.i("checking repo url validity")
if (MainApplication.forceDebugLogging) Timber.i("checking repo url validity")
// show error if string is empty, does not start with https://, or contains spaces
if (charSequence.toString().isEmpty()) {
input.error = getString(R.string.empty_field)
if (BuildConfig.DEBUG) Timber.d("No input for repo")
if (MainApplication.forceDebugLogging) Timber.d("No input for repo")
positiveButton.isEnabled = false
} else if (!charSequence.toString()
.matches("^https://.*".toRegex())
) {
input.error = getString(R.string.invalid_repo_url)
if (BuildConfig.DEBUG) Timber.d("Non https link for repo")
if (MainApplication.forceDebugLogging) Timber.d("Non https link for repo")
positiveButton.isEnabled = false
} else if (charSequence.toString().contains(" ")) {
input.error = getString(R.string.invalid_repo_url)
if (BuildConfig.DEBUG) Timber.d("Repo url has space")
if (MainApplication.forceDebugLogging) Timber.d("Repo url has space")
positiveButton.isEnabled = false
} else if (!customRepoManager.canAddRepo(charSequence.toString())) {
input.error = getString(R.string.repo_already_added)
if (BuildConfig.DEBUG) Timber.d("Could not add repo for misc reason")
if (MainApplication.forceDebugLogging) Timber.d("Could not add repo for misc reason")
positiveButton.isEnabled = false
} else {
// enable ok button
if (BuildConfig.DEBUG) Timber.d("Repo URL is ok")
if (MainApplication.forceDebugLogging) Timber.d("Repo URL is ok")
positiveButton.isEnabled = true
}
}
@ -647,7 +647,7 @@ class RepoFragment : PreferenceFragmentCompat() {
private fun setRepoData(repoData: RepoData?, preferenceName: String) {
if (repoData == null) return
if (BuildConfig.DEBUG) Timber.d("Setting preference $preferenceName to $repoData")
if (MainApplication.forceDebugLogging) Timber.d("Setting preference $preferenceName to $repoData")
val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
var preference = findPreference<Preference>(preferenceName) ?: return
if (!preferenceName.contains("androidacy") && !preferenceName.contains("magisk_alt_repo")) {
@ -658,13 +658,13 @@ class RepoFragment : PreferenceFragmentCompat() {
"ReposList.db"
).allowMainThreadQueries().build()
val reposList = db.reposListDao().getById(repoData.preferenceId!!)
if (BuildConfig.DEBUG) Timber.d("Setting preference $preferenceName because it is not the Androidacy repo or the Magisk Alt Repo")
if (MainApplication.forceDebugLogging) Timber.d("Setting preference $preferenceName because it is not the Androidacy repo or the Magisk Alt Repo")
if (repoData.isForceHide || reposList == null) {
if (BuildConfig.DEBUG) Timber.d("Hiding preference $preferenceName because it is null or force hidden")
if (MainApplication.forceDebugLogging) Timber.d("Hiding preference $preferenceName because it is null or force hidden")
hideRepoData(preferenceName)
return
} else {
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Showing preference %s because the forceHide status is %s and the RealmResults is %s",
preferenceName,
repoData.isForceHide,
@ -727,7 +727,7 @@ class RepoFragment : PreferenceFragmentCompat() {
}
}
} else {
if (BuildConfig.DEBUG) Timber.d("Hiding preference $preferenceName because it's data is null")
if (MainApplication.forceDebugLogging) Timber.d("Hiding preference $preferenceName because it's data is null")
hideRepoData(preferenceName)
return
}

@ -13,7 +13,6 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainActivity
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
@ -89,7 +88,7 @@ class SecurityFragment : PreferenceFragmentCompat() {
requireContext().getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d("Restarting app to save showcase mode preference: %s", v)
if (MainApplication.forceDebugLogging) Timber.d("Restarting app to save showcase mode preference: %s", v)
exitProcess(0) // Exit app process
}.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int ->
// Revert to showcase mode on
@ -112,7 +111,7 @@ class SecurityFragment : PreferenceFragmentCompat() {
requireContext().getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager
mgr[AlarmManager.RTC, System.currentTimeMillis() + 100] =
mPendingIntent
if (BuildConfig.DEBUG) Timber.d("Restarting app to save showcase mode preference: %s", v)
if (MainApplication.forceDebugLogging) Timber.d("Restarting app to save showcase mode preference: %s", v)
exitProcess(0) // Exit app process
}.show()
}

@ -71,7 +71,7 @@ class SettingsActivity : AppCompatActivity(), LanguageActivity,
}
@SuppressLint("RestrictedApi")
@SuppressLint("RestrictedApi", "CommitTransaction")
override fun onCreate(savedInstanceState: Bundle?) {
devModeStep = 0
super.onCreate(savedInstanceState)
@ -194,7 +194,7 @@ class SettingsActivity : AppCompatActivity(), LanguageActivity,
findPreference<Preference>("pref_pkg_info")!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener { p: Preference ->
versionClicks++
if (BuildConfig.DEBUG) Timber.d("Version clicks: %d", versionClicks)
if (MainApplication.forceDebugLogging) Timber.d("Version clicks: %d", versionClicks)
if (versionClicks == 7) {
versionClicks = 0
openUrl(p.context, "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
@ -262,7 +262,7 @@ class SettingsActivity : AppCompatActivity(), LanguageActivity,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
points += 1
}
if (BuildConfig.DEBUG) Timber.d("Device performance class: %d", points)
if (MainApplication.forceDebugLogging) Timber.d("Device performance class: %d", points)
return if (points <= 7) {
PERFORMANCE_CLASS_LOW
} else if (points <= 12) {
@ -274,6 +274,7 @@ class SettingsActivity : AppCompatActivity(), LanguageActivity,
}
@SuppressLint("CommitTransaction")
override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat, pref: Preference
): Boolean {

@ -6,20 +6,20 @@ package com.fox2code.mmm.settings
import android.content.SharedPreferences
import androidx.preference.PreferenceDataStore
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import timber.log.Timber
class SharedPreferenceDataStore(sharedPreferences: SharedPreferences) : PreferenceDataStore() {
private val mSharedPreferences: SharedPreferences
init {
if (BuildConfig.DEBUG) Timber.d("SharedPreferenceDataStore: %s", sharedPreferences)
if (MainApplication.forceDebugLogging) Timber.d("SharedPreferenceDataStore: %s", sharedPreferences)
mSharedPreferences = sharedPreferences
}
val sharedPreferences: SharedPreferences
get() {
if (BuildConfig.DEBUG) Timber.d("getSharedPreferences: %s", mSharedPreferences)
if (MainApplication.forceDebugLogging) Timber.d("getSharedPreferences: %s", mSharedPreferences)
return mSharedPreferences
}

@ -85,7 +85,7 @@ class UpdateFragment : PreferenceFragmentCompat() {
do {
fakeVersion = random.nextInt(10)
} while (fakeVersion == 0)
if (BuildConfig.DEBUG) Timber.d("Fake version: %s, count: %s", fakeVersion, i)
if (MainApplication.forceDebugLogging) Timber.d("Fake version: %s, count: %s", fakeVersion, i)
updateableModules["FakeModule $i"] = "1.0.$fakeVersion"
}
BackgroundUpdateChecker.postNotification(
@ -157,7 +157,7 @@ class UpdateFragment : PreferenceFragmentCompat() {
moduleNames[i] = localModuleInfo!!.name
// Stringset uses id, we show name
checkedItems[i] = stringSet.contains(localModuleInfo.id)
if (BuildConfig.DEBUG) Timber.d("name: %s, checked: %s", moduleNames[i], checkedItems[i])
if (MainApplication.forceDebugLogging) Timber.d("name: %s, checked: %s", moduleNames[i], checkedItems[i])
}
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.background_update_check_excludes)
.setMultiChoiceItems(
@ -204,7 +204,7 @@ class UpdateFragment : PreferenceFragmentCompat() {
val stringSet = sharedPreferences.getStringSet(
"pref_background_update_check_excludes_version", HashSet()
)
if (BuildConfig.DEBUG) Timber.d("stringSet: %s", stringSet)
if (MainApplication.forceDebugLogging) Timber.d("stringSet: %s", stringSet)
// for every module, add it's name and a text field to the dialog. the text field should accept a comma separated list of versions
val localModuleInfos: Collection<LocalModuleInfo?> =
ModuleManager.instance!!.modules.values
@ -262,7 +262,7 @@ class UpdateFragment : PreferenceFragmentCompat() {
.setView(scrollView).setPositiveButton(
R.string.ok
) { _: DialogInterface?, _: Int ->
if (BuildConfig.DEBUG) Timber.d("ok clicked")
if (MainApplication.forceDebugLogging) Timber.d("ok clicked")
// for every module, get the text field and save it to the stringset
val stringSetTemp: MutableSet<String> = HashSet()
var prevMod = ""
@ -286,9 +286,9 @@ class UpdateFragment : PreferenceFragmentCompat() {
localModuleInfo!!.name.equals(finalprevMod)
}.findFirst().orElse(null)!!.id + ":" + text
)
if (BuildConfig.DEBUG) Timber.d("text is %s for %s", text, editText.hint.toString())
if (MainApplication.forceDebugLogging) Timber.d("text is %s for %s", text, editText.hint.toString())
} else {
if (BuildConfig.DEBUG) Timber.d("text is empty for %s", editText.hint.toString())
if (MainApplication.forceDebugLogging) Timber.d("text is empty for %s", editText.hint.toString())
}
}
sharedPreferences.edit().putStringSet(

@ -17,6 +17,7 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.util.Supplier
import com.fox2code.mmm.Constants
import com.fox2code.mmm.MainApplication
import com.topjohnwu.superuser.internal.UiThreadHandler
import timber.log.Timber
@ -40,13 +41,13 @@ class ExternalHelper private constructor() {
)
}
if (resolveInfos.isEmpty()) {
Timber.i("No external provider installed!")
if (MainApplication.forceDebugLogging) Timber.i("No external provider installed!")
label = if (TEST_MODE) "External" else null
multi = TEST_MODE
fallback = null
} else {
val resolveInfo = resolveInfos[0]
Timber.i("Found external provider: %s", resolveInfo.activityInfo.packageName)
if (MainApplication.forceDebugLogging) Timber.i("Found external provider: %s", resolveInfo.activityInfo.packageName)
fallback =
ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)
label = resolveInfo.loadLabel(context.packageManager)

@ -8,8 +8,8 @@ package com.fox2code.mmm.utils
import android.annotation.SuppressLint
import android.app.Activity
import android.app.DownloadManager
import android.content.ActivityNotFoundException
import android.content.ContentResolver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
@ -18,11 +18,12 @@ import android.os.Bundle
import android.os.Environment
import android.util.TypedValue
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat.getSystemService
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.Constants
import com.fox2code.mmm.MainActivity
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
import com.fox2code.mmm.XHooks.Companion.getConfigIntent
@ -30,17 +31,11 @@ import com.fox2code.mmm.XHooks.Companion.isModuleActive
import com.fox2code.mmm.androidacy.AndroidacyActivity
import com.fox2code.mmm.installer.InstallerActivity
import com.fox2code.mmm.markdown.MarkdownActivity
import com.fox2code.mmm.utils.io.Files.Companion.closeSilently
import com.fox2code.mmm.utils.io.Files.Companion.copy
import com.fox2code.mmm.utils.io.net.Http.Companion.hasWebView
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFileInputStream
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.net.URISyntaxException
@Suppress("unused")
@ -75,7 +70,7 @@ enum class IntentHelper {;
@JvmOverloads
fun openUrl(context: Context, url: String?, forceBrowser: Boolean = false) {
if (BuildConfig.DEBUG) Timber.d("Opening url: %s, forced browser %b", url, forceBrowser)
if (MainApplication.forceDebugLogging) Timber.d("Opening url: %s, forced browser %b", url, forceBrowser)
try {
val myIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
myIntent.flags = FLAG_GRANT_URI_PERMISSION
@ -84,7 +79,7 @@ enum class IntentHelper {;
}
startActivity(context, myIntent, false)
} catch (e: ActivityNotFoundException) {
if (BuildConfig.DEBUG) Timber.d(e, "Could not find suitable activity to handle url")
if (MainApplication.forceDebugLogging) Timber.d(e, "Could not find suitable activity to handle url")
Toast.makeText(
context, MainApplication.INSTANCE!!.lastActivity!!.getString(
R.string.no_browser
@ -94,7 +89,7 @@ enum class IntentHelper {;
}
fun openCustomTab(context: Context, url: String?) {
if (BuildConfig.DEBUG) Timber.d("Opening url: %s in custom tab", url)
if (MainApplication.forceDebugLogging) Timber.d("Opening url: %s in custom tab", url)
try {
val viewIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
viewIntent.flags = FLAG_GRANT_URI_PERMISSION
@ -103,7 +98,7 @@ enum class IntentHelper {;
tabIntent.addCategory(Intent.CATEGORY_BROWSABLE)
startActivityEx(context, tabIntent, viewIntent)
} catch (e: ActivityNotFoundException) {
if (BuildConfig.DEBUG) Timber.d(e, "Could not find suitable activity to handle url")
if (MainApplication.forceDebugLogging) Timber.d(e, "Could not find suitable activity to handle url")
Toast.makeText(
context, MainApplication.INSTANCE!!.lastActivity!!.getString(
R.string.no_browser
@ -112,6 +107,56 @@ enum class IntentHelper {;
}
}
@SuppressLint("Range")
fun startDownloadUsingDownloadManager(context: Context, url: String?, title: String?) {
if (MainApplication.forceDebugLogging) Timber.d("Downloading url: %s", url)
val request = DownloadManager.Request(Uri.parse(url))
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
.setTitle((title?.replace(" ", "_") ?: "Module") + ".zip")
.setDescription(MainApplication.INSTANCE!!.lastActivity!!.getString(R.string.download_module_description, title))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setAllowedOverMetered(true)
.setAllowedOverRoaming(false)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, (title?.replace(" ", "_") ?: "Module") + ".zip")
val downloadManager= getSystemService(MainApplication.INSTANCE!!.lastActivity!!.applicationContext, DownloadManager::class.java)!!
val downloadID = downloadManager.enqueue(request)
Toast.makeText(
context, MainApplication.INSTANCE!!.lastActivity!!.getString(
R.string.download_started
), Toast.LENGTH_LONG
).show()
// listen for error
val query = DownloadManager.Query()
query.setFilterById(downloadID)
var downloading = true
while (downloading) {
try {
val cursor = downloadManager.query(query)
cursor.moveToFirst()
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_FAILED) {
downloading = false
Toast.makeText(
context, MainApplication.INSTANCE!!.lastActivity!!.getString(
R.string.download_failed
), Toast.LENGTH_LONG
).show()
} else {
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false
Toast.makeText(
context, MainApplication.INSTANCE!!.lastActivity!!.getString(
R.string.download_finished
), Toast.LENGTH_LONG
).show()
}
}
cursor.close()
} catch (e: Exception) {
Timber.e(e)
}
}
}
@JvmOverloads
fun openUrlAndroidacy(
context: Context,
@ -174,7 +219,7 @@ enum class IntentHelper {;
"am start -a android.intent.action.MAIN " + "-c org.lsposed.manager.LAUNCH_MANAGER " + "com.android.shell/.BugreportWarningActivity"
).to(object : CallbackList<String?>() {
override fun onAddElement(str: String?) {
Timber.i("LSPosed: %s", str)
if (MainApplication.forceDebugLogging) Timber.i("LSPosed: %s", str)
}
}).submit()
return
@ -355,13 +400,13 @@ enum class IntentHelper {;
return context
}
private const val RESPONSE_ERROR = 0
const val RESPONSE_ERROR = 0
const val RESPONSE_FILE = 1
const val RESPONSE_URL = 2
@SuppressLint("SdCardPath")
fun openFileTo(
compatActivity: AppCompatActivity, destination: File?, callback: OnFileReceivedCallback
destination: File?, callback: OnFileReceivedCallback
) {
var destinationFolder: File? = null
if ((destination == null) || (destination.parentFile.also {
@ -371,61 +416,9 @@ enum class IntentHelper {;
callback.onReceived(destination, null, RESPONSE_ERROR)
return
}
val getContent = compatActivity.registerForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
if (uri == null) {
Timber.d("invalid uri received")
callback.onReceived(destination, null, RESPONSE_ERROR)
return@registerForActivityResult
}
Timber.i("FilePicker returned %s", uri)
if ("http" == uri.scheme || "https" == uri.scheme) {
callback.onReceived(destination, uri, RESPONSE_URL)
return@registerForActivityResult
}
if (ContentResolver.SCHEME_FILE == uri.scheme) {
Toast.makeText(
compatActivity, R.string.file_picker_wierd, Toast.LENGTH_SHORT
).show()
}
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
var success = false
try {
if (ContentResolver.SCHEME_FILE == uri.scheme) {
var path = uri.path
if (path!!.startsWith("/sdcard/")) { // Fix file paths
path =
Environment.getExternalStorageDirectory().absolutePath + path.substring(
7
)
}
inputStream = SuFileInputStream.open(
File(path).absoluteFile
)
} else {
inputStream = compatActivity.contentResolver.openInputStream(uri)
}
outputStream = FileOutputStream(destination)
copy(inputStream!!, outputStream)
Timber.i("File saved at %s", destination)
success = true
} catch (e: Exception) {
Timber.e(e)
Toast.makeText(
compatActivity, R.string.file_picker_failure, Toast.LENGTH_SHORT
).show()
} finally {
closeSilently(inputStream)
closeSilently(outputStream)
if (!success && destination.exists() && !destination.delete()) Timber.e("Failed to delete artifact!")
}
callback.onReceived(
destination, uri, if (success) RESPONSE_FILE else RESPONSE_ERROR
)
}
getContent.launch("application/zip")
MainActivity.INSTANCE?.callback = callback
MainActivity.INSTANCE?.destination = destination
MainActivity.INSTANCE?.getContent?.launch("*/*")
}
}
}

@ -39,7 +39,7 @@ class RuntimeUtils {
@SuppressLint("RestrictedApi")
private fun ensurePermissions(context: Context, activity: MainActivity) {
if (BuildConfig.DEBUG) Timber.i("Ensure Permissions")
if (MainApplication.forceDebugLogging) Timber.i("Ensure Permissions")
// First, check if user has said don't ask again by checking if pref_dont_ask_again_notification_permission is true
if (!PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean("pref_dont_ask_again_notification_permission", false)
@ -48,14 +48,14 @@ class RuntimeUtils {
context, Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
if (BuildConfig.DEBUG) Timber.i("Request Notification Permission")
if (MainApplication.forceDebugLogging) Timber.i("Request Notification Permission")
if (MainApplication.INSTANCE!!.lastActivity!!
.shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)
) {
// Show a dialog explaining why we need context permission, which is to show
// notifications for updates
activity.runOnUiThread {
if (BuildConfig.DEBUG) Timber.i("Show Notification Permission Dialog")
if (MainApplication.forceDebugLogging) Timber.i("Show Notification Permission Dialog")
val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(R.string.permission_notification_title)
builder.setMessage(R.string.permission_notification_message)
@ -87,18 +87,18 @@ class RuntimeUtils {
MainActivity.doSetupNowRunning = false
}
builder.show()
if (BuildConfig.DEBUG) Timber.i("Show Notification Permission Dialog Done")
if (MainApplication.forceDebugLogging) Timber.i("Show Notification Permission Dialog Done")
}
} else {
// Request the permission
if (BuildConfig.DEBUG) Timber.i("Request Notification Permission")
if (MainApplication.forceDebugLogging) Timber.i("Request Notification Permission")
activity.requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
if (BuildConfig.DEBUG) {
// Log if granted via onRequestPermissionsResult
val granted = ContextCompat.checkSelfPermission(
context, Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
Timber.i("Request Notification Permission Done. Result: %s", granted)
if (MainApplication.forceDebugLogging) Timber.i("Request Notification Permission Done. Result: %s", granted)
}
MainActivity.doSetupNowRunning = false
}
@ -145,7 +145,7 @@ class RuntimeUtils {
MainActivity.doSetupNowRunning = false
}
} else {
if (BuildConfig.DEBUG) Timber.i("Notification Permission Already Granted or Don't Ask Again")
if (MainApplication.forceDebugLogging) Timber.i("Notification Permission Already Granted or Don't Ask Again")
MainActivity.doSetupNowRunning = false
}
}
@ -156,7 +156,7 @@ class RuntimeUtils {
// Method to show a setup box on first launch
@SuppressLint("InflateParams", "RestrictedApi", "UnspecifiedImmutableFlag", "ApplySharedPref")
fun checkShowInitialSetup(context: Context, activity: MainActivity) {
if (BuildConfig.DEBUG) Timber.i("Checking if we need to run setup")
if (MainApplication.forceDebugLogging) Timber.i("Checking if we need to run setup")
// Check if context is the first launch using prefs and if doSetupRestarting was passed in the intent
val prefs = MainApplication.getSharedPreferences("mmm")!!
var firstLaunch = prefs.getString("last_shown_setup", null) != "v5"
@ -167,7 +167,7 @@ class RuntimeUtils {
firstLaunch = false
}
if (BuildConfig.DEBUG) {
Timber.i(
if (MainApplication.forceDebugLogging) Timber.i(
"First launch: %s, pref value: %s",
firstLaunch,
prefs.getString("last_shown_setup", null)
@ -176,7 +176,7 @@ class RuntimeUtils {
if (firstLaunch) {
MainActivity.doSetupNowRunning = true
// Launch setup wizard
if (BuildConfig.DEBUG) Timber.i("Launching setup wizard")
if (MainApplication.forceDebugLogging) Timber.i("Launching setup wizard")
// Show setup activity
val intent = Intent(context, SetupActivity::class.java)
activity.finish()
@ -190,7 +190,7 @@ class RuntimeUtils {
* @return true if the load workflow must be stopped.
*/
fun waitInitialSetupFinished(context: Context, activity: MainActivity): Boolean {
if (BuildConfig.DEBUG) Timber.i("waitInitialSetupFinished")
if (MainApplication.forceDebugLogging) Timber.i("waitInitialSetupFinished")
try {
// Wait for doSetupNow to finish
while (MainActivity.doSetupNowRunning) {
@ -244,7 +244,7 @@ class RuntimeUtils {
*/
@SuppressLint("RestrictedApi")
fun showUpgradeSnackbar(context: Context, activity: MainActivity) {
Timber.i("showUpgradeSnackbar start")
if (MainApplication.forceDebugLogging) Timber.i("showUpgradeSnackbar start")
// if sb is already showing, wait 4 seconds and try again
if (MainActivity.isShowingWeblateSb) {
Handler(Looper.getMainLooper()).postDelayed({
@ -271,7 +271,7 @@ class RuntimeUtils {
snackbar.show()
// do not show for another 7 days
prefs.edit().putLong("ugsns4", System.currentTimeMillis()).apply()
Timber.i("showUpgradeSnackbar done")
if (MainApplication.forceDebugLogging) Timber.i("showUpgradeSnackbar done")
}
companion object {

@ -10,6 +10,7 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.R
import com.fox2code.mmm.installer.InstallerInitializer.Companion.peekMagiskPath
import com.fox2code.mmm.utils.IntentHelper.Companion.openInstaller
@ -40,7 +41,7 @@ class ZipFileOpener : AppCompatActivity() {
}
.show()
Thread(Runnable {
if (BuildConfig.DEBUG) Timber.d("onCreate: %s", intent)
if (MainApplication.forceDebugLogging) Timber.d("onCreate: %s", intent)
val zipFile: File
val uri = intent.data
if (uri == null) {
@ -108,7 +109,7 @@ class ZipFileOpener : AppCompatActivity() {
}
return@Runnable
} else {
if (BuildConfig.DEBUG) Timber.d("onCreate: Zip file is " + zipFile.length() + " bytes")
if (MainApplication.forceDebugLogging) Timber.d("onCreate: Zip file is " + zipFile.length() + " bytes")
}
var entry: ZipEntry?
var zip: ZipFile? = null
@ -120,7 +121,7 @@ class ZipFileOpener : AppCompatActivity() {
if (zip.getEntry("module.prop").also { entry = it } == null) {
Timber.e("onCreate: Zip file is not a valid magisk module")
if (BuildConfig.DEBUG) {
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"onCreate: Zip file contents: %s",
zip.stream().map { obj: ZipEntry -> obj.name }
.reduce { a: String, b: String -> "$a, $b" }.orElse("empty")
@ -147,7 +148,7 @@ class ZipFileOpener : AppCompatActivity() {
}
return@Runnable
}
if (BuildConfig.DEBUG) Timber.d("onCreate: Zip file is valid")
if (MainApplication.forceDebugLogging) Timber.d("onCreate: Zip file is valid")
var moduleInfo: String?
try {
moduleInfo = readModulePropSimple(zip.getInputStream(entry), "name")

@ -9,7 +9,6 @@ import android.net.Uri
import android.os.Build
import android.provider.OpenableColumns
import android.util.Log
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.topjohnwu.superuser.io.SuFile
import com.topjohnwu.superuser.io.SuFileInputStream
@ -222,7 +221,7 @@ enum class Files {
throw IOException("Unable to create temp unzip dir")
}
// unzip
if (BuildConfig.DEBUG) Timber.d("Unzipping module to %s", tempUnzipDir.absolutePath)
if (MainApplication.forceDebugLogging) Timber.d("Unzipping module to %s", tempUnzipDir.absolutePath)
try {
ZipFile(tempFile).use { zipFile ->
var files = zipFile.entries
@ -280,7 +279,7 @@ enum class Files {
Timber.e(e, "Unable to zip up module")
}
} else {
if (BuildConfig.DEBUG) Timber.d("Module does not have a single folder in the top level, skipping")
if (MainApplication.forceDebugLogging) Timber.d("Module does not have a single folder in the top level, skipping")
}
}
} catch (e: IOException) {

@ -5,6 +5,7 @@ package com.fox2code.mmm.utils.io
import android.content.Context
import android.content.pm.PackageManager
import com.fox2code.mmm.MainApplication
import timber.log.Timber
/**
@ -34,7 +35,7 @@ enum class GMSProviderInstaller {
val cl =
remote.classLoader.loadClass("com.google.android.gms.common.security.ProviderInstallerImpl")
cl.getDeclaredMethod("insertProvider", Context::class.java).invoke(null, remote)
Timber.i("Installed GMS security providers!")
if (MainApplication.forceDebugLogging) Timber.i("Installed GMS security providers!")
} catch (e: PackageManager.NameNotFoundException) {
Timber.w("No GMS Implementation are installed on this device")
} catch (e: Exception) {

@ -2,10 +2,9 @@
* Copyright (c) 2023 to present Androidacy and contributors. Names, logos, icons, and the Androidacy name are all trademarks of Androidacy and may not be used without license. See LICENSE for more information.
*/
@file:Suppress("UNUSED_PARAMETER")
package com.fox2code.mmm.utils.io
import com.fox2code.mmm.MainApplication
import timber.log.Timber
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
@ -66,7 +65,7 @@ enum class Hashes {;
return false
}
}
Timber.i("Checksum result (data: $hash,expected: $checksum)")
if (MainApplication.forceDebugLogging) Timber.i("Checksum result (data: $hash,expected: $checksum)")
return hash == checksum.lowercase()
}

@ -7,6 +7,7 @@ package com.fox2code.mmm.utils.io
import android.os.Build
import android.text.TextUtils
import com.fox2code.mmm.AppUpdateManager
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.manager.ModuleInfo
import com.topjohnwu.superuser.io.SuFileInputStream
import timber.log.Timber
@ -392,7 +393,7 @@ enum class PropUtils {
}
}
} catch (e: IOException) {
Timber.i(e)
if (MainApplication.forceDebugLogging) Timber.i(e)
}
return moduleId
}

@ -247,7 +247,7 @@ enum class Http {;
0, dot
).toInt()
}
if (BuildConfig.DEBUG) Timber.d(
if (MainApplication.forceDebugLogging) Timber.d(
"Webview version: %s (%d)", webviewVersion, webviewVersionCode
)
hasWebView =
@ -414,7 +414,7 @@ enum class Http {;
httpClientWithCache = followRedirects(httpclientBuilder, true).build()
httpclientBuilder.dns(fallbackDNS!!)
httpClientWithCacheDoH = followRedirects(httpclientBuilder, true).build()
Timber.i("Initialized Http successfully!")
if (MainApplication.forceDebugLogging) Timber.i("Initialized Http successfully!")
doh = MainApplication.isDohEnabled
}
@ -481,7 +481,7 @@ enum class Http {;
throw HttpException(e.message, 0)
}
if (BuildConfig.DEBUG_HTTP) {
if (BuildConfig.DEBUG) Timber.d("doHttpGet: request executed")
if (MainApplication.forceDebugLogging) Timber.d("doHttpGet: request executed")
}
// 200/204 == success, 304 == cache valid
if (response != null) {
@ -502,7 +502,7 @@ enum class Http {;
if (retryAfter != null) {
try {
val seconds = Integer.parseInt(retryAfter)
if (BuildConfig.DEBUG) Timber.d("Sleeping for $seconds seconds")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for $seconds seconds")
Thread.sleep(seconds * 1000L)
} catch (e: NumberFormatException) {
Timber.e(e, "Failed to parse Retry-After header")
@ -512,7 +512,7 @@ enum class Http {;
} else {// start with one second and try up to five times
if (limitedRetries < 5) {
limitedRetries++
if (BuildConfig.DEBUG) Timber.d("Sleeping for 1 second")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for 1 second")
try {
Thread.sleep(1000L * limitedRetries)
} catch (e: InterruptedException) {
@ -528,7 +528,7 @@ enum class Http {;
}
}
if (BuildConfig.DEBUG_HTTP) {
if (BuildConfig.DEBUG) Timber.d("doHttpGet: " + url.replace("=[^&]*".toRegex(), "=****") + " succeeded")
if (MainApplication.forceDebugLogging) Timber.d("doHttpGet: " + url.replace("=[^&]*".toRegex(), "=****") + " succeeded")
}
var responseBody = response?.body
// Use cache api if used cached response
@ -540,7 +540,7 @@ enum class Http {;
}
if (BuildConfig.DEBUG_HTTP) {
if (responseBody != null) {
if (BuildConfig.DEBUG) Timber.d("doHttpGet: returning " + responseBody.contentLength() + " bytes")
if (MainApplication.forceDebugLogging) Timber.d("doHttpGet: returning " + responseBody.contentLength() + " bytes")
}
}
if (MainApplication.analyticsAllowed() && MainApplication.isCrashReportingEnabled) {
@ -559,7 +559,7 @@ enum class Http {;
@Throws(IOException::class)
private fun doHttpPostRaw(url: String, data: String, allowCache: Boolean): Any {
if (BuildConfig.DEBUG) Timber.d("POST %s", url)
if (MainApplication.forceDebugLogging) Timber.d("POST %s", url)
val uniqid = randomUUID().toString()
if (MainApplication.analyticsAllowed() && MainApplication.isCrashReportingEnabled) {
@ -588,7 +588,7 @@ enum class Http {;
}
if (response.isRedirect) {
// follow redirect with same method
if (BuildConfig.DEBUG) Timber.d("doHttpPostRaw: following redirect: %s", response.header("Location"))
if (MainApplication.forceDebugLogging) Timber.d("doHttpPostRaw: following redirect: %s", response.header("Location"))
response =
(if (allowCache) getHttpClientWithCache() else getHttpClient())!!.newCall(
Request.Builder().url(
@ -607,7 +607,7 @@ enum class Http {;
if (retryAfter != null) {
try {
val seconds = Integer.parseInt(retryAfter)
if (BuildConfig.DEBUG) Timber.d("Sleeping for $seconds seconds")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for $seconds seconds")
Thread.sleep(seconds * 1000L)
} catch (e: NumberFormatException) {
Timber.e(e, "Failed to parse Retry-After header")
@ -617,7 +617,7 @@ enum class Http {;
} else {// start with one second and try up to five times
if (limitedRetries < 5) {
limitedRetries++
if (BuildConfig.DEBUG) Timber.d("Sleeping for 1 second")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for 1 second")
try {
Thread.sleep(1000L * limitedRetries)
} catch (e: InterruptedException) {
@ -678,7 +678,7 @@ enum class Http {;
if (retryAfter != null) {
try {
val seconds = Integer.parseInt(retryAfter)
if (BuildConfig.DEBUG) Timber.d("Sleeping for $seconds seconds")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for $seconds seconds")
Thread.sleep(seconds * 1000L)
} catch (e: NumberFormatException) {
Timber.e(e, "Failed to parse Retry-After header")
@ -688,7 +688,7 @@ enum class Http {;
} else {// start with one second and try up to five times
if (limitedRetries < 5) {
limitedRetries++
if (BuildConfig.DEBUG) Timber.d("Sleeping for 1 second")
if (MainApplication.forceDebugLogging) Timber.d("Sleeping for 1 second")
try {
Thread.sleep(1000L * limitedRetries)
} catch (e: InterruptedException) {
@ -716,7 +716,7 @@ enum class Http {;
val updateInterval: Long = 100
var nextUpdate = System.currentTimeMillis() + updateInterval
var currentUpdate: Long
Timber.i("Target: $target Divider: $divider")
if (MainApplication.forceDebugLogging) Timber.i("Target: $target Divider: $divider")
progressListener.onUpdate(0, (target / divider).toInt(), false)
while (true) {
val read = inputStream.read(buff)
@ -758,7 +758,7 @@ enum class Http {;
}
fun setDoh(doh: Boolean) {
Timber.i("DoH: " + Companion.doh + " -> " + doh)
if (MainApplication.forceDebugLogging) Timber.i("DoH: " + Companion.doh + " -> " + doh)
Companion.doh = doh
}
@ -780,19 +780,19 @@ enum class Http {;
val systemSaysYes = networkCapabilities != null && networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_INTERNET
)
if (BuildConfig.DEBUG) Timber.d("System says we have internet: $systemSaysYes")
if (MainApplication.forceDebugLogging) Timber.d("System says we have internet: $systemSaysYes")
// if we don't already have a listener, add one, so we can invalidate the cache when the network changes
if (connectivityListener == null) {
connectivityListener = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
if (BuildConfig.DEBUG) Timber.d("Network became available")
if (MainApplication.forceDebugLogging) Timber.d("Network became available")
lastConnectivityCheck = 0
}
override fun onLost(network: Network) {
super.onLost(network)
if (BuildConfig.DEBUG) Timber.d("Network became unavailable")
if (MainApplication.forceDebugLogging) Timber.d("Network became unavailable")
lastConnectivityCheck = 0
}
}
@ -809,7 +809,7 @@ enum class Http {;
Timber.e(e, "Failed to check internet connection")
false
}
if (BuildConfig.DEBUG) Timber.d("We say we have internet: $hasInternet")
if (MainApplication.forceDebugLogging) Timber.d("We say we have internet: $hasInternet")
lastConnectivityCheck = System.currentTimeMillis()
@Suppress("KotlinConstantConditions")
lastConnectivityResult =

@ -12,7 +12,7 @@
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:cardElevation="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

@ -404,4 +404,12 @@
<string name="androidacy_thanks_v2">An Androidacy app</string>
<string name="fox2code_thanks_v2">v0.x by Fox2Code</string>
<string name="fox2code_thanks_desc_v2">Versions before 0.6.8 were developed by Fox2Code and versions up to 1.1 were contributed to by him. We thank him for his work.</string>
<string name="force_debug_logging_desc">Forces debug logging in release builds. CAUTION: this may slow down the app significantly. Please do not turn on unless requested by support.</string>
<string name="force_debug_logging_pref">Force debug logging</string>
<string name="download_started">Started downloading</string>
<string name="download_module_description">Downloading Module %s</string>
<string name="download_completed">Download finished and saved to default download folder</string>
<string name="download_failed">Failed to download!</string>
<string name="download_finished">Finished downloading and saved to downloads folder</string>
<string name="file_picker_not_zip">The file you picked is not a valid zip file.</string>
</resources>

@ -30,6 +30,15 @@
app:singleLineTitle="false"
app:summary="@string/use_magisk_install_command_desc"
app:title="@string/use_magisk_install_command_pref" />
<!-- force debug logging -->
<SwitchPreferenceCompat
android:widgetLayout="@layout/preference_material_switch"
app:defaultValue="false"
app:icon="@drawable/ic_baseline_bug_report_24"
app:key="pref_force_debug_logging"
app:singleLineTitle="false"
app:summary="@string/force_debug_logging_desc"
app:title="@string/force_debug_logging_pref" />
<!-- Purposely crash the app -->
<Preference
app:icon="@drawable/ic_baseline_bug_report_24"

Loading…
Cancel
Save