diff --git a/.github/workflows/build_beta_apk.yml b/.github/workflows/build_beta_apk.yml
index 5718a9913..a5c325c0a 100644
--- a/.github/workflows/build_beta_apk.yml
+++ b/.github/workflows/build_beta_apk.yml
@@ -67,7 +67,7 @@ jobs:
cache: 'gradle'
- name: Cache Gradle dependencies
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
diff --git a/app/src/main/assets/html/changelogs.html b/app/src/main/assets/html/changelogs.html
index 964a8cf44..c8a5279f7 100644
--- a/app/src/main/assets/html/changelogs.html
+++ b/app/src/main/assets/html/changelogs.html
@@ -25,6 +25,7 @@
Bug Fixes
Fixed rate screen opening between transactions causing the app to crash on play builds.
Fixed changelogs popup not appearing on after an update.
Fixed invalid tracker states in tracker blocker framework.
+ Fixed an OOM on Dex Classes Code Viewer.
Fixed some random crashes.
diff --git a/app/src/main/java/app/simple/inure/util/TrackerUtils.kt b/app/src/main/java/app/simple/inure/util/TrackerUtils.kt
index 0070e0cfb..ec5eca335 100644
--- a/app/src/main/java/app/simple/inure/util/TrackerUtils.kt
+++ b/app/src/main/java/app/simple/inure/util/TrackerUtils.kt
@@ -1,13 +1,33 @@
package app.simple.inure.util
import android.content.Context
+import android.content.pm.PackageInfo
import app.simple.inure.R
+import app.simple.inure.apk.utils.ReceiversUtils
+import app.simple.inure.apk.utils.ServicesUtils
import app.simple.inure.models.Tracker
import app.simple.inure.util.ArrayUtils.toStringArray
import app.simple.inure.util.ConditionUtils.invert
+import com.topjohnwu.superuser.nio.ExtendedFile
+import com.topjohnwu.superuser.nio.FileSystemManager
import org.json.JSONObject
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.w3c.dom.Node
+import org.w3c.dom.NodeList
+import org.xml.sax.InputSource
import java.io.BufferedReader
+import java.io.FileNotFoundException
import java.io.InputStreamReader
+import java.io.StringReader
+import java.nio.ByteBuffer
+import java.nio.charset.Charset
+import javax.xml.parsers.DocumentBuilder
+import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.transform.Transformer
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.dom.DOMSource
+import javax.xml.transform.stream.StreamResult
object TrackerUtils {
@@ -91,4 +111,425 @@ object TrackerUtils {
} as ArrayList
}
}
-}
\ No newline at end of file
+
+ fun PackageInfo.getActivityTrackers(context: Context, trackersData: ArrayList, keyword: String = ""): ArrayList {
+ val activities = activities ?: null
+ val trackersList = arrayListOf()
+
+ if (activities != null) {
+ for (activity in activities) {
+ for (tracker in trackersData) {
+ tracker.codeSignature.split("|").forEach {
+ if (activity.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
+ if (activity.name.lowercase().contains(it.lowercase())) {
+ val tracker1 = Tracker()
+ tracker.copyBasicTrackerInfo(tracker1)
+
+ tracker1.activityInfo = activity
+ tracker1.componentName = activity.name
+ tracker1.isEnabled = kotlin.runCatching {
+ ActivityUtils.isEnabled(context, packageName, activity.name)
+ }.getOrElse {
+ false
+ }
+ tracker1.isReceiver = false
+ tracker1.isService = false
+ tracker1.isActivity = true
+
+ trackersList.add(tracker1)
+
+ return@forEach
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return trackersList
+ }
+
+ fun PackageInfo.getServiceTrackers(context: Context, trackersData: ArrayList, keyword: String = ""): ArrayList {
+ val services = services ?: null
+ val trackersList = arrayListOf()
+
+ if (services != null) {
+ for (service in services) {
+ for (tracker in trackersData) {
+ tracker.codeSignature.split("|").forEach {
+ if (service.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
+ if (service.name.lowercase().contains(it.lowercase())) {
+ val tracker1 = Tracker()
+ tracker.copyBasicTrackerInfo(tracker1)
+
+ tracker1.serviceInfo = service
+ tracker1.componentName = service.name
+ tracker1.isEnabled = kotlin.runCatching {
+ ServicesUtils.isEnabled(context, packageName, service.name)
+ }.getOrElse {
+ false
+ }
+ tracker1.isReceiver = false
+ tracker1.isService = true
+ tracker1.isActivity = false
+
+ trackersList.add(tracker1)
+
+ return@forEach
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return trackersList
+ }
+
+ fun PackageInfo.getReceiverTrackers(context: Context, trackersData: ArrayList, keyword: String = ""): ArrayList {
+ val receivers = receivers ?: null
+ val trackersList = arrayListOf()
+
+ if (receivers != null) {
+ for (receiver in receivers) {
+ for (tracker in trackersData) {
+ tracker.codeSignature.split("|").forEach {
+ if (receiver.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
+ if (receiver.name.lowercase().contains(it.lowercase())) {
+ val tracker1 = Tracker()
+ tracker.copyBasicTrackerInfo(tracker1)
+
+ tracker1.receiverInfo = receiver
+ tracker1.componentName = receiver.name
+ tracker1.isEnabled = kotlin.runCatching {
+ ReceiversUtils.isEnabled(context, packageName, receiver.name)
+ }.getOrElse {
+ false
+ }
+ tracker1.isReceiver = true
+ tracker1.isService = false
+ tracker1.isActivity = false
+
+ trackersList.add(tracker1)
+
+ return@forEach
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return trackersList
+ }
+
+ fun readIntentFirewallXml(fileSystemManager: FileSystemManager, trackersList: ArrayList, path: String) {
+ with(fileSystemManager.getFile(path)) {
+ if (this.exists().invert()) {
+ this.newOutputStream().use {
+ it.write("\n".toByteArray())
+ }
+ }
+ }
+
+ val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
+ val capacity = channel.size().toInt()
+ val buffer = ByteBuffer.allocate(capacity)
+ channel.read(buffer)
+ buffer.flip()
+
+ val xml = String(buffer.array(), Charset.defaultCharset())
+ val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xml)))
+
+ val activityNodes = document.getElementsByTagName("activity")
+ val serviceNodes = document.getElementsByTagName("service")
+ val broadcastNodes = document.getElementsByTagName("broadcast")
+
+ for (i in 0 until activityNodes.length) {
+ val activityNode: Node = activityNodes.item(i)
+ if (activityNode.nodeType == Node.ELEMENT_NODE) {
+ val activityElement = activityNode as Element
+ val isBlocked = activityElement.getAttribute("block").toBoolean()
+ val componentFilters: NodeList = activityElement.getElementsByTagName("component-filter")
+ for (j in 0 until componentFilters.length) {
+ val componentFilterNode: Node = componentFilters.item(j)
+ if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
+ val componentFilterElement = componentFilterNode as Element
+ val componentName = componentFilterElement.getAttribute("name")
+
+ trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
+ it.isBlocked = isBlocked
+ }
+ }
+ }
+ }
+ }
+
+ for (i in 0 until serviceNodes.length) {
+ val serviceNode: Node = serviceNodes.item(i)
+ if (serviceNode.nodeType == Node.ELEMENT_NODE) {
+ val serviceElement = serviceNode as Element
+ val isBlocked = serviceElement.getAttribute("block").toBoolean()
+ val componentFilters: NodeList = serviceElement.getElementsByTagName("component-filter")
+ for (j in 0 until componentFilters.length) {
+ val componentFilterNode: Node = componentFilters.item(j)
+ if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
+ val componentFilterElement = componentFilterNode as Element
+ val componentName = componentFilterElement.getAttribute("name")
+
+ trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
+ it.isBlocked = isBlocked
+ }
+ }
+ }
+ }
+ }
+
+ for (i in 0 until broadcastNodes.length) {
+ val broadcastNode: Node = broadcastNodes.item(i)
+ if (broadcastNode.nodeType == Node.ELEMENT_NODE) {
+ val broadcastElement = broadcastNode as Element
+ val isBlocked = broadcastElement.getAttribute("block").toBoolean()
+ val componentFilters: NodeList = broadcastElement.getElementsByTagName("component-filter")
+ for (j in 0 until componentFilters.length) {
+ val componentFilterNode: Node = componentFilters.item(j)
+ if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
+ val componentFilterElement = componentFilterNode as Element
+ val componentName = componentFilterElement.getAttribute("name")
+
+ trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
+ it.isBlocked = isBlocked
+ }
+ }
+ }
+ }
+ }
+
+ channel.close()
+ }
+
+ /**
+ *
+ *
+ *
+ * ...
+ *
+ *
+ *
+ * ...
+ *
+ *
+ *
+ * ...
+ *
+ *
+ *
+ * Parse the file following the above structure and append the components
+ * into subsequent tags (activity, service, broadcast), if the tags don't
+ * exist, create them.
+ *
+ * @param trackers The list of trackers to be added to the file
+ */
+ fun PackageInfo.blockTrackers(trackers: ArrayList, fileSystemManager: FileSystemManager, path: String) {
+ val file: ExtendedFile = fileSystemManager.getFile(path)
+
+ if (!file.exists()) {
+ file.newOutputStream().use {
+ it.write("\n".toByteArray())
+ }
+ }
+
+ val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
+ val capacity = channel.size().toInt()
+ val buffer = ByteBuffer.allocate(capacity)
+ channel.read(buffer)
+ buffer.flip()
+
+ val xml = String(buffer.array(), Charset.defaultCharset())
+ val docFactory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
+ val docBuilder: DocumentBuilder = docFactory.newDocumentBuilder()
+ val doc: Document = docBuilder.parse(InputSource(StringReader(xml)))
+
+ // Modify the XML document
+ val rules = doc.getElementsByTagName("rules").item(0)
+
+ for (tracker in trackers) {
+ val components = doc.getElementsByTagName("component-filter")
+
+ /**
+ * Remove the component if it already exists
+ * This is to prevent duplicate entries
+ */
+ for (i in 0 until components.length) {
+ val component = components.item(i)
+ val name = component.attributes.getNamedItem("name").nodeValue
+
+ if (name == "${packageName}/${tracker.componentName}") {
+ component.parentNode.removeChild(component)
+ }
+ }
+
+ val componentFilter = doc.createElement("component-filter")
+ componentFilter.setAttribute("name", "${packageName}/${tracker.componentName}")
+
+ if (tracker.isActivity) {
+ // Check if the activity tag exists
+ val activity = doc.getElementsByTagName("activity").item(0)
+
+ if (activity == null) {
+ val activity1 = doc.createElement("activity")
+ activity1.setAttribute("block", "true")
+ activity1.setAttribute("log", "false")
+ activity1.appendChild(componentFilter)
+
+ rules.appendChild(activity1)
+ } else {
+ /**
+ * Check if block already exists and is true, if false
+ * create another activity tag with block and log attributes
+ * set to true
+ */
+ if (activity.attributes.getNamedItem("block") != null
+ && activity.attributes.getNamedItem("block").nodeValue == "false") {
+ val activity1 = doc.createElement("activity")
+ activity1.setAttribute("block", "true")
+ activity1.setAttribute("log", "false")
+ activity1.appendChild(componentFilter)
+
+ rules.appendChild(activity1)
+ } else {
+ activity.appendChild(componentFilter)
+ }
+ }
+ }
+
+ if (tracker.isService) {
+ // Check if the service tag exists
+ val service = doc.getElementsByTagName("service").item(0)
+
+ if (service == null) {
+ val service1 = doc.createElement("service")
+ service1.setAttribute("block", "true")
+ service1.setAttribute("log", "false")
+ service1.appendChild(componentFilter)
+
+ rules.appendChild(service1)
+ } else {
+ /**
+ * Check if block already exists and is true, if false
+ * create another service tag with block and log attributes
+ * set to true
+ */
+ if (service.attributes.getNamedItem("block") != null
+ && service.attributes.getNamedItem("block").nodeValue == "false") {
+ val service1 = doc.createElement("service")
+ service1.setAttribute("block", "true")
+ service1.setAttribute("log", "false")
+ service1.appendChild(componentFilter)
+
+ rules.appendChild(service1)
+ } else {
+ service.appendChild(componentFilter)
+ }
+ }
+ }
+
+ if (tracker.isReceiver) {
+ // Check if the broadcast tag exists
+ val broadcast = doc.getElementsByTagName("broadcast").item(0)
+
+ if (broadcast == null) {
+ val broadcast1 = doc.createElement("broadcast")
+ broadcast1.setAttribute("block", "true")
+ broadcast1.setAttribute("log", "false")
+ broadcast1.appendChild(componentFilter)
+
+ rules.appendChild(broadcast1)
+ } else {
+ /**
+ * Check if block already exists and is true, if false
+ * create another broadcast tag with block and log attributes
+ * set to true
+ */
+ if (broadcast.attributes.getNamedItem("block") != null
+ && broadcast.attributes.getNamedItem("block").nodeValue == "false") {
+ val broadcast1 = doc.createElement("broadcast")
+ broadcast1.setAttribute("block", "true")
+ broadcast1.setAttribute("log", "false")
+ broadcast1.appendChild(componentFilter)
+
+ rules.appendChild(broadcast1)
+ } else {
+ broadcast.appendChild(componentFilter)
+ }
+ }
+ }
+ }
+
+ // Write the XML document back to the file
+ val transformerFactory: TransformerFactory = TransformerFactory.newInstance()
+ val transformer: Transformer = transformerFactory.newTransformer()
+ val source = DOMSource(doc)
+
+ channel.truncate(0)
+
+ val outputStream = file.newOutputStream()
+ val result = StreamResult(outputStream)
+ transformer.transform(source, result)
+
+ channel.close()
+ }
+
+ fun PackageInfo.unblockTrackers(trackers: ArrayList, fileSystemManager: FileSystemManager, path: String) {
+ val file: ExtendedFile = fileSystemManager.getFile(path)
+
+ if (!file.exists()) {
+ throw FileNotFoundException()
+ }
+
+ val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
+ val capacity = channel.size().toInt()
+ val buffer = ByteBuffer.allocate(capacity)
+ channel.read(buffer)
+ buffer.flip()
+
+ val xml = String(buffer.array(), Charset.defaultCharset())
+
+ val docFactory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
+ val docBuilder: DocumentBuilder = docFactory.newDocumentBuilder()
+ val doc: Document = docBuilder.parse(InputSource(StringReader(xml)))
+
+ // Modify the XML document
+ // val rules = doc.getElementsByTagName("rules").item(0)
+
+ for (tracker in trackers) {
+ val components = doc.getElementsByTagName("component-filter")
+
+ /**
+ * Remove the component if it already exists
+ * This is to prevent duplicate entries
+ */
+ for (i in 0 until components.length) {
+ val component = components.item(i)
+ val name = component.attributes.getNamedItem("name").nodeValue
+
+ if (name == "${packageName}/${tracker.componentName}") {
+ component.parentNode.removeChild(component)
+ }
+ }
+ }
+
+ // Write the XML document back to the file
+ val transformerFactory: TransformerFactory = TransformerFactory.newInstance()
+ val transformer: Transformer = transformerFactory.newTransformer()
+ val source = DOMSource(doc)
+
+ channel.truncate(0)
+
+ val outputStream = file.newOutputStream()
+ val result = StreamResult(outputStream)
+ transformer.transform(source, result)
+
+ channel.close()
+ }
+}
diff --git a/app/src/main/java/app/simple/inure/viewmodels/batch/BatchTrackersViewModel.kt b/app/src/main/java/app/simple/inure/viewmodels/batch/BatchTrackersViewModel.kt
index c543ec010..3b1fbcf81 100644
--- a/app/src/main/java/app/simple/inure/viewmodels/batch/BatchTrackersViewModel.kt
+++ b/app/src/main/java/app/simple/inure/viewmodels/batch/BatchTrackersViewModel.kt
@@ -10,24 +10,20 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import app.simple.inure.R
import app.simple.inure.apk.utils.PackageUtils.isPackageInstalled
-import app.simple.inure.apk.utils.ReceiversUtils
-import app.simple.inure.apk.utils.ServicesUtils
import app.simple.inure.extensions.viewmodels.RootServiceViewModel
import app.simple.inure.models.Tracker
-import app.simple.inure.util.ActivityUtils
-import app.simple.inure.util.ConditionUtils.invert
import app.simple.inure.util.ConditionUtils.isNotNull
import app.simple.inure.util.ConditionUtils.isZero
import app.simple.inure.util.TrackerUtils
+import app.simple.inure.util.TrackerUtils.getActivityTrackers
+import app.simple.inure.util.TrackerUtils.getReceiverTrackers
+import app.simple.inure.util.TrackerUtils.getServiceTrackers
import com.topjohnwu.superuser.nio.ExtendedFile
import com.topjohnwu.superuser.nio.FileSystemManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-import org.w3c.dom.NodeList
import org.xml.sax.InputSource
import java.io.StringReader
import java.nio.ByteBuffer
@@ -83,13 +79,13 @@ class BatchTrackersViewModel(application: Application, private val packages: Arr
progress.postValue("${index + 1}/${packages.size}\n$packageName")
val packageInfo = packageName.getPackageInfo() ?: return@forEachIndexed
- trackersList.addAll(packageInfo.getActivityTrackers(trackersData))
- trackersList.addAll(packageInfo.getServicesTrackers(trackersData))
- trackersList.addAll(packageInfo.getReceiversTrackers(trackersData))
+ trackersList.addAll(packageInfo.getActivityTrackers(applicationContext(), trackersData))
+ trackersList.addAll(packageInfo.getServiceTrackers(applicationContext(), trackersData))
+ trackersList.addAll(packageInfo.getReceiverTrackers(applicationContext(), trackersData))
try {
- readIntentFirewallXml(
- path.replace(placeHolder, packageInfo.packageName), getFileSystemManager(), trackersList)
+ TrackerUtils.readIntentFirewallXml(
+ getFileSystemManager()!!, trackersList, path.replace(placeHolder, packageInfo.packageName))
} catch (e: NullPointerException) {
Log.e("BatchTrackersViewModel", "Error: ${e.message}")
}
@@ -103,111 +99,6 @@ class BatchTrackersViewModel(application: Application, private val packages: Arr
}
}
- private fun PackageInfo.getActivityTrackers(trackersData: ArrayList): ArrayList {
- val activities = activities ?: null
- val trackersList = arrayListOf()
-
- if (activities != null) {
- for (activity in activities) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (activity.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.activityInfo = activity
- tracker1.componentName = activity.name
- tracker1.isEnabled = kotlin.runCatching {
- ActivityUtils.isEnabled(applicationContext(), packageName, activity.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = false
- tracker1.isService = false
- tracker1.isActivity = true
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun PackageInfo.getServicesTrackers(trackersData: ArrayList): ArrayList {
- val services = services ?: null
- val trackersList = arrayListOf()
-
- if (services != null) {
- for (service in services) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (service.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.serviceInfo = service
- tracker1.componentName = service.name
- tracker1.isEnabled = kotlin.runCatching {
- ServicesUtils.isEnabled(applicationContext(), packageName, service.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = false
- tracker1.isService = true
- tracker1.isActivity = false
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun PackageInfo.getReceiversTrackers(trackersData: ArrayList): ArrayList {
- val receivers = receivers ?: null
- val trackersList = arrayListOf()
-
- if (receivers != null) {
- for (receiver in receivers) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (receiver.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.receiverInfo = receiver
- tracker1.componentName = receiver.name
- tracker1.isEnabled = kotlin.runCatching {
- ReceiversUtils.isEnabled(applicationContext(), packageName, receiver.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = true
- tracker1.isService = false
- tracker1.isActivity = false
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
private fun String.getPackageInfo(): PackageInfo? {
if (packageManager.isPackageInstalled(this)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -235,99 +126,6 @@ class BatchTrackersViewModel(application: Application, private val packages: Arr
return null
}
- /**
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * Parse the file following the above structure
- */
- private fun readIntentFirewallXml(path: String, fileSystemManager: FileSystemManager?, trackersList: ArrayList) {
- if (fileSystemManager?.getFile(path)?.exists()?.invert()!!) {
- return
- }
-
- val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
- val capacity = channel.size().toInt()
- val buffer = ByteBuffer.allocate(capacity)
- channel.read(buffer)
- buffer.flip()
-
- val xml = String(buffer.array(), StandardCharsets.UTF_8)
- val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xml)))
-
- val activityNodes = document.getElementsByTagName("activity")
- val serviceNodes = document.getElementsByTagName("service")
- val broadcastNodes = document.getElementsByTagName("broadcast")
-
- for (i in 0 until activityNodes.length) {
- val activityNode: Node = activityNodes.item(i)
- if (activityNode.nodeType == Node.ELEMENT_NODE) {
- val activityElement = activityNode as Element
- val isBlocked = activityElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = activityElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until serviceNodes.length) {
- val serviceNode: Node = serviceNodes.item(i)
- if (serviceNode.nodeType == Node.ELEMENT_NODE) {
- val serviceElement = serviceNode as Element
- val isBlocked = serviceElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = serviceElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until broadcastNodes.length) {
- val broadcastNode: Node = broadcastNodes.item(i)
- if (broadcastNode.nodeType == Node.ELEMENT_NODE) {
- val broadcastElement = broadcastNode as Element
- val isBlocked = broadcastElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = broadcastElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- channel.close()
- }
-
fun changeTrackerState(trackers: ArrayList, shouldBlock: Boolean, function: () -> Unit) {
viewModelScope.launch(Dispatchers.IO) {
for (packageName in packages) {
diff --git a/app/src/main/java/app/simple/inure/viewmodels/installer/InstallerTrackersViewModel.kt b/app/src/main/java/app/simple/inure/viewmodels/installer/InstallerTrackersViewModel.kt
index 2c9506528..66d690f20 100644
--- a/app/src/main/java/app/simple/inure/viewmodels/installer/InstallerTrackersViewModel.kt
+++ b/app/src/main/java/app/simple/inure/viewmodels/installer/InstallerTrackersViewModel.kt
@@ -14,17 +14,16 @@ import app.simple.inure.apk.utils.PackageUtils.isPackageInstalled
import app.simple.inure.extensions.viewmodels.RootServiceViewModel
import app.simple.inure.models.Tracker
import app.simple.inure.preferences.ConfigurationPreferences
-import app.simple.inure.util.ActivityUtils
-import app.simple.inure.util.ConditionUtils.invert
import app.simple.inure.util.ConditionUtils.isZero
+import app.simple.inure.util.TrackerUtils
+import app.simple.inure.util.TrackerUtils.getActivityTrackers
+import app.simple.inure.util.TrackerUtils.getReceiverTrackers
+import app.simple.inure.util.TrackerUtils.getServiceTrackers
import com.topjohnwu.superuser.nio.ExtendedFile
import com.topjohnwu.superuser.nio.FileSystemManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-import org.w3c.dom.NodeList
import org.xml.sax.InputSource
import java.io.File
import java.io.StringReader
@@ -85,16 +84,17 @@ class InstallerTrackersViewModel(application: Application, private val apkFile:
}
if (packageManager.isPackageInstalled(packageInfo?.packageName!!)) {
- packageInfo = packageManager.getPackageInfo(packageInfo?.packageName!!)
+ packageInfo = packageManager.getPackageInfo(packageInfo?.packageName!!)!!
}
path = "/data/system/ifw/" + "${packageInfo?.packageName}.xml"
+ val trackersData = TrackerUtils.getTrackersData()
val trackersList = arrayListOf()
- trackersList.addAll(getActivityTrackers())
- trackersList.addAll(getServicesTrackers())
- trackersList.addAll(getReceiversTrackers())
+ trackersList.addAll(packageInfo?.getActivityTrackers(applicationContext(), trackersData)!!)
+ trackersList.addAll(packageInfo?.getServiceTrackers(applicationContext(), trackersData)!!)
+ trackersList.addAll(packageInfo?.getReceiverTrackers(applicationContext(), trackersData)!!)
trackersList.sortBy {
it.componentName
@@ -105,7 +105,7 @@ class InstallerTrackersViewModel(application: Application, private val apkFile:
}
if (ConfigurationPreferences.isUsingRoot()) {
- readIntentFirewallXml(getFileSystemManager()!!, trackersList)
+ TrackerUtils.readIntentFirewallXml(getFileSystemManager()!!, trackersList, path)
}
trackers.postValue(trackersList)
@@ -115,112 +115,6 @@ class InstallerTrackersViewModel(application: Application, private val apkFile:
}
}
- private fun getActivityTrackers(): ArrayList {
- val trackerSignatures = getTrackerSignatures()
- val activities = packageInfo?.activities
- val trackersList = arrayListOf()
-
- if (activities != null) {
- for (activity in activities) {
- for (signature in trackerSignatures) {
- if (activity.name.contains(signature)) {
- val tracker = Tracker()
-
- tracker.activityInfo = activity
- tracker.name = activity.name
-
- kotlin.runCatching {
- tracker.isEnabled = ActivityUtils.isEnabled(applicationContext(), packageInfo?.packageName!!, activity.name)
- }
-
- tracker.codeSignature = signature
- tracker.isReceiver = false
- tracker.isService = false
- tracker.isActivity = true
-
- trackersList.add(tracker)
-
- break
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun getServicesTrackers(): ArrayList {
- val trackerSignatures = getTrackerSignatures()
- val services = packageInfo?.services
- val trackersList = arrayListOf()
-
- if (services != null) {
- for (service in services) {
- for (signature in trackerSignatures) {
- if (service.name.contains(signature)) {
- val tracker = Tracker()
-
- tracker.serviceInfo = service
- tracker.name = service.name
-
- kotlin.runCatching {
- tracker.isEnabled = ActivityUtils.isEnabled(applicationContext(), packageInfo?.packageName!!, service.name)
- }
-
- tracker.codeSignature = signature
- tracker.isReceiver = false
- tracker.isService = true
- tracker.isActivity = false
-
- trackersList.add(tracker)
-
- break
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun getReceiversTrackers(): ArrayList {
- val trackerSignatures = getTrackerSignatures()
- val receivers = packageInfo?.receivers
- val trackersList = arrayListOf()
-
- if (receivers != null) {
- for (receiver in receivers) {
- for (signature in trackerSignatures) {
- if (receiver.name.contains(signature)) {
- val tracker = Tracker()
-
- tracker.activityInfo = receiver
- tracker.name = receiver.name
-
- kotlin.runCatching {
- tracker.isEnabled = ActivityUtils.isEnabled(applicationContext(), packageInfo?.packageName!!, receiver.name)
- }
-
- tracker.codeSignature = signature
- tracker.isReceiver = true
- tracker.isService = false
- tracker.isActivity = false
-
- trackersList.add(tracker)
-
- break
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun getTrackerSignatures(): List {
- return applicationContext().resources.getStringArray(R.array.trackers).filter { it.isNullOrEmpty().invert() }
- }
-
override fun runRootProcess(fileSystemManager: FileSystemManager?) {
scanTrackers()
}
@@ -229,103 +123,6 @@ class InstallerTrackersViewModel(application: Application, private val apkFile:
tracker.value = null
}
- /**
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * Parse the file following the above structure
- */
- private fun readIntentFirewallXml(fileSystemManager: FileSystemManager, trackersList: ArrayList) {
- with(fileSystemManager.getFile(path)) {
- if (this.exists().invert()) {
- this.newOutputStream().use {
- it.write("\n".toByteArray())
- }
- }
- }
-
- val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
- val capacity = channel.size().toInt()
- val buffer = ByteBuffer.allocate(capacity)
- channel.read(buffer)
- buffer.flip()
-
- val xml = String(buffer.array(), Charset.defaultCharset())
- val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xml)))
-
- val activityNodes = document.getElementsByTagName("activity")
- val serviceNodes = document.getElementsByTagName("service")
- val broadcastNodes = document.getElementsByTagName("broadcast")
-
- for (i in 0 until activityNodes.length) {
- val activityNode: Node = activityNodes.item(i)
- if (activityNode.nodeType == Node.ELEMENT_NODE) {
- val activityElement = activityNode as Element
- val isBlocked = activityElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = activityElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until serviceNodes.length) {
- val serviceNode: Node = serviceNodes.item(i)
- if (serviceNode.nodeType == Node.ELEMENT_NODE) {
- val serviceElement = serviceNode as Element
- val isBlocked = serviceElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = serviceElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until broadcastNodes.length) {
- val broadcastNode: Node = broadcastNodes.item(i)
- if (broadcastNode.nodeType == Node.ELEMENT_NODE) {
- val broadcastElement = broadcastNode as Element
- val isBlocked = broadcastElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = broadcastElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- channel.close()
- }
-
/**
*
*
diff --git a/app/src/main/java/app/simple/inure/viewmodels/viewers/TrackersViewModel.kt b/app/src/main/java/app/simple/inure/viewmodels/viewers/TrackersViewModel.kt
index 9afff11ba..5e54d5832 100644
--- a/app/src/main/java/app/simple/inure/viewmodels/viewers/TrackersViewModel.kt
+++ b/app/src/main/java/app/simple/inure/viewmodels/viewers/TrackersViewModel.kt
@@ -10,24 +10,20 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import app.simple.inure.R
import app.simple.inure.apk.utils.PackageUtils.isPackageInstalled
-import app.simple.inure.apk.utils.ReceiversUtils
-import app.simple.inure.apk.utils.ServicesUtils
import app.simple.inure.extensions.viewmodels.RootServiceViewModel
import app.simple.inure.models.Tracker
import app.simple.inure.preferences.ConfigurationPreferences
-import app.simple.inure.util.ActivityUtils
-import app.simple.inure.util.ConditionUtils.invert
import app.simple.inure.util.ConditionUtils.isNotNull
import app.simple.inure.util.ConditionUtils.isZero
import app.simple.inure.util.TrackerUtils
+import app.simple.inure.util.TrackerUtils.getActivityTrackers
+import app.simple.inure.util.TrackerUtils.getReceiverTrackers
+import app.simple.inure.util.TrackerUtils.getServiceTrackers
import com.topjohnwu.superuser.nio.ExtendedFile
import com.topjohnwu.superuser.nio.FileSystemManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-import org.w3c.dom.NodeList
import org.xml.sax.InputSource
import java.io.StringReader
import java.nio.ByteBuffer
@@ -78,9 +74,9 @@ class TrackersViewModel(application: Application, private val packageInfo: Packa
val trackersData = TrackerUtils.getTrackersData()
val trackersList = arrayListOf()
- trackersList.addAll(packageInfo.getActivityTrackers(trackersData))
- trackersList.addAll(packageInfo.getServicesTrackers(trackersData))
- trackersList.addAll(packageInfo.getReceiversTrackers(trackersData))
+ trackersList.addAll(packageInfo.getActivityTrackers(applicationContext(), trackersData, keyword))
+ trackersList.addAll(packageInfo.getServiceTrackers(applicationContext(), trackersData, keyword))
+ trackersList.addAll(packageInfo.getReceiverTrackers(applicationContext(), trackersData, keyword))
trackersList.sortBy {
it.componentName
@@ -91,7 +87,7 @@ class TrackersViewModel(application: Application, private val packageInfo: Packa
}
if (ConfigurationPreferences.isUsingRoot()) {
- readIntentFirewallXml(getFileSystemManager(), trackersList)
+ TrackerUtils.readIntentFirewallXml(getFileSystemManager()!!, trackersList, path)
}
Log.d("TrackersViewModel", "Trackers: ${trackersList.size}")
@@ -141,117 +137,6 @@ class TrackersViewModel(application: Application, private val packageInfo: Packa
}
}
- private fun PackageInfo.getActivityTrackers(trackersData: ArrayList): ArrayList {
- val activities = activities ?: null
- val trackersList = arrayListOf()
-
- if (activities != null) {
- for (activity in activities) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (activity.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
- if (activity.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.activityInfo = activity
- tracker1.componentName = activity.name
- tracker1.isEnabled = kotlin.runCatching {
- ActivityUtils.isEnabled(applicationContext(), packageInfo.packageName, activity.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = false
- tracker1.isService = false
- tracker1.isActivity = true
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun PackageInfo.getServicesTrackers(trackersData: ArrayList): ArrayList {
- val services = services ?: null
- val trackersList = arrayListOf()
-
- if (services != null) {
- for (service in services) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (service.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
- if (service.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.serviceInfo = service
- tracker1.componentName = service.name
- tracker1.isEnabled = kotlin.runCatching {
- ServicesUtils.isEnabled(applicationContext(), packageInfo.packageName, service.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = false
- tracker1.isService = true
- tracker1.isActivity = false
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
- private fun PackageInfo.getReceiversTrackers(trackersData: ArrayList): ArrayList {
- val receivers = receivers ?: null
- val trackersList = arrayListOf()
-
- if (receivers != null) {
- for (receiver in receivers) {
- for (tracker in trackersData) {
- tracker.codeSignature.split("|").forEach {
- if (receiver.name.lowercase().contains(keyword.lowercase()) || it.lowercase().contains(keyword.lowercase())) {
- if (receiver.name.lowercase().contains(it.lowercase())) {
- val tracker1 = Tracker()
- tracker.copyBasicTrackerInfo(tracker1)
-
- tracker1.receiverInfo = receiver
- tracker1.componentName = receiver.name
- tracker1.isEnabled = kotlin.runCatching {
- ReceiversUtils.isEnabled(applicationContext(), packageInfo.packageName, receiver.name)
- }.getOrElse {
- false
- }
- tracker1.isReceiver = true
- tracker1.isService = false
- tracker1.isActivity = false
-
- trackersList.add(tracker1)
-
- return@forEach
- }
- }
- }
- }
- }
- }
-
- return trackersList
- }
-
override fun runRootProcess(fileSystemManager: FileSystemManager?) {
if (fileSystemManager.isNotNull()) {
fileSystemManager?.let {
@@ -266,99 +151,6 @@ class TrackersViewModel(application: Application, private val packageInfo: Packa
tracker.value = null
}
- /**
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * Parse the file following the above structure
- */
- private fun readIntentFirewallXml(fileSystemManager: FileSystemManager?, trackersList: ArrayList) {
- if (fileSystemManager?.getFile(path)?.exists()?.invert()!!) {
- return
- }
-
- val channel = fileSystemManager.openChannel(path, FileSystemManager.MODE_READ_WRITE)
- val capacity = channel.size().toInt()
- val buffer = ByteBuffer.allocate(capacity)
- channel.read(buffer)
- buffer.flip()
-
- val xml = String(buffer.array(), Charset.defaultCharset())
- val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(xml)))
-
- val activityNodes = document.getElementsByTagName("activity")
- val serviceNodes = document.getElementsByTagName("service")
- val broadcastNodes = document.getElementsByTagName("broadcast")
-
- for (i in 0 until activityNodes.length) {
- val activityNode: Node = activityNodes.item(i)
- if (activityNode.nodeType == Node.ELEMENT_NODE) {
- val activityElement = activityNode as Element
- val isBlocked = activityElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = activityElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until serviceNodes.length) {
- val serviceNode: Node = serviceNodes.item(i)
- if (serviceNode.nodeType == Node.ELEMENT_NODE) {
- val serviceElement = serviceNode as Element
- val isBlocked = serviceElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = serviceElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- for (i in 0 until broadcastNodes.length) {
- val broadcastNode: Node = broadcastNodes.item(i)
- if (broadcastNode.nodeType == Node.ELEMENT_NODE) {
- val broadcastElement = broadcastNode as Element
- val isBlocked = broadcastElement.getAttribute("block").toBoolean()
- val componentFilters: NodeList = broadcastElement.getElementsByTagName("component-filter")
- for (j in 0 until componentFilters.length) {
- val componentFilterNode: Node = componentFilters.item(j)
- if (componentFilterNode.nodeType == Node.ELEMENT_NODE) {
- val componentFilterElement = componentFilterNode as Element
- val componentName = componentFilterElement.getAttribute("name")
-
- trackersList.find { it.componentName == componentName.split("/")[1] }?.let {
- it.isBlocked = isBlocked
- }
- }
- }
- }
- }
-
- channel.close()
- }
-
/**
*
*
diff --git a/fastlane/metadata/android/en-US/changelogs/10023.txt b/fastlane/metadata/android/en-US/changelogs/10023.txt
new file mode 100644
index 000000000..9d3bae4d0
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/10023.txt
@@ -0,0 +1,3 @@
+Refer to Change Logs under About section of the app to get the detailed list of all changes in this version.
+
+Feel free to join app's Telegram channel for future development updates: https://t.me/inure_app_manager
\ No newline at end of file