Skip to content

Commit

Permalink
More user-friendly locking and unlocking
Browse files Browse the repository at this point in the history
  • Loading branch information
iamr0s committed May 31, 2023
1 parent a0fb411 commit 62cdb9a
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 108 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ android {
namespace = "com.rosan.installer"
minSdk = 21
targetSdk = 33
versionCode = 20
versionCode = 21
versionName = "1.6"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.rosan.installer.data.app.model.impl

import android.content.ComponentName
import android.content.Context
import android.util.Log
import com.rosan.installer.data.app.repo.DSRepo
import com.rosan.installer.data.recycle.model.impl.AppProcessPrivilegedServiceRecyclers
import com.rosan.installer.data.recycle.model.impl.DhizukuPrivilegedServiceRecycler
Expand All @@ -26,8 +25,6 @@ object DSRepoImpl : DSRepo, KoinComponent {
.make()

else -> AppProcessPrivilegedServiceRecyclers.get("sh").make()
}.apply {
Log.e("r0s", "doWork: ${config.authorizer}")
}.use {
it.entity.setDefaultInstaller(
ComponentName(context, InstallerActivity::class.java),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.rosan.installer.data.app.model.impl.installer

import android.content.Context
import android.os.IBinder
import com.rosan.app_process.AppProcess
import com.rosan.installer.data.app.model.entity.InstallEntity
Expand All @@ -10,13 +9,8 @@ import com.rosan.installer.data.recycle.model.impl.AppProcessPrivilegedServiceRe
import com.rosan.installer.data.recycle.model.impl.AppProcessRecyclers
import com.rosan.installer.data.recycle.repo.Recyclable
import com.rosan.installer.data.settings.model.room.entity.ConfigEntity
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

abstract class AppProcessInstallerRepoImpl : IBinderInstallerRepoImpl(),
KoinComponent {
private val context by inject<Context>()

abstract class AppProcessInstallerRepoImpl : IBinderInstallerRepoImpl() {
private lateinit var recycler: Recyclable<AppProcess>

abstract fun getShell(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package com.rosan.installer.data.app.model.impl.installer

import android.content.Context
import com.rosan.installer.data.app.model.entity.InstallEntity
import com.rosan.installer.data.app.model.entity.InstallExtraEntity
import com.rosan.installer.data.settings.model.room.entity.ConfigEntity
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

object CustomizeInstallerRepoImpl : AppProcessInstallerRepoImpl(), KoinComponent {
private val context by inject<Context>()
object CustomizeInstallerRepoImpl : AppProcessInstallerRepoImpl() {
override fun getShell(
config: ConfigEntity,
entities: List<InstallEntity>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package com.rosan.installer.data.app.model.impl.installer

import android.content.Context
import com.rosan.installer.data.app.model.entity.InstallEntity
import com.rosan.installer.data.app.model.entity.InstallExtraEntity
import com.rosan.installer.data.settings.model.room.entity.ConfigEntity
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

object RootInstallerRepoImpl : AppProcessInstallerRepoImpl(), KoinComponent {
private val context by inject<Context>()
object RootInstallerRepoImpl : AppProcessInstallerRepoImpl() {
override fun getShell(
config: ConfigEntity,
entities: List<InstallEntity>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AppProcessRecycler(private val shell: String) : Recycler<AppProcess>() {
override fun onMake(): AppProcess {
return CustomizeAppProcess(shell).apply {
if (init()) return@apply
if (shell == "su" || shell.startsWith("su ")) throw RootNotWorkException()
if (shell == "su") throw RootNotWorkException()
else throw AppProcessNotWorkException()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.rosan.installer.ui.activity

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -90,7 +89,6 @@ class InstallerActivity : ComponentActivity(), KoinComponent {
}
launch {
installer.background.collect {
Log.e("r0s", "background $it")
if (it) this@InstallerActivity.finish()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.rosan.installer.R
import com.rosan.installer.data.installer.repo.InstallerRepo
import com.rosan.installer.data.recycle.model.exception.AppProcessNotWorkException
import com.rosan.installer.data.recycle.model.exception.DhizukuNotWorkException
import com.rosan.installer.data.recycle.model.exception.RootNotWorkException
import com.rosan.installer.data.recycle.model.exception.ShizukuNotWorkException
import com.rosan.installer.ui.page.installer.dialog.DialogViewModel
import com.rosan.installer.util.help

val pausingIcon: @Composable () -> Unit = {
Icon(
Expand All @@ -53,40 +48,7 @@ val errorText: ((installer: InstallerRepo, viewModel: DialogViewModel) -> (@Comp
.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)
) {
item {
val text = when (val error = installer.error) {
is com.rosan.installer.data.app.model.exception.InstallFailedAlreadyExistsException -> stringResource(R.string.exception_install_failed_already_exists)
is com.rosan.installer.data.app.model.exception.InstallFailedInvalidAPKException -> stringResource(R.string.exception_install_failed_invalid_apk)
is com.rosan.installer.data.app.model.exception.InstallFailedInvalidURIException -> stringResource(R.string.exception_install_failed_invalid_uri)
is com.rosan.installer.data.app.model.exception.InstallFailedInsufficientStorageException -> stringResource(R.string.exception_install_failed_insufficient_storage)
is com.rosan.installer.data.app.model.exception.InstallFailedDuplicatePackageException -> stringResource(R.string.exception_install_failed_duplicate_package)
is com.rosan.installer.data.app.model.exception.InstallFailedNoSharedUserException -> stringResource(R.string.exception_install_failed_no_shared_user)
is com.rosan.installer.data.app.model.exception.InstallFailedUpdateIncompatibleException -> stringResource(R.string.exception_install_failed_update_incompatible)
is com.rosan.installer.data.app.model.exception.InstallFailedSharedUserIncompatibleException -> stringResource(R.string.exception_install_failed_shared_user_incompatible)
is com.rosan.installer.data.app.model.exception.InstallFailedMissingSharedLibraryException -> stringResource(R.string.exception_install_failed_missing_shared_library)
is com.rosan.installer.data.app.model.exception.InstallFailedReplaceCouldntDeleteException -> stringResource(R.string.exception_install_failed_replace_couldnt_delete)
is com.rosan.installer.data.app.model.exception.InstallFailedDexoptException -> stringResource(R.string.exception_install_failed_dexopt)
is com.rosan.installer.data.app.model.exception.InstallFailedOlderSdkException -> stringResource(R.string.exception_install_failed_older_sdk)
is com.rosan.installer.data.app.model.exception.InstallFailedConflictingProviderException -> stringResource(R.string.exception_install_failed_conflicting_provider)
is com.rosan.installer.data.app.model.exception.InstallFailedNewerSDKException -> stringResource(R.string.exception_install_failed_newer_sdk)
is com.rosan.installer.data.app.model.exception.InstallFailedTestOnlyException -> stringResource(R.string.exception_install_failed_test_only)
is com.rosan.installer.data.app.model.exception.InstallFailedCpuAbiIncompatibleException -> stringResource(R.string.exception_install_failed_cpu_abi_incompatible)
is com.rosan.installer.data.app.model.exception.InstallFailedMissingFeatureException -> stringResource(R.string.exception_install_failed_missing_feature)
is com.rosan.installer.data.app.model.exception.InstallFailedContainerErrorException -> stringResource(R.string.exception_install_failed_container_error)
is com.rosan.installer.data.app.model.exception.InstallFailedInvalidInstallLocationException -> stringResource(R.string.exception_install_failed_invalid_install_location)
is com.rosan.installer.data.app.model.exception.InstallFailedMediaUnavailableException -> stringResource(R.string.exception_install_failed_media_unavailable)
is com.rosan.installer.data.app.model.exception.InstallFailedVerificationTimeoutException -> stringResource(R.string.exception_install_failed_verification_timeout)
is com.rosan.installer.data.app.model.exception.InstallFailedVerificationFailureException -> stringResource(R.string.exception_install_failed_verification_failure)
is com.rosan.installer.data.app.model.exception.InstallFailedPackageChangedException -> stringResource(R.string.exception_install_failed_package_changed)
is com.rosan.installer.data.app.model.exception.InstallFailedUidChangedException -> stringResource(R.string.exception_install_failed_uid_changed)
is com.rosan.installer.data.app.model.exception.InstallFailedVersionDowngradeException -> stringResource(R.string.exception_install_failed_version_downgrade)

is ShizukuNotWorkException -> stringResource(R.string.exception_shizuku_not_work)
is DhizukuNotWorkException -> stringResource(R.string.exception_dhizuku_not_work)
is RootNotWorkException -> stringResource(R.string.exception_root_not_work)
is AppProcessNotWorkException -> stringResource(R.string.exception_app_process_not_work)
else -> stringResource(R.string.exception_install_failed_unknown)
}
Text(text, fontWeight = FontWeight.Bold)
Text(installer.error.help(), fontWeight = FontWeight.Bold)
}
item {
SelectionContainer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,37 @@ package com.rosan.installer.ui.page.settings.preferred
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.twotone.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.rosan.installer.BuildConfig
import com.rosan.installer.R
import com.rosan.installer.data.app.model.impl.DSRepoImpl
import com.rosan.installer.data.settings.model.room.entity.ConfigEntity
import com.rosan.installer.data.settings.util.ConfigUtil
import com.rosan.installer.ui.widget.setting.BaseWidget
import com.rosan.installer.ui.widget.setting.DropDownMenuWidget
import com.rosan.installer.ui.widget.setting.LabelWidget
import com.rosan.installer.util.help
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.androidx.compose.getViewModel
import org.koin.compose.getKoin
import java.io.File

@OptIn(ExperimentalMaterial3Api::class)
Expand Down Expand Up @@ -65,8 +70,8 @@ fun PreferredPage(
item { DataAuthorizerWidget(viewModel) }
item { DataCustomizeAuthorizerWidget(viewModel) }
item { LabelWidget(label = stringResource(id = R.string.basic)) }
item { LockDefaultInstaller() }
item { UnlockDefaultInstaller() }
item { DefaultInstaller(snackBarHostState, true) }
item { DefaultInstaller(snackBarHostState, false) }
item { ClearCache() }
item { LabelWidget(label = stringResource(id = R.string.more)) }
item { UserTerms() }
Expand Down Expand Up @@ -126,58 +131,97 @@ fun DataCustomizeAuthorizerWidget(viewModel: PreferredViewModel) {
}

@Composable
fun LockDefaultInstaller() {
fun DefaultInstaller(snackBarHostState: SnackbarHostState, lock: Boolean) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var inProgress by remember {
var exception: Throwable by remember {
mutableStateOf(Throwable())
}
var showException by remember {
mutableStateOf(false)
}
BaseWidget(
icon = Icons.TwoTone.Favorite,
title = stringResource(id = R.string.lock_default_installer),
onClick = {

if (inProgress) return@BaseWidget
inProgress = true
fun workIt() {
synchronized(scope) {
scope.launch(Dispatchers.IO) {
val error = kotlin.runCatching {
DSRepoImpl.doWork(
ConfigUtil.getByPackageName(BuildConfig.APPLICATION_ID),
true
)
val exceptionOrNull = kotlin.runCatching {
DSRepoImpl.doWork(ConfigUtil.getByPackageName(null), lock)
}.exceptionOrNull()
error?.printStackTrace()
inProgress = false
exceptionOrNull?.printStackTrace()

snackBarHostState.currentSnackbarData?.dismiss()
if (exceptionOrNull == null) snackBarHostState.showSnackbar(
context.getString(
if (lock) R.string.lock_default_installer_success
else R.string.unlock_default_installer_success
)
)
else {
val result = snackBarHostState.showSnackbar(
context.getString(
if (lock) R.string.lock_default_installer_failed
else R.string.unlock_default_installer_failed
),
context.getString(R.string.details),
duration = SnackbarDuration.Short
)
if (result == SnackbarResult.ActionPerformed) {
exception = exceptionOrNull
showException = true
}
}
}
}
) {}
}

@Composable
fun UnlockDefaultInstaller() {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val koin = getKoin()
var inProgress by remember {
mutableStateOf(false)
}

BaseWidget(
icon = Icons.TwoTone.FavoriteBorder,
title = stringResource(id = R.string.unlock_default_installer),
icon = if (lock) Icons.TwoTone.Favorite else Icons.TwoTone.FavoriteBorder,
title =
stringResource(if (lock) R.string.lock_default_installer else R.string.unlock_default_installer),
description =
stringResource(if (lock) R.string.lock_default_installer_dsp else R.string.unlock_default_installer_dsp),
onClick = {
if (inProgress) return@BaseWidget
inProgress = true
scope.launch(Dispatchers.IO) {
val error = kotlin.runCatching {
DSRepoImpl.doWork(
ConfigUtil.getByPackageName(BuildConfig.APPLICATION_ID),
false
)
}.exceptionOrNull()
error?.printStackTrace()
inProgress = false
}
workIt()
}
) {}
if (!showException) return
AlertDialog(onDismissRequest = {
showException = false
}, title = {
Text(stringResource(if (lock) R.string.lock_default_installer_failed else R.string.unlock_default_installer_failed))
}, text = {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onErrorContainer) {
LazyColumn(
modifier = Modifier
.clip(RoundedCornerShape(12.dp))
.background(MaterialTheme.colorScheme.errorContainer)
.fillMaxWidth()
.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)
) {
item {
Text(exception.help(), fontWeight = FontWeight.Bold)
}
item {
SelectionContainer {
Text(exception.stackTraceToString().trim())
}
}
}
}
}, confirmButton = {
TextButton(onClick = {
showException = false
workIt()
}) {
Text(stringResource(R.string.retry))
}
}, dismissButton = {
TextButton(onClick = {
showException = false
}) {
Text(stringResource(R.string.cancel))
}
})
}

@Composable
Expand Down
Loading

0 comments on commit 62cdb9a

Please sign in to comment.