feat: select apk from storage

This commit is contained in:
Canny 2022-10-08 15:42:51 +03:00
parent 477ec3e182
commit b41f483f1c
No known key found for this signature in database
GPG Key ID: 395CCB0AA979F27B
8 changed files with 67 additions and 27 deletions

View File

@ -80,7 +80,7 @@ dependencies {
implementation("androidx.core:core-splashscreen:1.0.0") implementation("androidx.core:core-splashscreen:1.0.0")
// AndroidX activity // AndroidX activity
implementation("androidx.activity:activity-compose:1.6.0-rc02") implementation("androidx.activity:activity-compose:1.6.0")
implementation("androidx.work:work-runtime-ktx:2.7.1") implementation("androidx.work:work-runtime-ktx:2.7.1")
// Koin // Koin
@ -93,7 +93,7 @@ dependencies {
val composeVersion = "1.3.0-alpha03" val composeVersion = "1.3.0-alpha03"
implementation("androidx.compose.ui:ui:${composeVersion}") implementation("androidx.compose.ui:ui:${composeVersion}")
debugImplementation("androidx.compose.ui:ui-tooling:${composeVersion}") debugImplementation("androidx.compose.ui:ui-tooling:${composeVersion}")
implementation("androidx.compose.material3:material3:1.0.0-beta02") implementation("androidx.compose.material3:material3:1.0.0-beta03")
implementation("androidx.compose.material:material-icons-extended:${composeVersion}") implementation("androidx.compose.material:material-icons-extended:${composeVersion}")
// Accompanist // Accompanist
@ -134,5 +134,5 @@ dependencies {
// ListenableFuture // ListenableFuture
implementation("com.google.guava:guava:31.0.1-android") implementation("com.google.guava:guava:31.0.1-android")
implementation("androidx.concurrent:concurrent-futures:1.1.0") implementation("androidx.concurrent:concurrent-futures:1.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.4")
} }

View File

@ -11,7 +11,7 @@ import java.util.*
object Variables { object Variables {
val selectedAppPackage = mutableStateOf(Optional.empty<String>()) val selectedAppPackage = mutableStateOf(Optional.empty<ApplicationInfo>())
val selectedPatches = mutableStateListOf<String>() val selectedPatches = mutableStateListOf<String>()
val patches = mutableStateOf<Resource<List<Class<out Patch<Context>>>>>(Resource.Loading) val patches = mutableStateOf<Resource<List<Class<out Patch<Context>>>>>(Resource.Loading)
val patchesState by patches val patchesState by patches

View File

@ -89,7 +89,7 @@ class PatcherWorker(context: Context, parameters: WorkerParameters, private val
applicationContext.filesDir.resolve("framework").also { it.mkdirs() }.absolutePath applicationContext.filesDir.resolve("framework").also { it.mkdirs() }.absolutePath
val integrationsCacheDir = val integrationsCacheDir =
applicationContext.filesDir.resolve("integrations-cache").also { it.mkdirs() } applicationContext.filesDir.resolve("integrations-cache").also { it.mkdirs() }
val appInfo = applicationContext.packageManager.getApplicationInfo(selectedAppPackage.value.get(), 3) val appInfo = selectedAppPackage.value.get()
Logging.log += "Checking prerequisites\n" Logging.log += "Checking prerequisites\n"
val patches = findPatchesByIds(selectedPatches) val patches = findPatchesByIds(selectedPatches)
@ -151,9 +151,8 @@ class PatcherWorker(context: Context, parameters: WorkerParameters, private val
Logging.log += "Applying ${patches.size} patch(es)\n" Logging.log += "Applying ${patches.size} patch(es)\n"
patcher.executePatches().forEach { (patch, result) -> patcher.executePatches().forEach { (patch, result) ->
if (result.isFailure) { if (result.isFailure) {
Logging.log += "Failed to apply $patch \n" + result.exceptionOrNull()!!.message Logging.log += "Failed to apply $patch" + result.exceptionOrNull()!!.cause + "\n"
return@forEach return@forEach
} }

View File

@ -71,7 +71,10 @@ fun PatcherScreen(
) )
Text( Text(
text = if (patchesLoaded) { text = if (patchesLoaded) {
selectedAppPackage.orElse(stringResource(R.string.card_application_not_selected)) if (selectedAppPackage.isPresent) {
selectedAppPackage.get().packageName
}
else {stringResource(R.string.card_application_not_selected)}
} else { } else {
stringResource(R.string.card_application_not_loaded) stringResource(R.string.card_application_not_loaded)
}, },

View File

@ -11,7 +11,6 @@ import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Done import androidx.compose.material.icons.filled.Done
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@ -31,7 +30,7 @@ fun PatchingScreen(
navigator: BackstackNavigator<AppDestination>, navigator: BackstackNavigator<AppDestination>,
vm: PatchingScreenViewModel = getViewModel() vm: PatchingScreenViewModel = getViewModel()
) { ) {
var patching by rememberSaveable {mutableStateOf(false)} var patching by mutableStateOf(false)
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
LaunchedEffect(patching) { LaunchedEffect(patching) {

View File

@ -1,14 +1,19 @@
package app.revanced.manager.ui.screen.subscreens package app.revanced.manager.ui.screen.subscreens
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.SdStorage
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.Variables.filteredApps import app.revanced.manager.Variables.filteredApps
@ -28,32 +33,45 @@ fun AppSelectorSubscreen(
navigator: BackstackNavigator<AppDestination>, navigator: BackstackNavigator<AppDestination>,
vm: AppSelectorViewModel = getViewModel(), vm: AppSelectorViewModel = getViewModel(),
) { ) {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
it?.let { uri ->
vm.setSelectedAppPackageFromFile(uri)
navigator.pop()
return@rememberLauncherForActivityResult
}
Toast.makeText(context, "Couldn't load APK file.", Toast.LENGTH_SHORT).show()
}
Scaffold( Scaffold(
topBar = { topBar = {
MediumTopAppBar( MediumTopAppBar(title = { Text(stringResource(R.string.app_selector_title)) },
title = { Text(stringResource(R.string.app_selector_title)) },
navigationIcon = { navigationIcon = {
IconButton(onClick = navigator::pop) { IconButton(onClick = navigator::pop) {
Icon( Icon(Icons.Default.ArrowBack, contentDescription = null)
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
} }
})
}, },
floatingActionButton = {
ExtendedFloatingActionButton(
onClick = { launcher.launch(arrayOf("application/vnd.android.package-archive")) },
icon = { Icon(Icons.Default.SdStorage, contentDescription = null) },
text = { Text("Storage") },
) )
} },
) { paddingValues -> ) { paddingValues ->
when (patchesState) { when (patchesState) {
is Resource.Success -> { is Resource.Success -> {
LazyColumn(modifier = Modifier.padding(paddingValues)) { LazyColumn(modifier = Modifier.padding(paddingValues)) {
items(count = filteredApps.size) { items(count = filteredApps.size) {
val app = filteredApps[it] val app = filteredApps.distinct()[it]
val label = vm.applicationLabel(app) val label = vm.applicationLabel(app)
val packageName = app.packageName val packageName = app.packageName
val same = packageName == label val same = packageName == label
ListItem(modifier = Modifier.clickable { ListItem(modifier = Modifier.clickable {
vm.setSelectedAppPackage(app.packageName) vm.setSelectedAppPackage(app)
navigator.pop() navigator.pop()
}, leadingContent = { }, leadingContent = {
AppIcon(vm.loadIcon(app), packageName) AppIcon(vm.loadIcon(app), packageName)

View File

@ -2,7 +2,9 @@ package app.revanced.manager.ui.viewmodel
import android.app.Application import android.app.Application
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import app.revanced.manager.Variables import app.revanced.manager.Variables
@ -11,6 +13,8 @@ import app.revanced.manager.Variables.patches
import app.revanced.manager.Variables.selectedAppPackage import app.revanced.manager.Variables.selectedAppPackage
import app.revanced.manager.ui.Resource import app.revanced.manager.ui.Resource
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.* import java.util.*
class AppSelectorViewModel( class AppSelectorViewModel(
@ -28,7 +32,7 @@ class AppSelectorViewModel(
patch.compatiblePackages?.forEach { pkg -> patch.compatiblePackages?.forEach { pkg ->
try { try {
val appInfo = app.packageManager.getApplicationInfo(pkg.name, 0) val appInfo = app.packageManager.getApplicationInfo(pkg.name, 0)
if (appInfo !in filteredApps) { if (!filteredApps.contains(appInfo)) {
filteredApps.add(appInfo) filteredApps.add(appInfo)
return@forEach return@forEach
} }
@ -51,11 +55,25 @@ class AppSelectorViewModel(
return info.loadIcon(app.packageManager) return info.loadIcon(app.packageManager)
} }
fun setSelectedAppPackage(appId: String) { fun setSelectedAppPackage(appId: ApplicationInfo) {
selectedAppPackage.value.ifPresent { s -> selectedAppPackage.value.ifPresent { s ->
if (s != appId) Variables.selectedPatches.clear() if (s != appId) Variables.selectedPatches.clear()
} }
selectedAppPackage.value = Optional.of(appId) selectedAppPackage.value = Optional.of(appId)
}
fun setSelectedAppPackageFromFile(file: Uri?) {
val apkDir = app.filesDir.resolve("input.apk").toPath()
Files.copy(
app.contentResolver.openInputStream(file!!),
apkDir,
StandardCopyOption.REPLACE_EXISTING
)
setSelectedAppPackage(
app.packageManager.getPackageArchiveInfo(
apkDir.toString(),
PackageManager.GET_META_DATA
)!!.applicationInfo
)
} }
} }

View File

@ -1,6 +1,7 @@
package app.revanced.manager.ui.viewmodel package app.revanced.manager.ui.viewmodel
import android.app.Application import android.app.Application
import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Parcelable import android.os.Parcelable
import android.util.Log import android.util.Log
@ -64,13 +65,15 @@ class PatcherScreenViewModel(private val app: Application, private val api: API)
} }
fun getSelectedPackageInfo() = fun getSelectedPackageInfo(): PackageInfo? {
if (selectedAppPackage.value.isPresent) if (selectedAppPackage.value.isPresent) {
app.packageManager.getPackageInfo( return app.packageManager.getPackageArchiveInfo(
selectedAppPackage.value.get(), selectedAppPackage.value.get().publicSourceDir,
PackageManager.GET_META_DATA PackageManager.GET_META_DATA
) )
else null }
else {return null}
}
fun checkSplitApk(): Boolean { fun checkSplitApk(): Boolean {
if (getSelectedPackageInfo()!!.applicationInfo!!.metaData!!.getBoolean( if (getSelectedPackageInfo()!!.applicationInfo!!.metaData!!.getBoolean(