AppInstaller: Always use intent based uninstallation of apps

This requests user's confirmation before uninstallation every time which
is what we want to happen as well.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-01-20 15:12:57 +05:30
parent b46d232956
commit 859d32d878
8 changed files with 21 additions and 156 deletions

View File

@@ -40,13 +40,3 @@ inline fun <reified T : Context> Context.newIntent(flags: Int, extras: Bundle):
intent.putExtras(extras) intent.putExtras(extras)
return intent return intent
} }
fun Intent.applyUninstallActionCompat() {
if (isPAndAbove()) {
action = Intent.ACTION_DELETE
} else {
@Suppress("DEPRECATION")
action = Intent.ACTION_UNINSTALL_PACKAGE
putExtra(Intent.EXTRA_RETURN_RESULT, true)
}
}

View File

@@ -21,9 +21,12 @@
package com.aurora.store.data.installer package com.aurora.store.data.installer
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri
import com.aurora.extensions.isOAndAbove import com.aurora.extensions.isOAndAbove
import com.aurora.extensions.isPAndAbove
import com.aurora.store.BuildConfig import com.aurora.store.BuildConfig
import com.aurora.store.R import com.aurora.store.R
import com.aurora.store.util.PackageUtil import com.aurora.store.util.PackageUtil
@@ -91,6 +94,20 @@ open class AppInstaller private constructor(var context: Context) {
return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
} }
fun uninstall(context: Context, packageName: String) {
val intent = Intent().apply {
data = Uri.fromParts("package", packageName, null)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (isPAndAbove()) {
action = Intent.ACTION_DELETE
} else {
@Suppress("DEPRECATION")
action = Intent.ACTION_UNINSTALL_PACKAGE
putExtra(Intent.EXTRA_RETURN_RESULT, true)
}
}
context.startActivity(intent)
}
} }
val choiceAndInstaller = HashMap<Int, IInstaller>() val choiceAndInstaller = HashMap<Int, IInstaller>()

View File

@@ -21,8 +21,6 @@ package com.aurora.store.data.installer
interface IInstaller { interface IInstaller {
fun install(packageName: String, files: List<Any>) fun install(packageName: String, files: List<Any>)
fun uninstall(packageName: String)
fun clearQueue() fun clearQueue()
fun isAlreadyQueued(packageName: String): Boolean fun isAlreadyQueued(packageName: String): Boolean
fun removeFromInstallQueue(packageName: String) fun removeFromInstallQueue(packageName: String)

View File

@@ -20,10 +20,8 @@
package com.aurora.store.data.installer package com.aurora.store.data.installer
import android.content.Context import android.content.Context
import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import com.aurora.extensions.applyUninstallActionCompat
import com.aurora.store.AuroraApplication import com.aurora.store.AuroraApplication
import com.aurora.store.BuildConfig import com.aurora.store.BuildConfig
import com.aurora.store.data.event.InstallerEvent import com.aurora.store.data.event.InstallerEvent
@@ -45,17 +43,6 @@ abstract class InstallerBase(protected var context: Context) : IInstaller {
AuroraApplication.enqueuedInstalls.remove(packageName) AuroraApplication.enqueuedInstalls.remove(packageName)
} }
override fun uninstall(packageName: String) {
val uri = Uri.fromParts("package", packageName, null)
val intent = Intent().apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
applyUninstallActionCompat()
}
context.startActivity(intent)
}
open fun postError(packageName: String, error: String?, extra: String?) { open fun postError(packageName: String, error: String?, extra: String?) {
Log.e("Service Error :$error") Log.e("Service Error :$error")

View File

@@ -57,30 +57,6 @@ class RootInstaller(context: Context) : InstallerBase(context) {
} }
} }
override fun uninstall(packageName: String) {
if (Shell.getShell().isRoot) {
val result: Shell.Result =
Shell.cmd("pm uninstall --user 0 $packageName")
.exec()
val response = result.out
if (response[0] != "Success") {
postError(
packageName,
context.getString(R.string.installer_status_failure),
parseError(result)
)
}
} else {
postError(
packageName,
context.getString(R.string.installer_status_failure),
context.getString(R.string.installer_root_unavailable)
)
Log.e(" >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
}
}
private fun xInstall(packageName: String, files: List<File>) { private fun xInstall(packageName: String, files: List<File>) {
var totalSize = 0 var totalSize = 0

View File

@@ -98,85 +98,6 @@ class ServiceInstaller(context: Context) : InstallerBase(context) {
} }
} }
override fun uninstall(packageName: String) {
executor.execute {
val readyWithAction = AtomicBoolean(false)
Handler(Looper.getMainLooper()).post {
val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
if (isAlreadyQueued(packageName)) {
if (::serviceConnection.isInitialized) {
context.unbindService(serviceConnection)
}
readyWithAction.set(true)
return
}
AuroraApplication.enqueuedInstalls.add(packageName)
val service = IPrivilegedService.Stub.asInterface(binder)
if (service.hasPrivilegedPermissions()) {
Log.i(context.getString(R.string.installer_service_available))
val callback = object : IPrivilegedCallback.Stub() {
override fun handleResult(packageName: String, returnCode: Int) {}
override fun handleResultX(
packageName: String,
returnCode: Int,
extra: String?
) {
removeFromInstallQueue(packageName)
handleCallbackUninstall(packageName, returnCode, extra)
readyWithAction.set(true)
}
}
try {
service.deletePackageX(
packageName,
2,
BuildConfig.APPLICATION_ID,
callback
)
} catch (e: RemoteException) {
Log.e("Failed to connect Aurora Services")
removeFromInstallQueue(packageName)
readyWithAction.set(true)
}
} else {
removeFromInstallQueue(packageName)
postError(
packageName,
context.getString(R.string.installer_status_failure),
context.getString(R.string.installer_service_misconfigured)
)
readyWithAction.set(true)
}
}
override fun onServiceDisconnected(name: ComponentName) {
removeFromInstallQueue(packageName)
Log.e("Disconnected from Aurora Services")
readyWithAction.set(true)
}
}
val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT)
intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME)
context.bindService(
intent,
serviceConnection,
Context.BIND_AUTO_CREATE
)
}
while (!readyWithAction.get()) {
Thread.sleep(1000)
}
}
}
private fun xInstall(packageName: String, uriList: List<Uri>, fileList: List<String>) { private fun xInstall(packageName: String, uriList: List<Uri>, fileList: List<String>) {
executor.execute { executor.execute {
val readyWithAction = AtomicBoolean(false) val readyWithAction = AtomicBoolean(false)

View File

@@ -64,7 +64,6 @@ import com.aurora.store.data.ViewState
import com.aurora.store.data.event.BusEvent import com.aurora.store.data.event.BusEvent
import com.aurora.store.data.event.InstallerEvent import com.aurora.store.data.event.InstallerEvent
import com.aurora.store.data.installer.AppInstaller import com.aurora.store.data.installer.AppInstaller
import com.aurora.store.data.installer.RootInstaller
import com.aurora.store.data.model.DownloadStatus import com.aurora.store.data.model.DownloadStatus
import com.aurora.store.data.providers.AuthProvider import com.aurora.store.data.providers.AuthProvider
import com.aurora.store.databinding.FragmentDetailsBinding import com.aurora.store.databinding.FragmentDetailsBinding
@@ -89,7 +88,6 @@ import com.aurora.store.viewmodel.details.AppDetailsViewModel
import com.aurora.store.viewmodel.details.DetailsClusterViewModel import com.aurora.store.viewmodel.details.DetailsClusterViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
@@ -375,7 +373,7 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
} }
R.id.action_uninstall -> { R.id.action_uninstall -> {
uninstallApp() AppInstaller.uninstall(requireContext(), app.packageName)
} }
R.id.menu_download_manual -> { R.id.menu_download_manual -> {
@@ -440,27 +438,6 @@ class AppDetailsFragment : BaseFragment(R.layout.fragment_details) {
} }
} }
@Synchronized
private fun uninstallApp() {
val installer = AppInstaller.getInstance(requireContext()).getPreferredInstaller()
if (installer is RootInstaller) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(app.displayName)
.setMessage(requireContext().getString(R.string.action_uninstall_confirmation))
.setPositiveButton(requireContext().getString(android.R.string.ok)) { _, _ ->
installer.uninstall(app.packageName)
}
.setNegativeButton(requireContext().getString(android.R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
} else {
installer.uninstall(app.packageName)
}
}
private fun inflatePartialApp() { private fun inflatePartialApp() {
if (::app.isInitialized) { if (::app.isInitialized) {
attachHeader() attachHeader()

View File

@@ -115,8 +115,7 @@ class AppMenuSheet : BaseBottomSheet() {
} }
R.id.action_uninstall -> { R.id.action_uninstall -> {
AppInstaller.getInstance(requireContext()) AppInstaller.uninstall(requireContext(), args.app.packageName)
.getPreferredInstaller().uninstall(args.app.packageName)
} }
R.id.action_info -> { R.id.action_info -> {