Skip to content

Commit

Permalink
Add installer app name when possible
Browse files Browse the repository at this point in the history
* Mapping installer app name from installed app informations
* Rename "Preload or ADB" to "OS or ADB"
* Change format of mapping installer list
* Add more installer
* Move contributors list to `Contributors`
  • Loading branch information
akexorcist committed Mar 20, 2024
1 parent 1096ff2 commit 20c68ac
Show file tree
Hide file tree
Showing 18 changed files with 453 additions and 293 deletions.
12 changes: 1 addition & 11 deletions app/src/main/java/com/akexorcist/ruammij/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ class MainActivity : AppCompatActivity() {
override fun onDisplayAdded(displayId: Int) {
val display = displayManager.getDisplay(displayId) ?: return
val packageName = display.getOwnerPackageName() ?: return
val app = getInstalledApp(packageName) ?: return
sharedEventViewModel.onMediaProjectionDetected(app, displayId)
sharedEventViewModel.onMediaProjectionDetected(packageName, displayId)
}

override fun onDisplayRemoved(displayId: Int) {
Expand All @@ -52,13 +51,4 @@ class MainActivity : AppCompatActivity() {

override fun onDisplayChanged(displayId: Int) = Unit
}

private fun getInstalledApp(packageName: String): InstalledApp? {
return try {
packageManager.getPackageInfo(packageName, 0).toInstalledApp(packageManager)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.akexorcist.ruammij

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.akexorcist.ruammij.data.InstalledApp
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
Expand All @@ -12,12 +11,12 @@ class SharedEventViewModel : ViewModel() {
val mediaProjectionEvent = _mediaProjectionEvent.receiveAsFlow()

fun onMediaProjectionDetected(
app: InstalledApp,
packageName: String,
displayId: Int,
) = viewModelScope.launch {
_mediaProjectionEvent.send(
AutoMediaProjectionDetectionEvent.Detected(
app = app,
packageName = packageName,
displayId = displayId,
)
)
Expand All @@ -36,7 +35,7 @@ class SharedEventViewModel : ViewModel() {

sealed class AutoMediaProjectionDetectionEvent {
data class Detected(
val app: InstalledApp,
val packageName: String,
val displayId: Int,
) : AutoMediaProjectionDetectionEvent()

Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/com/akexorcist/ruammij/common/Contributors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.akexorcist.ruammij.common

object Contributors {
val contributors = listOf(
"9arm",
"Somkiat Khitwongwattana",
"Sorakrich Oanmanee",
"เอกลักษณ์ ต่อติด",
"Kritsadin Rayanakorn",
"Tipatai Puthanukunkit",
"Dheerapat Tookkane",
"Kajornsak Peerapathananont",
)
}
164 changes: 51 additions & 113 deletions app/src/main/java/com/akexorcist/ruammij/common/Installers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,118 +7,56 @@ enum class InstallerVerificationStatus {
SIDE_LOAD,
}

enum class Installer(
val packageName: String?,
val readableName: String?,
val verificationStatus: InstallerVerificationStatus,
) {
GOOGLE_PLAY(
"com.android.vending",
"Google Play",
InstallerVerificationStatus.VERIFIED,
),
AMAZON_APPSTORE(
"com.amazon.venezia",
"Amazon Appstore",
InstallerVerificationStatus.VERIFIED,
),
HEYTAP_APP_MARKET(
"com.heytap.market",
"App Market",
InstallerVerificationStatus.VERIFIED,
),
VIVO_V_APPSTORE(
"com.vivo.appstore",
"vivo V-Appstore",
InstallerVerificationStatus.VERIFIED,
),
VIVO_SYSTEM_LAUNCHER(
"com.bbk.launcher2",
"vivo System Launcher",
InstallerVerificationStatus.VERIFIED,
),
FACEBOOK(
"com.facebook.system",
"Facebook",
InstallerVerificationStatus.VERIFIED,
),
SAMSUNG_GALAXY_STORE(
"com.sec.android.app.samsungapps",
"Samsung Galaxy Store",
InstallerVerificationStatus.VERIFIED,
),
SAMSUNG_OMC_AGENT(
"com.samsung.android.app.omcagent",
"Samsung OMC Agent",
InstallerVerificationStatus.VERIFIED,
),
SAMSUNG_SMART_SWITCH(
"com.sec.android.easyMover",
"Samsung Smart Switch",
InstallerVerificationStatus.VERIFIED,
),
SAMSUNG_CLOUD(
"com.samsung.android.scloud",
"Samsung Cloud",
InstallerVerificationStatus.VERIFIED,
),
HUAWEI_APP_GALLERY(
"com.huawei.appmarket",
"HUAWEI AppGallery",
InstallerVerificationStatus.VERIFIED,
),
HUAWEI_SYSTEM_SERVICES(
"com.huawei.systemserver",
"HUAWEI System Services",
InstallerVerificationStatus.VERIFIED,
),
HUAWEI_HMS_SERVICES_FRAMEWORK(
"com.huawei.android.hsf",
"HUAWEI HMS Services Framework",
InstallerVerificationStatus.VERIFIED
),
HUAWEI_SOFTWARE_UPDATE(
"com.huawei.android.hwouc",
"HUAWEI Software Update",
InstallerVerificationStatus.VERIFIED,
),
XIAOMI_MARKET(
"com.xiaomi.market",
"Xiaomi Market",
InstallerVerificationStatus.VERIFIED,
),
XIAOMI_GET_APPS(
"com.xiaomi.mipicks",
"Xiaomi GetApps",
InstallerVerificationStatus.VERIFIED,
),
XIAOMI_ANALYTICS(
"com.miui.analytics",
"Xiaomi Analytics",
InstallerVerificationStatus.VERIFIED,
),
COLOR_OS_MY_FILES(
"com.coloros.filemanager",
"ColorOS My Files",
InstallerVerificationStatus.UNVERIFIED,
),
APK_PURE(
"com.apkpure.aegon",
"APKPure",
InstallerVerificationStatus.UNVERIFIED,
),
SIDE_LOAD(
"com.google.android.packageinstaller",
"Sideload",
InstallerVerificationStatus.SIDE_LOAD,
),
PRE_INSTALLED(
null,
null,
InstallerVerificationStatus.VERIFIED,
);
object Installers {
val apps: Map<String?, InstallerVerificationStatus> = mapOf(
null to InstallerVerificationStatus.VERIFIED,
"android" to InstallerVerificationStatus.VERIFIED,
"com.android.vending" to InstallerVerificationStatus.VERIFIED,
"com.amazon.venezia" to InstallerVerificationStatus.VERIFIED,
"com.heytap.market" to InstallerVerificationStatus.VERIFIED,
"com.vivo.appstore" to InstallerVerificationStatus.VERIFIED,
"com.bbk.appstore" to InstallerVerificationStatus.VERIFIED,
"com.bbk.launcher2" to InstallerVerificationStatus.VERIFIED,
"com.bbk.theme" to InstallerVerificationStatus.VERIFIED,
"com.iqoo.website" to InstallerVerificationStatus.VERIFIED,
"com.vivo.assistant" to InstallerVerificationStatus.VERIFIED,
"com.vivo.easyshare" to InstallerVerificationStatus.VERIFIED,
"com.facebook.system" to InstallerVerificationStatus.VERIFIED,
"com.sec.android.app.samsungapps" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.app.omcagent" to InstallerVerificationStatus.VERIFIED,
"com.sec.android.easyMover" to InstallerVerificationStatus.VERIFIED,
"com.sec.android.easyMover.Agent" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.scloud" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.themestore" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.themecenter" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.goodlock" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.app.updatecenter" to InstallerVerificationStatus.VERIFIED,
"com.samsung.android.app.watchmanager" to InstallerVerificationStatus.VERIFIED,
"com.huawei.appmarket" to InstallerVerificationStatus.VERIFIED,
"com.huawei.systemserver" to InstallerVerificationStatus.VERIFIED,
"com.huawei.android.hsf" to InstallerVerificationStatus.VERIFIED,
"com.huawei.android.hwouc" to InstallerVerificationStatus.VERIFIED,
"com.huawei.android.thememanager" to InstallerVerificationStatus.VERIFIED,
"com.xiaomi.market" to InstallerVerificationStatus.VERIFIED,
"com.xiaomi.mipicks" to InstallerVerificationStatus.VERIFIED,
"com.miui.analytics" to InstallerVerificationStatus.VERIFIED,
"com.xiaomi.discover" to InstallerVerificationStatus.VERIFIED,
"com.aura.oobe.deutsche" to InstallerVerificationStatus.VERIFIED,
"com.sonyericsson.updatecenter" to InstallerVerificationStatus.VERIFIED,

"com.apkpure.aegon" to InstallerVerificationStatus.UNVERIFIED,
"com.qooapp.qoohelper" to InstallerVerificationStatus.UNVERIFIED,

companion object {
fun fromPackageName(packageName: String?) = entries.firstOrNull { it.packageName == packageName }
}
"com.coloros.filemanager" to InstallerVerificationStatus.SIDE_LOAD,
"com.google.android.packageinstaller" to InstallerVerificationStatus.SIDE_LOAD,
"com.miui.packageinstaller" to InstallerVerificationStatus.SIDE_LOAD,
"com.android.chrome" to InstallerVerificationStatus.SIDE_LOAD,
"com.htetznaing.zfile" to InstallerVerificationStatus.SIDE_LOAD,
)
}

data class Installer(
val name: String?,
val packageName: String?,
val verificationStatus: InstallerVerificationStatus,
)
88 changes: 79 additions & 9 deletions app/src/main/java/com/akexorcist/ruammij/data/DeviceRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,34 @@ package com.akexorcist.ruammij.data
import android.Manifest
import android.accessibilityservice.AccessibilityServiceInfo
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.hardware.display.DisplayManager
import android.os.Build
import android.provider.Settings
import android.view.accessibility.AccessibilityManager
import com.akexorcist.ruammij.common.CoroutineDispatcherProvider
import com.akexorcist.ruammij.common.Installer
import com.akexorcist.ruammij.common.InstallerVerificationStatus
import com.akexorcist.ruammij.common.Installers
import com.akexorcist.ruammij.ui.overview.MediaProjectionApp
import com.akexorcist.ruammij.ui.overview.MediaProjectionState
import com.akexorcist.ruammij.utility.getInstaller
import com.akexorcist.ruammij.utility.getInstallerPackageName
import com.akexorcist.ruammij.utility.getOwnerPackageName
import com.akexorcist.ruammij.utility.toInstalledApp
import com.akexorcist.ruammij.utility.toInstaller
import kotlinx.coroutines.withContext
import kotlin.reflect.*

interface DeviceRepository {
suspend fun getInstalledApps(forceRefresh: Boolean = false): List<InstalledApp>

suspend fun getInstalledApp(
forceRefresh: Boolean = false,
packageName: String,
): InstalledApp?

suspend fun getEnabledAccessibilityApps(forceRefresh: Boolean = false): List<InstalledApp>

suspend fun getAccessibilitySupportApps(forceRefresh: Boolean = false): List<InstalledApp>
Expand Down Expand Up @@ -49,13 +61,60 @@ class DefaultDeviceRepository(

override suspend fun getInstalledApps(forceRefresh: Boolean): List<InstalledApp> =
getCachedDataOrFetch(::cacheInstalledApps, forceRefresh) {
packageManager.getInstalledApplications(0).mapNotNull {
runCatching {
packageManager.getPackageInfo(it.packageName, 0).toInstalledApp(packageManager)
}.getOrNull()
val installedAppInfoList: Map<String, PackageInfo> = packageManager.getInstalledApplications(0)
.mapNotNull {
runCatching { packageManager.getPackageInfo(it.packageName, 0) }.getOrNull()
}
.associateBy { it.packageName }

val installers: Map<String?, Installer> = installedAppInfoList
.map { (_, info) -> info.applicationInfo.getInstallerPackageName(packageManager) }
.distinctBy { it }
.map { installerPackageName ->
installedAppInfoList[installerPackageName]
.let { info ->
info.toInstaller(
packageName = installerPackageName,
packageManager = packageManager,
)
}
}
.associateBy { it.packageName }

installedAppInfoList.map { (_, value) ->
val installerPackageName = value.applicationInfo.getInstallerPackageName(packageManager)
val installer = installers[installerPackageName]
?: Installer(
name = when (installerPackageName == null) {
true -> "OS or ADB"
false -> null
},
packageName = installerPackageName,
verificationStatus = when (installerPackageName == null) {
true -> InstallerVerificationStatus.VERIFIED
false -> InstallerVerificationStatus.UNVERIFIED
},
)
value.toInstalledApp(packageManager, installer)
}
}

override suspend fun getInstalledApp(
forceRefresh: Boolean,
packageName: String,
): InstalledApp? {
val app = if (!forceRefresh) {
cacheInstalledApps?.find { it.packageName == context.packageName }
} else {
null
}
return app ?: runCatching {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
val installer = packageInfo.getInstaller(packageManager)
packageInfo.toInstalledApp(packageManager, installer)
}.getOrNull()
}

private var cacheEnabledAccessibilityApps: List<InstalledApp>? = null

override suspend fun getEnabledAccessibilityApps(forceRefresh: Boolean): List<InstalledApp> =
Expand All @@ -64,9 +123,14 @@ class DefaultDeviceRepository(
.orEmpty()
.mapNotNull { info ->
runCatching {
info.resolveInfo.serviceInfo.packageName.let { packageManager.getPackageInfo(it, 0) }
.toInstalledApp(packageManager)
info.resolveInfo.serviceInfo.packageName.let {
packageManager.getPackageInfo(it, 0)
}
}.getOrNull()
?.let { packageInfo ->
val installer = packageInfo.getInstaller(packageManager)
packageInfo.toInstalledApp(packageManager, installer)
}
}
}

Expand All @@ -79,7 +143,10 @@ class DefaultDeviceRepository(
packageInfo.services
?.any { serviceInfo -> serviceInfo.permission == Manifest.permission.BIND_ACCESSIBILITY_SERVICE }
?: false
}.map { it.toInstalledApp(packageManager) }
}.map { packageInfo ->
val installer = packageInfo.getInstaller(packageManager)
packageInfo.toInstalledApp(packageManager, installer)
}
}

private var cacheRunningMediaProjectionApps: List<MediaProjectionApp>? = null
Expand All @@ -93,8 +160,11 @@ class DefaultDeviceRepository(
display.displayId to packageName
}
}.mapNotNull { (displayId, packageName) ->
runCatching { packageManager.getPackageInfo(packageName, 0).toInstalledApp(packageManager) }
.getOrNull()
runCatching {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
val installer = packageInfo.getInstaller(packageManager)
packageInfo.toInstalledApp(packageManager, installer)
}.getOrNull()
?.let { app -> displayId to app }
}.map { (displayId, app) ->
MediaProjectionApp(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.akexorcist.ruammij.data

import android.graphics.drawable.Drawable
import com.akexorcist.ruammij.common.Installer

data class InstalledApp(
val name: String,
Expand All @@ -9,5 +10,5 @@ data class InstalledApp(
val icon: Drawable?,
val systemApp: Boolean,
val installedAt: Long?,
val installer: String?,
val installer: Installer,
)
Loading

0 comments on commit 20c68ac

Please sign in to comment.