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