mirror of
https://github.com/YTVanced/VancedManager
synced 2024-11-28 22:13:01 +00:00
implement nonroot uninstallation
This commit is contained in:
parent
19f8219c3c
commit
7141df8af8
7 changed files with 107 additions and 40 deletions
|
@ -41,9 +41,8 @@
|
|||
android:theme="@style/Theme.MaterialComponents.NoActionBar"
|
||||
android:label="@string/app_name"/>
|
||||
|
||||
<service android:name="com.xinto.apkhelper.services.PackageManagerService" />
|
||||
|
||||
<service android:name=".core.installer.service.AppInstallService" />
|
||||
<service android:name=".core.installer.service.AppUninstallService" />
|
||||
|
||||
</application>
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ class AppInstallService : Service() {
|
|||
flags: Int,
|
||||
startId: Int
|
||||
): Int {
|
||||
when (val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
|
||||
val extraStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)
|
||||
val extraStatusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
||||
when (extraStatus) {
|
||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||
startActivity(
|
||||
intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT).apply {
|
||||
|
@ -22,12 +24,9 @@ class AppInstallService : Service() {
|
|||
}
|
||||
else -> {
|
||||
sendBroadcast(Intent().apply {
|
||||
action = APP_INSTALL_STATUS
|
||||
putExtra(EXTRA_INSTALL_STATUS, status)
|
||||
putExtra(
|
||||
EXTRA_INSTALL_EXTRA,
|
||||
intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
||||
)
|
||||
action = APP_INSTALL_ACTION
|
||||
putExtra(EXTRA_INSTALL_STATUS, extraStatus)
|
||||
putExtra(EXTRA_INSTALL_EXTRA, extraStatusMessage)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +37,7 @@ class AppInstallService : Service() {
|
|||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
companion object {
|
||||
const val APP_INSTALL_STATUS = "APP_INSTALL_STATUS"
|
||||
const val APP_INSTALL_ACTION = "APP_INSTALL_ACTION"
|
||||
|
||||
const val EXTRA_INSTALL_STATUS = "EXTRA_INSTALL_STATUS"
|
||||
const val EXTRA_INSTALL_EXTRA = "EXTRA_INSTALL_EXTRA"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package com.vanced.manager.core.installer.service
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInstaller
|
||||
import android.os.IBinder
|
||||
|
||||
class AppUninstallService : Service() {
|
||||
|
||||
override fun onStartCommand(
|
||||
intent: Intent,
|
||||
flags: Int,
|
||||
startId: Int
|
||||
): Int {
|
||||
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
|
||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||
startActivity(
|
||||
intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT).apply {
|
||||
this?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
sendBroadcast(Intent().apply {
|
||||
action = APP_UNINSTALL_ACTION
|
||||
})
|
||||
}
|
||||
}
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
companion object {
|
||||
const val APP_UNINSTALL_ACTION = "APP_UNINSTALL_ACTION"
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import android.content.pm.PackageInstaller
|
|||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import com.vanced.manager.core.installer.service.AppInstallService
|
||||
import com.vanced.manager.core.installer.service.AppUninstallService
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
|
@ -17,7 +18,7 @@ fun installApp(apk: File, context: Context) {
|
|||
val session =
|
||||
packageInstaller.openSession(packageInstaller.createSession(sessionParams))
|
||||
writeApkToSession(apk, session)
|
||||
session.commit(getIntentSender(context))
|
||||
session.commit(context.installIntentSender)
|
||||
session.close()
|
||||
}
|
||||
|
||||
|
@ -28,10 +29,28 @@ fun installSplitApp(apks: Array<File>, context: Context) {
|
|||
for (apk in apks) {
|
||||
writeApkToSession(apk, session)
|
||||
}
|
||||
session.commit(getIntentSender(context))
|
||||
session.commit(context.installIntentSender)
|
||||
session.close()
|
||||
}
|
||||
|
||||
fun uninstallPackage(pkg: String, context: Context) {
|
||||
val packageInstaller = context.packageManager.packageInstaller
|
||||
packageInstaller.uninstall(pkg, context.uninstallIntentSender)
|
||||
}
|
||||
|
||||
private fun writeApkToSession(
|
||||
apk: File,
|
||||
session: PackageInstaller.Session
|
||||
) {
|
||||
val inputStream = FileInputStream(apk)
|
||||
val outputStream = session.openWrite(apk.name, 0, apk.length())
|
||||
inputStream.copyTo(outputStream, byteArraySize)
|
||||
session.fsync(outputStream)
|
||||
inputStream.close()
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
}
|
||||
|
||||
private val intentFlags
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
PendingIntent.FLAG_MUTABLE
|
||||
|
@ -47,27 +66,18 @@ private val sessionParams
|
|||
}
|
||||
}
|
||||
|
||||
private fun getIntentSender(context: Context) =
|
||||
PendingIntent.getService(
|
||||
context,
|
||||
private val Context.installIntentSender
|
||||
get() = PendingIntent.getService(
|
||||
this,
|
||||
0,
|
||||
Intent(context, AppInstallService::class.java),
|
||||
Intent(this, AppInstallService::class.java),
|
||||
intentFlags
|
||||
).intentSender
|
||||
|
||||
private fun writeApkToSession(
|
||||
apk: File,
|
||||
session: PackageInstaller.Session
|
||||
) {
|
||||
val inputStream = FileInputStream(apk)
|
||||
val outputStream = session.openWrite(apk.name, 0, apk.length())
|
||||
val buffer = ByteArray(byteArraySize)
|
||||
var length: Int
|
||||
while (inputStream.read(buffer).also { length = it } > 0) {
|
||||
outputStream.write(buffer, 0, length)
|
||||
}
|
||||
session.fsync(outputStream)
|
||||
inputStream.close()
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
}
|
||||
private val Context.uninstallIntentSender
|
||||
get() = PendingIntent.getService(
|
||||
this,
|
||||
0,
|
||||
Intent(this, AppUninstallService::class.java),
|
||||
intentFlags
|
||||
).intentSender
|
|
@ -17,6 +17,7 @@ import com.github.zsoltk.compose.backpress.LocalBackPressHandler
|
|||
import com.github.zsoltk.compose.router.Router
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.vanced.manager.core.installer.service.AppInstallService
|
||||
import com.vanced.manager.core.installer.service.AppUninstallService
|
||||
import com.vanced.manager.ui.component.color.managerSurfaceColor
|
||||
import com.vanced.manager.ui.screens.*
|
||||
import com.vanced.manager.ui.theme.ManagerTheme
|
||||
|
@ -36,12 +37,18 @@ class MainActivity : ComponentActivity() {
|
|||
private val installBroadcastReceiver = object : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action != AppInstallService.APP_INSTALL_STATUS) return
|
||||
|
||||
installViewModel.postInstallStatus(
|
||||
pmStatus = intent.getIntExtra(AppInstallService.EXTRA_INSTALL_STATUS, -999),
|
||||
extra = intent.getStringExtra(AppInstallService.EXTRA_INSTALL_EXTRA)!!,
|
||||
)
|
||||
when (intent?.action) {
|
||||
AppInstallService.APP_INSTALL_ACTION -> {
|
||||
installViewModel.postInstallStatus(
|
||||
pmStatus = intent.getIntExtra(AppInstallService.EXTRA_INSTALL_STATUS, -999),
|
||||
extra = intent.getStringExtra(AppInstallService.EXTRA_INSTALL_EXTRA)!!,
|
||||
)
|
||||
mainViewModel.fetch()
|
||||
}
|
||||
AppUninstallService.APP_UNINSTALL_ACTION -> {
|
||||
mainViewModel.fetch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,7 +158,8 @@ class MainActivity : ComponentActivity() {
|
|||
registerReceiver(
|
||||
installBroadcastReceiver,
|
||||
IntentFilter().apply {
|
||||
addAction(AppInstallService.APP_INSTALL_STATUS)
|
||||
addAction(AppInstallService.APP_INSTALL_ACTION)
|
||||
addAction(AppUninstallService.APP_UNINSTALL_ACTION)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -136,7 +136,11 @@ fun HomeLayout(
|
|||
app.installationOptions
|
||||
)
|
||||
},
|
||||
onAppUninstallClick = { /*TODO*/ },
|
||||
onAppUninstallClick = {
|
||||
viewModel.uninstallApp(
|
||||
appPackage = app.packageName
|
||||
)
|
||||
},
|
||||
onAppLaunchClick = {
|
||||
viewModel.launchApp(
|
||||
appName = app.name,
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vanced.manager.core.installer.util.uninstallPackage
|
||||
import com.vanced.manager.core.preferences.holder.managerVariantPref
|
||||
import com.vanced.manager.core.preferences.holder.musicEnabled
|
||||
import com.vanced.manager.core.preferences.holder.vancedEnabled
|
||||
|
@ -96,6 +97,13 @@ class MainViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
//TODO implement root uninstallation
|
||||
fun uninstallApp(
|
||||
appPackage: String,
|
||||
) {
|
||||
uninstallPackage(appPackage, app)
|
||||
}
|
||||
|
||||
init {
|
||||
fetch()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue