From 9f7a5f583844c3f6742197f1de43a2b81a4da8a3 Mon Sep 17 00:00:00 2001 From: androidacy-user Date: Wed, 20 Sep 2023 18:45:01 -0400 Subject: [PATCH] various improvements Signed-off-by: androidacy-user --- app/src/main/AndroidManifest.xml | 2 + .../com/fox2code/mmm/AppUpdateManager.kt | 6 +- .../main/kotlin/com/fox2code/mmm/Constants.kt | 1 + .../kotlin/com/fox2code/mmm/CrashHandler.kt | 4 +- .../kotlin/com/fox2code/mmm/MainActivity.kt | 183 ++++++++++++++---- .../com/fox2code/mmm/MainApplication.kt | 91 ++++++--- .../com/fox2code/mmm/NotificationType.kt | 2 +- .../kotlin/com/fox2code/mmm/SetupActivity.kt | 40 ++-- .../mmm/androidacy/AndroidacyActivity.kt | 24 +-- .../mmm/androidacy/AndroidacyRepoData.kt | 21 +- .../mmm/androidacy/AndroidacyWebAPI.kt | 15 +- .../mmm/background/BackgroundUpdateChecker.kt | 28 +-- .../mmm/installer/InstallerActivity.kt | 21 +- .../mmm/installer/InstallerInitializer.kt | 14 +- .../com/fox2code/mmm/manager/ModuleManager.kt | 25 ++- .../fox2code/mmm/markdown/MarkdownActivity.kt | 8 +- .../mmm/markdown/MarkdownUrlLinker.kt | 6 +- .../fox2code/mmm/module/ActionButtonType.kt | 34 ++-- .../com/fox2code/mmm/module/ModuleHolder.kt | 30 +-- .../fox2code/mmm/module/ModuleViewAdapter.kt | 3 +- .../mmm/module/ModuleViewListBuilder.kt | 28 +-- .../kotlin/com/fox2code/mmm/repo/RepoData.kt | 3 +- .../com/fox2code/mmm/repo/RepoManager.kt | 17 +- .../com/fox2code/mmm/repo/RepoUpdater.kt | 17 +- .../mmm/settings/AppearanceFragment.kt | 7 +- .../fox2code/mmm/settings/DebugFragment.kt | 16 +- .../com/fox2code/mmm/settings/InfoFragment.kt | 4 +- .../fox2code/mmm/settings/PrivacyFragment.kt | 3 +- .../com/fox2code/mmm/settings/RepoFragment.kt | 34 ++-- .../fox2code/mmm/settings/SecurityFragment.kt | 5 +- .../fox2code/mmm/settings/SettingsActivity.kt | 7 +- .../mmm/settings/SharedPreferenceDataStore.kt | 6 +- .../fox2code/mmm/settings/UpdateFragment.kt | 12 +- .../com/fox2code/mmm/utils/ExternalHelper.kt | 5 +- .../com/fox2code/mmm/utils/IntentHelper.kt | 133 ++++++------- .../com/fox2code/mmm/utils/RuntimeUtils.kt | 26 +-- .../com/fox2code/mmm/utils/ZipFileOpener.kt | 9 +- .../kotlin/com/fox2code/mmm/utils/io/Files.kt | 5 +- .../mmm/utils/io/GMSProviderInstaller.kt | 3 +- .../com/fox2code/mmm/utils/io/Hashes.kt | 5 +- .../com/fox2code/mmm/utils/io/PropUtils.kt | 3 +- .../com/fox2code/mmm/utils/io/net/Http.kt | 38 ++-- app/src/main/res/layout/module_entry.xml | 2 +- app/src/main/res/values/strings.xml | 8 + .../main/res/xml/debugging_preferences.xml | 9 + 45 files changed, 583 insertions(+), 380 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d8a8e0e..edf6188 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,6 +48,8 @@ + + + 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?, 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?, 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") } } } diff --git a/app/src/main/kotlin/com/fox2code/mmm/MainApplication.kt b/app/src/main/kotlin/com/fox2code/mmm/MainApplication.kt index 094cc56..310e869 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/MainApplication.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/MainApplication.kt @@ -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 } } diff --git a/app/src/main/kotlin/com/fox2code/mmm/NotificationType.kt b/app/src/main/kotlin/com/fox2code/mmm/NotificationType.kt index f2922c0..fe4320b 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/NotificationType.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/NotificationType.kt @@ -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( diff --git a/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt index 5c1c7a0..72f95d9 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/SetupActivity.kt @@ -196,31 +196,31 @@ class SetupActivity : AppCompatActivity(), LanguageActivity { // On debug builds, log when a switch is toggled if (BuildConfig.DEBUG) { (Objects.requireNonNull(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(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(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(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( @@ -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, diff --git a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt index 11b296b..3371fcc 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt @@ -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( "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 { diff --git a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyRepoData.kt b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyRepoData.kt index 5ba2e41..6a8e214 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyRepoData.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyRepoData.kt @@ -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? { 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) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyWebAPI.kt b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyWebAPI.kt index c213207..6d065da 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyWebAPI.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyWebAPI.kt @@ -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 diff --git a/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt b/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt index 92fd25e..873d973 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt @@ -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, diff --git a/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerActivity.kt index ab8ed0e..8ae9c32 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerActivity.kt @@ -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 } diff --git a/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerInitializer.kt b/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerInitializer.kt index 574f795..6ba29dc 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerInitializer.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/installer/InstallerInitializer.kt @@ -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()) diff --git a/app/src/main/kotlin/com/fox2code/mmm/manager/ModuleManager.kt b/app/src/main/kotlin/com/fox2code/mmm/manager/ModuleManager.kt index f0bff13..c90c7f1 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/manager/ModuleManager.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/manager/ModuleManager.kt @@ -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) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownActivity.kt index 78325dd..191e868 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownActivity.kt @@ -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(R.id.markdownBackground) val textView = findViewById(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) diff --git a/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownUrlLinker.kt b/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownUrlLinker.kt index 3605b6d..40e5f81 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownUrlLinker.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/markdown/MarkdownUrlLinker.kt @@ -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() } } diff --git a/app/src/main/kotlin/com/fox2code/mmm/module/ActionButtonType.kt b/app/src/main/kotlin/com/fox2code/mmm/module/ActionButtonType.kt index 0f5cd73..2969321 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/module/ActionButtonType.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/module/ActionButtonType.kt @@ -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().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 -> diff --git a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleHolder.kt b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleHolder.kt index 0497a55..aee795e 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleHolder.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleHolder.kt @@ -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 { } 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 { 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 { 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 { 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 { // 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 } diff --git a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewAdapter.kt b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewAdapter.kt index d89d451..679408b 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewAdapter.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewAdapter.kt @@ -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) diff --git a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewListBuilder.kt b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewListBuilder.kt index aea7c77..25596af 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewListBuilder.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/module/ModuleViewListBuilder.kt @@ -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) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt index 973233f..f300c28 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoData.kt @@ -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 diff --git a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoManager.kt b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoManager.kt index d3fe7e4..ff9f7ac 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoManager.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoManager.kt @@ -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) } diff --git a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt index b17ab73..a2e08cc 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/repo/RepoUpdater.kt @@ -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() 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).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() diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/AppearanceFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/AppearanceFragment.kt index ddc1c10..300551d 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/AppearanceFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/AppearanceFragment.kt @@ -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("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("pref_enable_monet")!!.isEnabled = false // Toggle monet off (findPreference("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) diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/DebugFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/DebugFragment.kt index 65c88ac..83407e3 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/DebugFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/DebugFragment.kt @@ -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("pref_test_crash")!!.isVisible = false } else { if (findPreference("pref_test_crash") != null && findPreference( @@ -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("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 + } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/InfoFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/InfoFragment.kt index c5b81a1..2429fea 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/InfoFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/InfoFragment.kt @@ -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 -> diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/PrivacyFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/PrivacyFragment.kt index 7777d83..1e23cca 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/PrivacyFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/PrivacyFragment.kt @@ -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 diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/RepoFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/RepoFragment.kt index c8edea2..ca99ed3 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/RepoFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/RepoFragment.kt @@ -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("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(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 } diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/SecurityFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/SecurityFragment.kt index e116fdc..ed6dfbe 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/SecurityFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/SecurityFragment.kt @@ -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() } diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.kt index ecde152..7ea9257 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/SettingsActivity.kt @@ -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("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 { diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/SharedPreferenceDataStore.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/SharedPreferenceDataStore.kt index f0535d7..ec2df3a 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/SharedPreferenceDataStore.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/SharedPreferenceDataStore.kt @@ -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 } diff --git a/app/src/main/kotlin/com/fox2code/mmm/settings/UpdateFragment.kt b/app/src/main/kotlin/com/fox2code/mmm/settings/UpdateFragment.kt index 53a6d2a..a608781 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/settings/UpdateFragment.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/settings/UpdateFragment.kt @@ -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 = 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 = 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( diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/ExternalHelper.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/ExternalHelper.kt index 35a133f..95d2af8 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/ExternalHelper.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/ExternalHelper.kt @@ -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) diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/IntentHelper.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/IntentHelper.kt index b5f1b09..65a474a 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/IntentHelper.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/IntentHelper.kt @@ -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() { 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("*/*") } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/RuntimeUtils.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/RuntimeUtils.kt index 13b9196..84871fd 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/RuntimeUtils.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/RuntimeUtils.kt @@ -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 { diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/ZipFileOpener.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/ZipFileOpener.kt index 780f129..ec118fd 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/ZipFileOpener.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/ZipFileOpener.kt @@ -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") diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/Files.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/Files.kt index 1b7bc4c..9642f6e 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/Files.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/Files.kt @@ -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) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt index bc24019..e6400c2 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt @@ -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) { diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/Hashes.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/Hashes.kt index e926453..5fe1429 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/Hashes.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/Hashes.kt @@ -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() } diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/PropUtils.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/PropUtils.kt index e4796f2..66bd816 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/PropUtils.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/PropUtils.kt @@ -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 } diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt index f176e51..20aa046 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt @@ -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 = diff --git a/app/src/main/res/layout/module_entry.xml b/app/src/main/res/layout/module_entry.xml index 8a897ab..9091669 100644 --- a/app/src/main/res/layout/module_entry.xml +++ b/app/src/main/res/layout/module_entry.xml @@ -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"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 84fb056..bcd6e5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -404,4 +404,12 @@ An Androidacy app v0.x by Fox2Code 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. + Forces debug logging in release builds. CAUTION: this may slow down the app significantly. Please do not turn on unless requested by support. + Force debug logging + Started downloading + Downloading Module %s + Download finished and saved to default download folder + Failed to download! + Finished downloading and saved to downloads folder + The file you picked is not a valid zip file. diff --git a/app/src/main/res/xml/debugging_preferences.xml b/app/src/main/res/xml/debugging_preferences.xml index 019664b..4ff4004 100644 --- a/app/src/main/res/xml/debugging_preferences.xml +++ b/app/src/main/res/xml/debugging_preferences.xml @@ -30,6 +30,15 @@ app:singleLineTitle="false" app:summary="@string/use_magisk_install_command_desc" app:title="@string/use_magisk_install_command_pref" /> + +