started code cleanup

This commit is contained in:
X1nto 2020-09-06 14:33:04 +04:00
parent 5681b6fb4f
commit 160a5684f7
30 changed files with 809 additions and 1024 deletions

View File

@ -71,14 +71,8 @@
android:resource="@drawable/ic_stat_name" />
<service android:name=".core.installer.SplitInstallerService" />
<service android:name=".core.installer.RootSplitInstallerService" />
<service android:name=".core.installer.SplitInstaller" />
<service android:name=".core.installer.AppUninstallerService" />
<service android:name=".core.installer.AppInstallerService" />
<service android:name=".core.installer.AppInstaller" />
<service android:name=".core.downloader.VancedDownloadService" />
<service android:name=".core.downloader.MicrogDownloadService" />
<service android:name=".core.downloader.MusicDownloadService" />
</application>

View File

@ -1,8 +1,6 @@
package com.vanced.manager.core
import android.app.Application
import android.util.Log
import android.os.Build
import com.crowdin.platform.Crowdin
import com.crowdin.platform.CrowdinConfig
import com.crowdin.platform.data.remote.NetworkType

View File

@ -1,86 +0,0 @@
package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
import com.vanced.manager.R
import com.vanced.manager.core.installer.AppInstaller
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getJsonString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MicrogDownloadService: Service() {
//private var downloadId: Long = 0
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
downloadMicrog()
stopSelf()
return START_NOT_STICKY
}
private fun downloadMicrog() {
CoroutineScope(Dispatchers.IO).launch {
val url = getJsonString("microg.json", "url", this@MicrogDownloadService)
//downloadId = download(url, "apk", "microg.apk", this@MicrogDownloadService)
PRDownloader.download(url, getExternalFilesDir("apk")?.path, "microg.apk")
.build()
.setOnStartOrResumeListener { installing = true }
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MICROG_DOWNLOADING).putExtra("progress", mProgress.toInt()).putExtra("file", getFileNameFromUrl(url)))
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
val intent = Intent(this@MicrogDownloadService, AppInstaller::class.java)
intent.putExtra("path", "${getExternalFilesDir("apk")}/microg.apk")
intent.putExtra("pkg", "com.mgoogle.android.gms")
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MICROG_INSTALLING))
startService(intent)
}
override fun onError(error: Error?) {
installing = false
Toast.makeText(this@MicrogDownloadService, getString(R.string.error_downloading, "microG"), Toast.LENGTH_SHORT).show()
}
})
}
}
/*
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadId) {
//prefs?.edit()?.putBoolean("isMicrogDownloading", false)?.apply()
//cancelNotif(channel, this@MicrogDownloadService)
val bIntent = Intent(this@MicrogDownloadService, AppInstaller::class.java)
bIntent.putExtra("path", "${getExternalFilesDir("apk")}/microg.apk")
bIntent.putExtra("pkg", "com.mgoogle.android.gms")
startService(bIntent)
}
}
}
*/
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -0,0 +1,71 @@
package com.vanced.manager.core.downloader
import android.content.Context
import android.widget.Toast
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
import com.vanced.manager.R
import com.vanced.manager.core.installer.AppInstaller
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.microgProgress
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getJsonString
import com.vanced.manager.utils.PackageHelper.install
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
object MicrogDownloader {
//private var downloadId: Long = 0
fun downloadMicrog(context: Context) {
CoroutineScope(Dispatchers.IO).launch {
val url = getJsonString("microg.json", "url", context)
//downloadId = download(url, "apk", "microg.apk", this@MicrogDownloadService)
PRDownloader.download(url, context.getExternalFilesDir("apk")?.path, "microg.apk")
.build()
.setOnStartOrResumeListener {
installing = true
microgProgress.get()?.setDownloadingFile(getFileNameFromUrl(url))
microgProgress.get()?.showDownloadBar = true
}
.setOnProgressListener { progress ->
microgProgress.get()?.setDownloadProgress(progress.currentBytes * 100 / progress.totalBytes)
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
install("microg", "${context.getExternalFilesDir("apk")}/microg.apk", context)
microgProgress.showDownloadBar = false
microgProgress.showInstallCircle = true
}
override fun onError(error: Error?) {
installing = false
Toast.makeText(context, getString(R.string.error_downloading, "microG"), Toast.LENGTH_SHORT).show()
}
})
}
}
/*
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadId) {
//prefs?.edit()?.putBoolean("isMicrogDownloading", false)?.apply()
//cancelNotif(channel, this@MicrogDownloadService)
val bIntent = Intent(this@MicrogDownloadService, AppInstaller::class.java)
bIntent.putExtra("path", "${getExternalFilesDir("apk")}/microg.apk")
bIntent.putExtra("pkg", "com.mgoogle.android.gms")
startService(bIntent)
}
}
}
*/
}

View File

@ -1,63 +1,53 @@
package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
import com.vanced.manager.R
import com.vanced.manager.core.installer.AppInstaller
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.musicProgress
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getJsonString
import com.vanced.manager.utils.PackageHelper.install
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MusicDownloadService: Service() {
object MusicDownloader {
//private var downloadId: Long = 0
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
downloadMusic()
stopSelf()
return START_NOT_STICKY
}
private fun downloadMusic() {
fun downloadMusic(context: Context) {
CoroutineScope(Dispatchers.IO).launch {
val version = getJsonString("music.json", "version", this@MusicDownloadService)
val version = getJsonString("music.json", "version", context)
val url = "https://vanced.app/api/v1/music/v$version.apk"
//downloadId = download(url, "apk", "music.apk", this@MusicDownloadService)
PRDownloader.download(url, getExternalFilesDir("apk")?.path, "music.apk")
.build()
.setOnStartOrResumeListener { installing = true }
.setOnStartOrResumeListener {
installing = true
musicProgress.get()?.setDownloadingFile(getFileNameFromUrl(url))
musicProgress.get()?.showDownloadBar = true
}
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MUSIC_DOWNLOADING).putExtra("progress", mProgress.toInt()).putExtra("file", getFileNameFromUrl(url)))
musicProgress.get()?.setDownloadProgress(progress.currentBytes * 100 / progress.totalBytes)
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
val intent = Intent(this@MusicDownloadService, AppInstaller::class.java)
intent.putExtra("path", "${getExternalFilesDir("apk")}/music.apk")
intent.putExtra("pkg", "com.vanced.android.apps.youtube.music")
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MUSIC_INSTALLING))
startService(intent)
install("music", "${context.getExternalFilesDir("apk")}/music.apk", context)
musicProgress.get().showDownloadBar = false
musicProgress.get().showInstallCircle = true
}
override fun onError(error: Error?) {
installing = false
Toast.makeText(this@MusicDownloadService, getString(R.string.error_downloading, "music"), Toast.LENGTH_SHORT).show()
Toast.makeText(context, getString(R.string.error_downloading, "Music"), Toast.LENGTH_SHORT).show()
}
})

View File

@ -1,13 +1,11 @@
package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Build
import android.os.IBinder
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.downloader.Error
import com.downloader.OnDownloadListener
@ -15,13 +13,15 @@ import com.downloader.PRDownloader
import com.vanced.manager.R
import com.vanced.manager.core.installer.RootSplitInstallerService
import com.vanced.manager.core.installer.SplitInstaller
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.vancedProgress
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.InternetTools
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getObjectFromJson
import com.vanced.manager.utils.PackageHelper.getPkgVerCode
import com.vanced.manager.utils.PackageHelper.installVanced
import com.vanced.manager.utils.PackageHelper.installvancedRoot
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -30,7 +30,7 @@ import java.io.File
import java.io.IOException
import java.security.MessageDigest
class VancedDownloadService: Service() {
object VancedDownloader {
private var sha256Val: String? = null
@ -48,16 +48,15 @@ class VancedDownloadService: Service() {
//private var downloadId: Long = 0
//private var apkType: String = "arch"
private var count: Int = 0
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
private var hashUrl = ""
private val yPkg = "com.google.android.youtube"
private val vancedVersionCode by lazy {runBlocking { InternetTools.getJsonInt("vanced.json", "versionCode", applicationContext) }}
private val vancedVersion by lazy { runBlocking { getObjectFromJson("$installUrl/vanced.json", "version") }}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
fun downloadVanced(context: Context) {
//registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
File(getExternalFilesDir("apks")?.path as String).deleteRecursively()
File(context.getExternalFilesDir("apks")?.path as String).deleteRecursively()
defPrefs = PreferenceManager.getDefaultSharedPreferences(this)
installUrl = defPrefs.getString("install_url", baseUrl)
prefs = getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
@ -73,12 +72,11 @@ class VancedDownloadService: Service() {
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a"
else -> "armeabi_v7a"
}
downloadSplits()
stopSelf()
return START_NOT_STICKY
downloadSplits(context)
}
private fun downloadSplits(
private fun downloadSplits(context,
context: Context,
type: String = "theme"
) {
CoroutineScope(Dispatchers.IO).launch {
@ -95,54 +93,57 @@ class VancedDownloadService: Service() {
//apkType = type
//downloadId = download(url, "apks", getFileNameFromUrl(url), this@VancedDownloadService)
PRDownloader
.download(url, getExternalFilesDir("apks")?.path, getFileNameFromUrl(url))
.build()
.setOnStartOrResumeListener { installing = true }
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
localBroadcastManager.sendBroadcast(Intent(HomeFragment.VANCED_DOWNLOADING).putExtra("progress", mProgress.toInt()).putExtra("file", getFileNameFromUrl(url)))
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
when (type) {
"theme" ->
if (variant == "root" && newInstaller == true) {
if (ValidateTheme()) {
if(downloadStockCheck())
downloadSplits("arch")
else
prepareInstall(variant!!)
PRDownloader
.download(url, getExternalFilesDir("apks")?.path, getFileNameFromUrl(url))
.build()
.setOnStartOrResumeListener {
installing = true
vancedProgress.get()?.setDownloadingFile(getFileNameFromUrl(url))
vancedProgress.get()?.showDownloadBar = true
}
.setOnProgressListener { progress ->
vancedProgress.get()?.setDownloadProgress(progress.currentBytes * 100 / progress.totalBytes)
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
when (type) {
"theme" ->
if (variant == "root" && newInstaller == true) {
if (ValidateTheme()) {
if(downloadStockCheck())
downloadSplits(context, "arch")
else
prepareInstall(variant!!)
} else
downloadSplits(context, "theme")
} else
downloadSplits("theme")
} else
downloadSplits("arch")
"arch" -> if (variant == "root" && newInstaller == true) downloadSplits("stock") else downloadSplits("lang")
"stock" -> downloadSplits("dpi")
"dpi" -> downloadSplits("lang")
"lang" -> {
downloadSplits(context, "arch")
"arch" -> if (variant == "root" && newInstaller == true) downloadSplits(context, "stock") else downloadSplits(context, "lang")
"stock" -> downloadSplits(context, "dpi")
"dpi" -> downloadSplits(context, "lang")
"lang" -> {
count++
if (count < lang?.count()!!)
downloadSplits(context, "lang")
else
prepareInstall(variant!!)
}
}
}
override fun onError(error: Error?) {
if (type == "lang") {
count++
if (count < lang?.count()!!)
downloadSplits("lang")
downloadSplits(context, "lang")
else
prepareInstall(variant!!)
} else {
installing = false
Toast.makeText(context, getString(R.string.error_downloading, "Vanced"), Toast.LENGTH_SHORT).show()
}
}
}
override fun onError(error: Error?) {
if (type == "lang") {
count++
if (count < lang?.count()!!)
downloadSplits("lang")
else
prepareInstall(variant!!)
} else {
installing = false
Toast.makeText(this@VancedDownloadService, getString(R.string.error_downloading, "Vanced"), Toast.LENGTH_SHORT).show()
}
}
})
})
}
}
@ -176,14 +177,14 @@ class VancedDownloadService: Service() {
val lang = prefs?.getString("lang", "en")
if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadId) {
when (apkType) {
"arch" -> downloadSplits("theme")
"theme" -> downloadSplits("lang")
"arch" -> downloadSplits(context, "theme")
"theme" -> downloadSplits(context, "lang")
"lang" -> {
if (lang == "en") {
prepareInstall(variant!!)
//cancelNotif(channel, this@VancedDownloadService)
} else {
downloadSplits("enlang")
downloadSplits(context, "enlang")
}
}
"enlang" -> {
@ -196,12 +197,13 @@ class VancedDownloadService: Service() {
}
*/
private fun prepareInstall(variant: String) {
localBroadcastManager.sendBroadcast(Intent(HomeFragment.VANCED_INSTALLING))
private fun prepareInstall(variant: String, context: Context) {
vancedProgress.get()?.showDownloadBar = false
vancedProgress.get()?.showInstallCircle = true
if (variant == "root")
startService(Intent(this, RootSplitInstallerService::class.java))
installVancedRoot(context)
else
startService(Intent(this, SplitInstaller::class.java))
installvanced(context)
}
override fun onBind(intent: Intent?): IBinder? {

View File

@ -1,40 +0,0 @@
package com.vanced.manager.core.installer
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import java.io.FileInputStream
import java.io.InputStream
class AppInstaller: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val app = if (intent?.getStringExtra("pkg")?.contains("mgoogle") == true) "microg" else "music"
val callbackIntent = Intent(applicationContext, AppInstallerService::class.java).putExtra("app", app)
val pendingIntent = PendingIntent.getService(applicationContext, 0, callbackIntent, 0)
val packageInstaller = packageManager.packageInstaller
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
params.setAppPackageName(intent?.getStringExtra("pkg"))
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
val inputStream: InputStream = FileInputStream(intent?.getStringExtra("path") as String)
val outputStream = session.openWrite("install", 0, -1)
val buffer = ByteArray(65536)
var c: Int
while (inputStream.read(buffer).also { c = it } != -1) {
outputStream.write(buffer, 0, c)
}
session.fsync(outputStream)
inputStream.close()
outputStream.close()
session.commit(pendingIntent.intentSender)
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -5,9 +5,8 @@ import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.utils.AppUtils.sendFailure
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.microgProgress
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.musicProgress
class AppInstallerService: Service() {
@ -17,7 +16,6 @@ class AppInstallerService: Service() {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d(TAG, "Requesting user confirmation for installation")
localBroadcastManager.sendBroadcast(Intent(if (intent.getStringExtra("app") == "microg") HomeFragment.MICROG_INSTALLING else HomeFragment.MUSIC_INSTALLING))
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
@ -28,10 +26,7 @@ class AppInstallerService: Service() {
}
PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed")
with(localBroadcastManager) {
sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
sendBroadcast(Intent(if (intent.getStringExtra("app") == "microg") HomeFragment.MICROG_INSTALLING else HomeFragment.MUSIC_INSTALLING))
}
if (intent?.getStringExtra("app") == "microg") microgProgress.showInstallCircle = false else musicProgress.showInstallCircle = false
}
else -> sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999), this)
}

View File

@ -5,14 +5,14 @@ import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.ui.fragments.HomeFragment
import kotlinx.coroutines.*
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.fetchData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class AppUninstallerService: Service() {
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val pkgName = intent?.getStringExtra("pkg")
when (intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
@ -25,18 +25,18 @@ class AppUninstallerService: Service() {
} catch (e: Exception) {
}
}
//Delay broadcast until activity (and fragment) show up on screen
//Delay broadcast until activity (and fragment) show up on the screen
PackageInstaller.STATUS_SUCCESS -> {
CoroutineScope(Dispatchers.IO).launch {
delay(500)
localBroadcastManager.sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
fetchData()
Log.d("VMpm", "Successfully uninstalled $pkgName")
}
}
PackageInstaller.STATUS_FAILURE -> {
CoroutineScope(Dispatchers.IO).launch {
delay(500)
localBroadcastManager.sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
fetchData()
Log.d("VMpm", "Failed to uninstall $pkgName")
}
}
@ -49,4 +49,4 @@ class AppUninstallerService: Service() {
return null
}
}
}

View File

@ -1,402 +0,0 @@
package com.vanced.manager.core.installer
import android.app.Service
import android.content.Intent
import android.content.pm.PackageInfo
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.annotation.Nullable
import androidx.annotation.WorkerThread
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile
import com.vanced.manager.BuildConfig
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.utils.AppUtils.sendFailure
import com.vanced.manager.utils.FileInfo
import com.vanced.manager.utils.InternetTools.getJsonInt
import com.vanced.manager.utils.PackageHelper
import com.vanced.manager.utils.PackageHelper.getPkgVerCode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList
class RootSplitInstallerService: Service() {
private val vancedVersionCode by lazy{ runBlocking { getJsonInt("vanced.json","versionCode", applicationContext) }}
private val yPkg = "com.google.android.youtube"
private val apkInstallPath = "/data/adb/Vanced/"
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Shell.enableVerboseLogging = BuildConfig.DEBUG
Shell.setDefaultBuilder(
Shell.Builder.create()
.setFlags(Shell.FLAG_REDIRECT_STDERR)
.setTimeout(10)
)
Shell.getShell {
CoroutineScope(Dispatchers.IO).launch {
val apkFilesPath = getExternalFilesDir("apks")?.path
val fileInfoList = apkFilesPath?.let { it1 -> getFileInfoList(it1) }
if (fileInfoList != null) {
var modApk: FileInfo? = null
for (file in fileInfoList) {
if (file.name == "dark.apk" || file.name == "black.apk") {
modApk = file
}
}
if (modApk != null) {
if (getDefaultSharedPreferences(this@RootSplitInstallerService).getBoolean("new_installer", false)) {
if (overwriteBase(modApk, fileInfoList, vancedVersionCode)) {
with(localBroadcastManager) {
sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
sendBroadcast(Intent(HomeFragment.VANCED_INSTALLED))
}
}
} else
installSplitApkFiles(fileInfoList)
}
else
{
sendFailure(listOf("ModApk_Missing").toMutableList(), applicationContext)
}
//installSplitApkFiles(fileInfoList)
}
else
{
sendFailure(listOf("Files_Missing_VA").toMutableList(), applicationContext)
}
}
}
stopSelf()
return START_NOT_STICKY
}
@WorkerThread
private fun installSplitApkFiles(apkFiles: ArrayList<FileInfo>) : Boolean {
var sessionId: Int?
Log.d("AppLog", "installing split apk files:$apkFiles")
run {
val sessionIdResult = Shell.su("pm install-create -r -t").exec().out
val sessionIdPattern = Pattern.compile("(\\d+)")
val sessionIdMatcher = sessionIdPattern.matcher(sessionIdResult[0])
sessionIdMatcher.find()
sessionId = Integer.parseInt(sessionIdMatcher.group(1)!!)
}
apkFiles.forEach { apkFile ->
if(apkFile.name != "black.apk" && apkFile.name != "dark.apk" && apkFile.name != "hash.json")
{
Log.d("AppLog", "installing APK : ${apkFile.name} ${apkFile.fileSize} ")
val command = arrayOf("su", "-c", "pm", "install-write", "-S", "${apkFile.fileSize}", "$sessionId", apkFile.name)
val process: Process = Runtime.getRuntime().exec(command)
val inputPipe = apkFile.getInputStream()
try {
process.outputStream.use { outputStream -> inputPipe.copyTo(outputStream) }
} catch (e: Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
process.destroyForcibly()
else
process.destroy()
throw RuntimeException(e)
}
process.waitFor()
}
}
Log.d("AppLog", "committing...")
val installResult = Shell.su("pm install-commit $sessionId").exec()
if (installResult.isSuccess) {
return true
} else
sendFailure(installResult.out, this)
return false
}
private fun SimpleDateFormat.tryParse(str: String) = try {
parse(str) != null
} catch (e: Exception) {
false
}
@WorkerThread
private fun getFileInfoList(splitApkPath: String): ArrayList<FileInfo> {
val parentFile = File(splitApkPath)
val result = ArrayList<FileInfo>()
if (parentFile.exists() && parentFile.canRead()) {
val listFiles = parentFile.listFiles() ?: return ArrayList()
for (file in listFiles)
result.add(FileInfo(file.name, file.length(), file))
return result
}
val longLines = Shell.su("ls -l $splitApkPath").exec().out
val pattern = Pattern.compile(" +")
val formatter = SimpleDateFormat("HH:mm", Locale.getDefault())
longLinesLoop@ for (line in longLines) {
val matcher = pattern.matcher(line)
for (i in 0 until 4)
if (!matcher.find())
continue@longLinesLoop
val startSizeStr = matcher.end()
matcher.find()
val endSizeStr = matcher.start()
val fileSizeStr = line.substring(startSizeStr, endSizeStr)
while (true) {
val testTimeStr: String =
line.substring(matcher.end(), line.indexOf(' ', matcher.end()))
if (formatter.tryParse(testTimeStr)) {
//found time, so apk is next
val fileName = line.substring(line.indexOf(' ', matcher.end()) + 1)
if (fileName.endsWith("apk"))
result.add(FileInfo(fileName, fileSizeStr.toLong(), File(splitApkPath, fileName)))
break
}
matcher.find()
}
}
return result
}
@Nullable
override fun onBind(intent: Intent?): IBinder? {
return null
}
//install Vanced
private fun overwriteBase(apkFile: FileInfo,baseApkFiles: ArrayList<FileInfo>, versionCode: Int): Boolean {
if (checkVersion(versionCode,baseApkFiles)) {
val path = getPackageDir()
apkFile.file?.let {
val apath = it.absolutePath
setupFolder(apkInstallPath)
if(path != null)
{
val apkFPath = apkInstallPath + "base.apk"
if(moveAPK(apath, apkFPath))
{
if(chConV(apkFPath))
{
if(setupScript(apkFPath,path))
{
return linkVanced(apkFPath,path)
}
}
}
}
}
}
return false
}
private fun setupScript(apkFPath: String, path: String): Boolean
{
if(Shell.su("""echo "#!/system/bin/sh\nsleep 1m\nmount -o bind $apkFPath $path" > /data/adb/service.d/vanced.sh""").exec().isSuccess)
{
return Shell.su("chmod 744 /data/adb/service.d/vanced.sh").exec().isSuccess
}
return false
}
private fun linkVanced(apkFPath: String, path: String): Boolean
{
Shell.su("am force-stop $yPkg").exec()
Thread.sleep(500)
val response = Shell.su("""su -mm -c "mount -o bind $apkFPath $path"""").exec()
return response.isSuccess
}
private fun setupFolder(apkInstallPath: String): Boolean {
return Shell.su("mkdir -p $apkInstallPath").exec().isSuccess
}
//check version and perform action based on result
private fun checkVersion(versionCode: Int, baseApkFiles: ArrayList<FileInfo>): Boolean {
val path = getPackageDir()
if (path != null) {
if(path.contains("/data/app/"))
{
when(getVersionNumber()?.let { compareVersion(it,versionCode) })
{
1 -> {return fixHigherVer(baseApkFiles) }
-1 -> {return fixLowerVer(baseApkFiles) }
}
return true
}
else
{
return fixNoInstall(baseApkFiles)
}
}
return fixNoInstall(baseApkFiles)
}
private fun getPkgInfo(pkg: String): PackageInfo? {
return try {
packageManager.getPackageInfo(pkg, 0)
} catch (e:Exception) {
Log.d("VMpm", "Unable to get package info")
null
}
}
private fun compareVersion(pkgVerCode: Int, versionCode: Int): Int {
return when {
pkgVerCode > versionCode -> 1
pkgVerCode < versionCode -> -1
else -> 0
}
}
//uninstall current update and install base that works with patch
private fun fixHigherVer(apkFiles: ArrayList<FileInfo>) : Boolean {
if(PackageHelper.uninstallApk(yPkg, applicationContext)) {
return installSplitApkFiles(apkFiles)
}
sendFailure(listOf("Failed_Uninstall").toMutableList(), this)
return false
}
//install newer stock youtube
private fun fixLowerVer(apkFiles: ArrayList<FileInfo>): Boolean {
return installSplitApkFiles(apkFiles)
}
//install stock youtube since no install was found
private fun fixNoInstall(baseApkFiles: ArrayList<FileInfo>): Boolean {
return installSplitApkFiles(baseApkFiles)
}
//set chcon to apk_data_file
private fun chConV(path: String): Boolean {
val response = Shell.su("chcon u:object_r:apk_data_file:s0 $path").exec()
//val response = Shell.su("chcon -R u:object_r:system_file:s0 $path").exec()
return if (response.isSuccess) {
true
} else {
sendFailure(response.out, applicationContext)
false
}
}
//move patch to data/app
private fun moveAPK(apkFile: String, path: String) : Boolean {
val apkinF = SuFile.open(apkFile)
val apkoutF = SuFile.open(path)
if(apkinF.exists()) {
try {
Shell.su("am force-stop $yPkg").exec()
//Shell.su("rm -r SuFile.open(path).parent")
copy(apkinF,apkoutF)
Shell.su("chmod 644 $path").exec().isSuccess
return if(Shell.su("chown system:system $path").exec().isSuccess) {
true
} else {
sendFailure(listOf("Chown_Fail").toMutableList(), applicationContext)
false
}
}
catch (e: IOException)
{
sendFailure(listOf("${e.message}").toMutableList(), applicationContext)
return false
}
}
else {
sendFailure(listOf("IFile_Missing").toMutableList(), applicationContext)
return false
}
}
@Throws(IOException::class)
fun copy(src: File?, dst: File?) {
val cmd = Shell.su("mv ${src!!.absolutePath} ${dst!!.absolutePath}").exec().isSuccess
Log.d("ZLog", cmd.toString())
}
//get path of the installed youtube
private fun getVPath(): String? {
return try {
val p = getPkgInfo(yPkg)
p?.applicationInfo?.sourceDir
} catch (e: Exception) {
null
}
}
private fun getVersionNumber(): Int?
{
try {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
packageManager.getPackageInfo(yPkg, 0)?.longVersionCode?.and(0xFFFFFFFF)?.toInt()
else
packageManager.getPackageInfo(yPkg, 0)?.versionCode
}
catch (e : Exception)
{
val execRes = Shell.su("dumpsys package com.google.android.youtube | grep versionCode").exec()
if(execRes.isSuccess)
{
val result = execRes.out
var version: Int = 0
for(line in result)
{
val versionCode = line.substringAfter("=")
val versionCodeFiltered = versionCode.substringBefore(" ")
if(version < Integer.valueOf(versionCodeFiltered))
{
version = Integer.valueOf(versionCodeFiltered)
}
}
return version
}
}
return null
}
private fun getPackageDir(): String?
{
return try {
val p = getPkgInfo(yPkg)
p?.applicationInfo?.sourceDir
} catch (e: Exception) {
val execRes = Shell.su("dumpsys package com.google.android.youtube | grep codePath").exec()
if(execRes.isSuccess)
{
val result = execRes.out
for (line in result)
{
if(line.contains("data/app")) "${line.substringAfter("=")}/base.apk"
}
}
null
}
}
}

View File

@ -1,124 +0,0 @@
package com.vanced.manager.core.installer
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import java.io.*
class SplitInstaller: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
installSplitApk(this)
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private fun installSplitApk(context: Context): Int {
val apkFolderPath = context.getExternalFilesDir("apks")?.path + "/"
val nameSizeMap = HashMap<String, Long>()
var totalSize: Long = 0
var sessionId = 0
val folder = File(apkFolderPath)
val listOfFiles = folder.listFiles()
try {
for (listOfFile in listOfFiles!!) {
if (listOfFile.isFile) {
Log.d("AppLog", "installApk: " + listOfFile.name)
nameSizeMap[listOfFile.name] = listOfFile.length()
totalSize += listOfFile.length()
}
}
} catch (e: Exception) {
e.printStackTrace()
return -1
}
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
installParams.setSize(totalSize)
try {
sessionId = context.packageManager.packageInstaller.createSession(installParams)
Log.d("AppLog","Success: created install session [$sessionId]")
for ((key, value) in nameSizeMap) {
doWriteSession(sessionId, apkFolderPath + key, value, key, context)
}
doCommitSession(sessionId, context)
Log.d("AppLog","Success")
} catch (e: IOException) {
e.printStackTrace()
}
return sessionId
}
private fun doWriteSession(sessionId: Int, inPath: String?, sizeBytes: Long, splitName: String, context: Context): Int {
var inPathToUse = inPath
var sizeBytesToUse = sizeBytes
if ("-" == inPathToUse) {
inPathToUse = null
} else if (inPathToUse != null) {
val file = File(inPathToUse)
if (file.isFile)
sizeBytesToUse = file.length()
}
var session: PackageInstaller.Session? = null
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
if (inPathToUse != null) {
inputStream = FileInputStream(inPathToUse)
}
out = session.openWrite(splitName, 0, sizeBytesToUse)
var total = 0
val buffer = ByteArray(65536)
var c: Int
while (true) {
c = inputStream!!.read(buffer)
if (c == -1)
break
total += c
out.write(buffer, 0, c)
}
session.fsync(out)
Log.d("AppLog", "Success: streamed $total bytes")
return PackageInstaller.STATUS_SUCCESS
} catch (e: IOException) {
Log.e("AppLog", "Error: failed to write; " + e.message)
return PackageInstaller.STATUS_FAILURE
} finally {
try {
out?.close()
inputStream?.close()
session?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
private fun doCommitSession(sessionId: Int, context: Context) {
var session: PackageInstaller.Session? = null
try {
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
val callbackIntent = Intent(context.applicationContext, SplitInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context.applicationContext, 0, callbackIntent, 0)
session.commit(pendingIntent.intentSender)
session.close()
Log.d("AppLog", "install request sent")
Log.d("AppLog", "doCommitSession: " + context.packageManager.packageInstaller.mySessions)
Log.d("AppLog", "doCommitSession: after session commit ")
} catch (e: IOException) {
e.printStackTrace()
}
} finally {
session!!.close()
}
}
}

View File

@ -5,18 +5,15 @@ import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.IBinder
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.vancedProgress
import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.fetchData
import com.vanced.manager.utils.AppUtils.sendFailure
class SplitInstallerService: Service() {
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
localBroadcastManager.sendBroadcast(Intent(HomeFragment.VANCED_INSTALLING))
Log.d(TAG, "Requesting user confirmation for installation")
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@ -27,10 +24,8 @@ class SplitInstallerService: Service() {
}
PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed")
with(localBroadcastManager) {
sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
sendBroadcast(Intent(HomeFragment.VANCED_INSTALLED))
}
vancedProgress.showInstallCircle = false
fetchData()
}
else -> sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999), this)
@ -47,4 +42,4 @@ class SplitInstallerService: Service() {
const val TAG = "VMInstall"
}
}
}

View File

@ -3,20 +3,14 @@ package com.vanced.manager.model
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.vanced.manager.R
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getJsonInt
import com.vanced.manager.utils.InternetTools.getJsonString
import com.vanced.manager.utils.InternetTools.getObjectFromJson
import com.vanced.manager.utils.PackageHelper.isPackageInstalled
import com.vanced.manager.R
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.runBlocking
open class DataModel(
private val jsonName: String,

View File

@ -0,0 +1,27 @@
package com.vanced.manager.model
open class ProgressModel {
private var downloadProgres = 0
private var downloadingFile = ""
var showInstallCircle = false
var showDownloadBar = false
open fun getDownloadProgress(): Int {
return downloadProgress
}
open fun setDownloadProgress(progresss: Int) {
downloadProgress = progress
}
open fun getDownloadingFile(): String {
return downloadProgress
}
open fun setDownloadingFile(file: String) {
downloadingFile = file
}
}

View File

@ -4,17 +4,16 @@ import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.crowdin.platform.LoadingStateListener
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.tabs.TabLayout
import com.vanced.manager.adapter.SectionVariantAdapter
import com.google.android.material.tabs.TabLayoutMediator
import com.google.firebase.messaging.FirebaseMessaging
import com.vanced.manager.R
import com.vanced.manager.adapter.SectionVariantAdapter
import com.vanced.manager.databinding.ActivityMainBinding
import com.vanced.manager.ui.dialogs.DialogContainer
import com.vanced.manager.ui.fragments.UpdateCheckFragment

View File

@ -121,20 +121,21 @@ object DialogContainer {
}
}
fun launchVanced(activity: Activity) {
fun launchVanced(context: Context) {
val intent = Intent()
intent.component =
if (PreferenceManager.getDefaultSharedPreferences(activity).getString("vanced_variant", "nonroot") == "root")
if (PreferenceManager.getDefaultSharedPreferences(context).getString("vanced_variant", "nonroot") == "root")
ComponentName("com.google.android.youtube", "com.google.android.youtube.HomeActivity")
else
ComponentName("com.vanced.android.youtube", "com.google.android.youtube.HomeActivity")
MaterialAlertDialogBuilder(activity).apply {
setTitle(activity.getString(R.string.success))
setMessage(activity.getString(R.string.vanced_installed))
setPositiveButton(activity.getString(R.string.launch)) { _, _ ->
startActivity(activity, intent, null)
MaterialAlertDialogBuilder(context).apply {
setTitle(context.getString(R.string.success))
setMessage(context.getString(R.string.vanced_installed))
setPositiveButton(context.getString(R.string.launch)) { _, _ ->
startActivity(context, intent, null)
}
setNegativeButton(activity.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
setNegativeButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
create()
show()
}

View File

@ -11,21 +11,14 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.topjohnwu.superuser.Shell
import com.vanced.manager.R
import com.vanced.manager.adapter.*
import com.vanced.manager.core.downloader.MicrogDownloadService
import com.vanced.manager.core.downloader.MusicDownloadService
import com.vanced.manager.core.downloader.VancedDownloadService
import com.vanced.manager.adapter.SectionPageAdapter
import com.vanced.manager.adapter.SectionPageRootAdapter
import com.vanced.manager.databinding.FragmentHomeBinding
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.ui.dialogs.DialogContainer.installAlertBuilder
import com.vanced.manager.ui.dialogs.DialogContainer.launchVanced
import com.vanced.manager.ui.dialogs.DialogContainer.launchMusic
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.PackageHelper
@ -55,12 +48,6 @@ open class HomeFragment : Fragment(), View.OnClickListener {
super.onViewCreated(view, savedInstanceState)
with(binding) {
includeVancedLayout.vancedInstallbtn.setOnClickListener(this@HomeFragment)
includeVancedLayout.vancedUninstallbtn.setOnClickListener(this@HomeFragment)
includeMusicLayout.musicInstallbtn.setOnClickListener(this@HomeFragment)
includeMusicLayout.musicUninstallbtn.setOnClickListener(this@HomeFragment)
includeMicrogLayout.microgInstallbtn.setOnClickListener(this@HomeFragment)
includeMicrogLayout.microgUninstallbtn.setOnClickListener(this@HomeFragment)
includeChangelogsLayout.changelogButton.setOnClickListener(this@HomeFragment)
includeVancedLayout.vancedCard.setOnLongClickListener {
@ -107,83 +94,7 @@ open class HomeFragment : Fragment(), View.OnClickListener {
}
override fun onClick(v: View?) {
val prefs = requireActivity().getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val vancedPkgName =
if (variant == "root")
"com.google.android.youtube"
else
"com.vanced.android.youtube"
when (v?.id) {
R.id.vanced_installbtn -> {
if (!installing) {
if (!viewModel.fetching.get()) {
if (variant == "nonroot" && !viewModel.microg.get()?.isAppInstalled()!!) {
Snackbar.make(
binding.homeRefresh,
R.string.no_microg,
Snackbar.LENGTH_LONG
).setAction(R.string.install) {
requireActivity().startService(
Intent(
requireActivity(),
MicrogDownloadService::class.java
)
)
}.show()
} else {
if (prefs?.getBoolean("valuesModified", false)!!) {
requireActivity().startService(
Intent(
requireActivity(),
VancedDownloadService::class.java
)
)
} else {
view?.findNavController()?.navigate(R.id.toInstallThemeFragment)
}
}
}
} else
Toast.makeText(requireActivity(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
R.id.music_installbtn -> {
if (!installing) {
if (!viewModel.fetching.get()) {
if (!viewModel.microg.get()?.isAppInstalled()!!) {
Snackbar.make(
binding.homeRefresh,
R.string.no_microg,
Snackbar.LENGTH_LONG
).setAction(R.string.install) {
requireActivity().startService(
Intent(
requireActivity(),
MicrogDownloadService::class.java
)
)
}.show()
} else {
requireActivity().startService(
Intent(
requireActivity(),
MusicDownloadService::class.java
)
)
}
}
} else
Toast.makeText(requireActivity(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
R.id.microg_installbtn -> {
if (!installing)
requireActivity().startService(Intent(requireActivity(), MicrogDownloadService::class.java))
else
Toast.makeText(requireActivity(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
R.id.vanced_uninstallbtn -> PackageHelper.uninstallApk(vancedPkgName, requireActivity())
R.id.music_uninstallbtn -> PackageHelper.uninstallApk("com.vanced.android.apps.youtube.music", requireActivity())
R.id.microg_uninstallbtn -> PackageHelper.uninstallApk("com.mgoogle.android.gms", requireActivity())
R.id.changelog_button -> cardExpandCollapse()
}
}
@ -219,65 +130,6 @@ open class HomeFragment : Fragment(), View.OnClickListener {
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
VANCED_DOWNLOADING -> {
with(binding.includeVancedLayout) {
vancedDownloading.visibility = View.VISIBLE
vancedDownloading.progress = intent.getIntExtra("progress", 0)
vancedDownloadingTxt.visibility = View.VISIBLE
vancedDownloadingTxt.text = requireActivity().getString(R.string.downloading_file, intent.getStringExtra("file"))
}
}
MUSIC_DOWNLOADING -> {
with(binding.includeMusicLayout) {
musicDownloading.visibility = View.VISIBLE
musicDownloading.progress = intent.getIntExtra("progress", 0)
musicDownloadingTxt.visibility = View.VISIBLE
musicDownloadingTxt.text = requireActivity().getString(R.string.downloading_file, "music.apk")
}
}
MICROG_DOWNLOADING -> {
with(binding.includeMicrogLayout) {
microgDownloading.visibility = View.VISIBLE
microgDownloading.progress = intent.getIntExtra("progress", 0)
microgDownloadingTxt.visibility = View.VISIBLE
microgDownloadingTxt.text = requireActivity().getString(R.string.downloading_file, "microg.apk")
}
}
VANCED_INSTALLING -> {
with (binding.includeVancedLayout) {
vancedDownloading.visibility = View.GONE
vancedDownloadingTxt.visibility = View.GONE
vancedInstalling.visibility = View.VISIBLE
}
}
MUSIC_INSTALLING -> {
with (binding.includeMusicLayout) {
musicDownloading.visibility = View.GONE
musicDownloadingTxt.visibility = View.GONE
musicInstalling.visibility = View.VISIBLE
}
}
MICROG_INSTALLING -> {
with (binding.includeMicrogLayout) {
microgDownloading.visibility = View.GONE
microgDownloadingTxt.visibility = View.GONE
microgInstalling.visibility = View.VISIBLE
}
}
VANCED_INSTALLED -> {
binding.includeVancedLayout.vancedInstalling.visibility = View.GONE
launchVanced(requireActivity())
installing = false
}
MUSIC_INSTALLED -> {
binding.includeMusicLayout.musicInstalling.visibility = View.GONE
launchMusic(requireActivity())
installing = false
}
MICROG_INSTALLED -> {
binding.includeMicrogLayout.microgInstalling.visibility = View.GONE
installing = false
}
INSTALL_FAILED -> {
with(binding) {
includeMicrogLayout.microgInstalling.visibility = View.GONE
@ -287,26 +139,12 @@ open class HomeFragment : Fragment(), View.OnClickListener {
installAlertBuilder(intent.getStringExtra("errorMsg") as String, requireActivity())
installing = false
}
REFRESH_HOME -> {
Log.d("VMRefresh", "Refreshing home page")
viewModel.fetchData()
}
}
}
}
private fun registerReceivers() {
val intentFilter = IntentFilter()
intentFilter.addAction(VANCED_DOWNLOADING)
intentFilter.addAction(MUSIC_DOWNLOADING)
intentFilter.addAction(MICROG_DOWNLOADING)
intentFilter.addAction(VANCED_INSTALLING)
intentFilter.addAction(MUSIC_INSTALLING)
intentFilter.addAction(MICROG_INSTALLING)
intentFilter.addAction(VANCED_INSTALLED)
intentFilter.addAction(MUSIC_INSTALLED)
intentFilter.addAction(MICROG_INSTALLED)
intentFilter.addAction(REFRESH_HOME)
intentFilter.addAction(INSTALL_FAILED)
localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter)
}
@ -316,18 +154,8 @@ open class HomeFragment : Fragment(), View.OnClickListener {
super.onCreateOptionsMenu(menu, inflater)
}
companion object {
const val VANCED_DOWNLOADING = "vanced_downloading"
const val MUSIC_DOWNLOADING = "music_downloading"
const val MICROG_DOWNLOADING = "microg_downloading"
const val VANCED_INSTALLING = "vanced_installing"
const val MUSIC_INSTALLING = "music_installing"
const val MICROG_INSTALLING = "microg_installing"
const val VANCED_INSTALLED = "vanced_installed"
const val MUSIC_INSTALLED = "music_installed"
const val MICROG_INSTALLED = "microg_installed"
companion object {
const val INSTALL_FAILED = "install_failed"
const val REFRESH_HOME = "refresh_home"
}
}

View File

@ -6,19 +6,17 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.LinearLayout
import androidx.databinding.DataBindingUtil
import androidx.navigation.findNavController
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import androidx.fragment.app.Fragment
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.tabs.TabLayout
import com.vanced.manager.databinding.FragmentMainBinding
import com.vanced.manager.R
import com.vanced.manager.databinding.FragmentMainBinding
class MainFragment : Fragment() {

View File

@ -19,7 +19,9 @@ import com.vanced.manager.R
import com.vanced.manager.core.downloader.VancedDownloadService
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getArrayFromJson
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.*
class VancedLanguageSelectionFragment : Fragment() {

View File

@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.RadioButton
import android.widget.RadioGroup
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController

View File

@ -3,48 +3,66 @@ package com.vanced.manager.ui.viewmodels
import android.app.Application
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.databinding.ObservableField
import androidx.databinding.ObservableBoolean
import androidx.databinding.ObservableField
import androidx.lifecycle.AndroidViewModel
import androidx.navigation.Navigation.findNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin
import com.google.android.material.snackbar.Snackbar
import com.vanced.manager.core.downloader.MicrogDownloader.downloadMicrog
import com.vanced.manager.core.downloader.MusicDownloader.downloadMusic
import com.vanced.manager.core.downloader.VancedDownloader.downloadVanced
import com.vanced.manager.R
import com.vanced.manager.model.DataModel
import com.vanced.manager.model.ProgressModel
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.InternetTools
import com.vanced.manager.utils.PackageHelper.uninstallApk
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
open class HomeViewModel(application: Application): AndroidViewModel(application) {
val app = application
//val variant = getDefaultSharedPreferences(application).getString("vanced_variant", "nonroot")
var variant = "nonroot"
val fetching = ObservableBoolean()
val vanced = ObservableField<DataModel>()
val microg = ObservableField<DataModel>()
val music = ObservableField<DataModel>()
val manager = ObservableField<DataModel>()
val fetching = ObservableBoolean()
fun fetchData() {
CoroutineScope(Dispatchers.IO).launch {
fetching.set(true)
Crowdin.forceUpdate(getApplication())
vanced.set(DataModel("vanced", variant, getApplication()))
microg.set(DataModel("microg", context = getApplication()))
music.set(DataModel("music", context = getApplication()))
manager.set(DataModel("manager", context = getApplication()))
vanced.set(DataModel("vanced", variant, app))
microg.set(DataModel("microg", context = app))
music.set(DataModel("music", context = app))
manager.set(DataModel("manager", context = app))
fetching.set(false)
}
}
private val microgSnackbar = Snackbar.make(, R.string.no_microg, Snackbar.LENGTH_LONG).setAction(R.string.install) { downloadMicrog(getApplication()) }
private val vancedPkgName =
if (variant == "root")
"com.google.android.youtube"
else
"com.vanced.android.youtube"
fun openMicrogSettings() {
try {
@ -60,10 +78,9 @@ open class HomeViewModel(application: Application): AndroidViewModel(application
}
}
fun openUrl(Url: String) {
val customTabPrefs = getDefaultSharedPreferences(getApplication()).getBoolean("use_customtabs", true)
fun openUrl(url: String) {
val color: Int =
when (Url) {
when (url) {
"https://discord.gg/TUVd7rd" -> R.color.Discord
"https://t.me/joinchat/AAAAAEHf-pi4jH1SDlAL4w" -> R.color.Telegram
"https://twitter.com/YTVanced" -> R.color.Twitter
@ -72,18 +89,55 @@ open class HomeViewModel(application: Application): AndroidViewModel(application
"https://brave.com/van874" -> R.color.Brave
else -> R.color.Vanced
}
if (customTabPrefs) {
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(getApplication(), color))
val customTabsIntent = builder.build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
customTabsIntent.launchUrl(getApplication(), Uri.parse(Url))
} else {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(Url))
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(getApplication(), intent , null)
}
InternetTools.openUrl(url, color, getApplication())
}
fun installVanced() {
if (!installing) {
if (!fetching.get()) {
if (variant == "nonroot" && !microg.get()?.isAppInstalled()!!) {
microgSnackbar.show()
} else {
if (app.getSharedPreferences("installPrefs", Context.MODE_PRIVATE).getBoolean("valuesModified", false)!!) {
downloadVanced()
} else {
findNavController(MainActivity, R.id.nav_host).navigate(R.id.toInstallThemeFragment)
}
}
}
} else
Toast.makeText(getApplication(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
fun installMusic() {
if (!installing) {
if (!fetching.get()) {
if (!microg.get()?.isAppInstalled()!!) {
microgSnackbar.show()
} else {
downloadMusic(getApplication())
}
}
} else
Toast.makeText(getApplication(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
fun installMicrog() {
if (!installing)
downloadMicrog(getApplication())
else
Toast.makeText(getApplication(), R.string.installation_wait, Toast.LENGTH_SHORT).show()
}
fun uninstallVanced() = uninstallApk(vancedPkgName, app)
fun uninstallMusic() = uninstallApk("com.vanced.android.apps.youtube.music", app)
fun uninstallMicrog() = uninstallApk("com.mgoogle.android.gms", app)
companion object {
val vancedProgress = ObservableField<ProgressModel>()
val musicProgress = ObservableField<ProgressModel>()
val microgProgress = ObservableField<ProgressModel>()
}
init {

View File

@ -6,7 +6,10 @@ import android.content.pm.PackageInstaller
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.R
import com.vanced.manager.ui.fragments.HomeFragment
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
object AppUtils {

View File

@ -19,4 +19,4 @@ object DownloadHelper {
return downloadManager.enqueue(request)
}
}
}

View File

@ -6,9 +6,6 @@ import com.beust.klaxon.Klaxon
import com.beust.klaxon.Parser
import com.github.kittinunf.fuel.coroutines.awaitString
import com.github.kittinunf.fuel.httpGet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
object JsonHelper {

View File

@ -6,10 +6,17 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import com.vanced.manager.core.installer.AppUninstallerService
import java.lang.Exception
import com.vanced.manager.core.installer.AppInstallerService
import com.vanced.manager.core.installer.SplitInstallerService
import java.io.FileInputStream
import java.io.InputStream
object PackageHelper {
private const val yPkg = "com.google.android.youtube"
private const val apkInstallPath = "/data/adb/Vanced/"
fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try {
@ -37,18 +44,18 @@ object PackageHelper {
}
fun uninstallApk(pkg: String, activity: Activity) {
val callbackIntent = Intent(activity.applicationContext, AppUninstallerService::class.java)
val callbackIntent = Intent(activity.context, AppUninstallerService::class.java)
callbackIntent.putExtra("pkg", pkg)
val pendingIntent = PendingIntent.getService(activity.applicationContext, 0, callbackIntent, 0)
val pendingIntent = PendingIntent.getService(activity.context, 0, callbackIntent, 0)
activity.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
}
fun uninstallApk(pkg: String, applicationContext: Context): Boolean {
val callbackIntent = Intent(applicationContext, AppUninstallerService::class.java)
fun uninstallApk(pkg: String, context: Context): Boolean {
val callbackIntent = Intent(context, AppUninstallerService::class.java)
callbackIntent.putExtra("pkg", pkg)
val pendingIntent = PendingIntent.getService(applicationContext, 0, callbackIntent, 0)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
try {
applicationContext.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
context.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
return true
}
catch (e: Exception)
@ -57,4 +64,477 @@ object PackageHelper {
return false;
}
}
fun install(app: String, path: String, context: Context){
val callbackIntent = Intent(context, AppInstallerService::class.java).putExtra("app", app)
val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
params.setAppPackageName(intent?.getStringExtra("pkg"))
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
val inputStream: InputStream = FileInputStream(path)
val outputStream = session.openWrite("install", 0, -1)
val buffer = ByteArray(65536)
var c: Int
while (inputStream.read(buffer).also { c = it } != -1) {
outputStream.write(buffer, 0, c)
}
session.fsync(outputStream)
inputStream.close()
outputStream.close()
session.commit(pendingIntent.intentSender)
}
fun installVanced(context: Context): Int {
val apkFolderPath = context.getExternalFilesDir("apks")?.path + "/"
val nameSizeMap = HashMap<String, Long>()
var totalSize: Long = 0
var sessionId = 0
val folder = File(apkFolderPath)
val listOfFiles = folder.listFiles()
try {
for (listOfFile in listOfFiles!!) {
if (listOfFile.isFile) {
Log.d("AppLog", "installApk: " + listOfFile.name)
nameSizeMap[listOfFile.name] = listOfFile.length()
totalSize += listOfFile.length()
}
}
} catch (e: Exception) {
e.printStackTrace()
return -1
}
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
installParams.setSize(totalSize)
try {
sessionId = context.packageManager.packageInstaller.createSession(installParams)
Log.d("AppLog","Success: created install session [$sessionId]")
for ((key, value) in nameSizeMap) {
doWriteSession(sessionId, apkFolderPath + key, value, key, context)
}
doCommitSession(sessionId, context)
Log.d("AppLog","Success")
} catch (e: IOException) {
e.printStackTrace()
}
return sessionId
}
private fun doWriteSession(sessionId: Int, inPath: String?, sizeBytes: Long, splitName: String, context: Context): Int {
var inPathToUse = inPath
var sizeBytesToUse = sizeBytes
if ("-" == inPathToUse) {
inPathToUse = null
} else if (inPathToUse != null) {
val file = File(inPathToUse)
if (file.isFile)
sizeBytesToUse = file.length()
}
var session: PackageInstaller.Session? = null
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
if (inPathToUse != null) {
inputStream = FileInputStream(inPathToUse)
}
out = session.openWrite(splitName, 0, sizeBytesToUse)
var total = 0
val buffer = ByteArray(65536)
var c: Int
while (true) {
c = inputStream!!.read(buffer)
if (c == -1)
break
total += c
out.write(buffer, 0, c)
}
session.fsync(out)
Log.d("AppLog", "Success: streamed $total bytes")
return PackageInstaller.STATUS_SUCCESS
} catch (e: IOException) {
Log.e("AppLog", "Error: failed to write; " + e.message)
return PackageInstaller.STATUS_FAILURE
} finally {
try {
out?.close()
inputStream?.close()
session?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
private fun doCommitSession(sessionId: Int, context: Context) {
var session: PackageInstaller.Session? = null
try {
try {
session = context.packageManager.packageInstaller.openSession(sessionId)
val callbackIntent = Intent(context.context, SplitInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context.context, 0, callbackIntent, 0)
session.commit(pendingIntent.intentSender)
session.close()
Log.d("AppLog", "install request sent")
Log.d("AppLog", "doCommitSession: " + context.packageManager.packageInstaller.mySessions)
Log.d("AppLog", "doCommitSession: after session commit ")
} catch (e: IOException) {
e.printStackTrace()
}
} finally {
session!!.close()
}
}
fun insallVancedRoot(context: Context) {
Shell.enableVerboseLogging = BuildConfig.DEBUG
Shell.setDefaultBuilder(
Shell.Builder.create()
.setFlags(Shell.FLAG_REDIRECT_STDERR)
.setTimeout(10)
)
Shell.getShell {
CoroutineScope(Dispatchers.IO).launch {
val apkFilesPath = getExternalFilesDir("apks")?.path
val fileInfoList = apkFilesPath?.let { it1 -> getFileInfoList(it1) }
if (fileInfoList != null) {
var modApk: FileInfo? = null
for (file in fileInfoList) {
if (file.name == "dark.apk" || file.name == "black.apk") {
modApk = file
}
}
if (modApk != null) {
if (getDefaultSharedPreferences(this@RootSplitInstallerService).getBoolean("new_installer", false)) {
if (overwriteBase(modApk, fileInfoList, vancedVersionCode)) {
with(localBroadcastManager) {
sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
sendBroadcast(Intent(HomeFragment.VANCED_INSTALLED))
}
}
} else
installSplitApkFiles(fileInfoList)
}
else
{
sendFailure(listOf("ModApk_Missing").toMutableList(), context)
}
//installSplitApkFiles(fileInfoList)
}
else
{
sendFailure(listOf("Files_Missing_VA").toMutableList(), context)
}
}
}
}
private fun installSplitApkFiles(apkFiles: ArrayList<FileInfo>) : Boolean {
var sessionId: Int?
Log.d("AppLog", "installing split apk files:$apkFiles")
run {
val sessionIdResult = Shell.su("pm install-create -r -t").exec().out
val sessionIdPattern = Pattern.compile("(\\d+)")
val sessionIdMatcher = sessionIdPattern.matcher(sessionIdResult[0])
sessionIdMatcher.find()
sessionId = Integer.parseInt(sessionIdMatcher.group(1)!!)
}
apkFiles.forEach { apkFile ->
if(apkFile.name != "black.apk" && apkFile.name != "dark.apk" && apkFile.name != "hash.json")
{
Log.d("AppLog", "installing APK : ${apkFile.name} ${apkFile.fileSize} ")
val command = arrayOf("su", "-c", "pm", "install-write", "-S", "${apkFile.fileSize}", "$sessionId", apkFile.name)
val process: Process = Runtime.getRuntime().exec(command)
val inputPipe = apkFile.getInputStream()
try {
process.outputStream.use { outputStream -> inputPipe.copyTo(outputStream) }
} catch (e: Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
process.destroyForcibly()
else
process.destroy()
throw RuntimeException(e)
}
process.waitFor()
}
}
Log.d("AppLog", "committing...")
val installResult = Shell.su("pm install-commit $sessionId").exec()
if (installResult.isSuccess) {
return true
} else
sendFailure(installResult.out, this)
return false
}
private fun SimpleDateFormat.tryParse(str: String) = try {
parse(str) != null
} catch (e: Exception) {
false
}
private fun getFileInfoList(splitApkPath: String): ArrayList<FileInfo> {
val parentFile = File(splitApkPath)
val result = ArrayList<FileInfo>()
if (parentFile.exists() && parentFile.canRead()) {
val listFiles = parentFile.listFiles() ?: return ArrayList()
for (file in listFiles)
result.add(FileInfo(file.name, file.length(), file))
return result
}
val longLines = Shell.su("ls -l $splitApkPath").exec().out
val pattern = Pattern.compile(" +")
val formatter = SimpleDateFormat("HH:mm", Locale.getDefault())
longLinesLoop@ for (line in longLines) {
val matcher = pattern.matcher(line)
for (i in 0 until 4)
if (!matcher.find())
continue@longLinesLoop
val startSizeStr = matcher.end()
matcher.find()
val endSizeStr = matcher.start()
val fileSizeStr = line.substring(startSizeStr, endSizeStr)
while (true) {
val testTimeStr: String =
line.substring(matcher.end(), line.indexOf(' ', matcher.end()))
if (formatter.tryParse(testTimeStr)) {
//found time, so apk is next
val fileName = line.substring(line.indexOf(' ', matcher.end()) + 1)
if (fileName.endsWith("apk"))
result.add(FileInfo(fileName, fileSizeStr.toLong(), File(splitApkPath, fileName)))
break
}
matcher.find()
}
}
return result
}
//install Vanced
private fun overwriteBase(apkFile: FileInfo,baseApkFiles: ArrayList<FileInfo>, versionCode: Int): Boolean {
if (checkVersion(versionCode,baseApkFiles)) {
val path = getPackageDir()
apkFile.file?.let {
val apath = it.absolutePath
setupFolder(apkInstallPath)
if(path != null)
{
val apkFPath = apkInstallPath + "base.apk"
if(moveAPK(apath, apkFPath))
{
if(chConV(apkFPath))
{
if(setupScript(apkFPath,path))
{
return linkVanced(apkFPath,path)
}
}
}
}
}
}
return false
}
private fun setupScript(apkFPath: String, path: String): Boolean
{
if(Shell.su("""echo "#!/system/bin/sh\nsleep 1m\nmount -o bind $apkFPath $path" > /data/adb/service.d/vanced.sh""").exec().isSuccess)
{
return Shell.su("chmod 744 /data/adb/service.d/vanced.sh").exec().isSuccess
}
return false
}
private fun linkVanced(apkFPath: String, path: String): Boolean
{
Shell.su("am force-stop $yPkg").exec()
Thread.sleep(500)
val response = Shell.su("""su -mm -c "mount -o bind $apkFPath $path"""").exec()
return response.isSuccess
}
private fun setupFolder(apkInstallPath: String): Boolean {
return Shell.su("mkdir -p $apkInstallPath").exec().isSuccess
}
//check version and perform action based on result
private fun checkVersion(versionCode: Int, baseApkFiles: ArrayList<FileInfo>): Boolean {
val path = getPackageDir()
if (path != null) {
if(path.contains("/data/app/"))
{
when(getVersionNumber()?.let { compareVersion(it,versionCode) })
{
1 -> {return fixHigherVer(baseApkFiles) }
-1 -> {return fixLowerVer(baseApkFiles) }
}
return true
}
else
{
return fixNoInstall(baseApkFiles)
}
}
return fixNoInstall(baseApkFiles)
}
private fun getPkgInfo(pkg: String): PackageInfo? {
return try {
packageManager.getPackageInfo(pkg, 0)
} catch (e:Exception) {
Log.d("VMpm", "Unable to get package info")
null
}
}
private fun compareVersion(pkgVerCode: Int, versionCode: Int): Int {
return when {
pkgVerCode > versionCode -> 1
pkgVerCode < versionCode -> -1
else -> 0
}
}
//uninstall current update and install base that works with patch
private fun fixHigherVer(apkFiles: ArrayList<FileInfo>) : Boolean {
if(PackageHelper.uninstallApk(yPkg, context)) {
return installSplitApkFiles(apkFiles)
}
sendFailure(listOf("Failed_Uninstall").toMutableList(), this)
return false
}
//install newer stock youtube
private fun fixLowerVer(apkFiles: ArrayList<FileInfo>): Boolean {
return installSplitApkFiles(apkFiles)
}
//install stock youtube since no install was found
private fun fixNoInstall(baseApkFiles: ArrayList<FileInfo>): Boolean {
return installSplitApkFiles(baseApkFiles)
}
//set chcon to apk_data_file
private fun chConV(path: String): Boolean {
val response = Shell.su("chcon u:object_r:apk_data_file:s0 $path").exec()
//val response = Shell.su("chcon -R u:object_r:system_file:s0 $path").exec()
return if (response.isSuccess) {
true
} else {
sendFailure(response.out, context)
false
}
}
//move patch to data/app
private fun moveAPK(apkFile: String, path: String) : Boolean {
val apkinF = SuFile.open(apkFile)
val apkoutF = SuFile.open(path)
if(apkinF.exists()) {
try {
Shell.su("am force-stop $yPkg").exec()
//Shell.su("rm -r SuFile.open(path).parent")
copy(apkinF,apkoutF)
Shell.su("chmod 644 $path").exec().isSuccess
return if(Shell.su("chown system:system $path").exec().isSuccess) {
true
} else {
sendFailure(listOf("Chown_Fail").toMutableList(), context)
false
}
}
catch (e: IOException)
{
sendFailure(listOf("${e.message}").toMutableList(), context)
return false
}
}
else {
sendFailure(listOf("IFile_Missing").toMutableList(), context)
return false
}
}
@Throws(IOException::class)
fun copy(src: File?, dst: File?) {
val cmd = Shell.su("mv ${src!!.absolutePath} ${dst!!.absolutePath}").exec().isSuccess
Log.d("ZLog", cmd.toString())
}
//get path of the installed youtube
private fun getVPath(): String? {
return try {
val p = getPkgInfo(yPkg)
p?.applicationInfo?.sourceDir
} catch (e: Exception) {
null
}
}
private fun getVersionNumber(): Int?
{
try {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
packageManager.getPackageInfo(yPkg, 0)?.longVersionCode?.and(0xFFFFFFFF)?.toInt()
else
packageManager.getPackageInfo(yPkg, 0)?.versionCode
}
catch (e : Exception)
{
val execRes = Shell.su("dumpsys package com.google.android.youtube | grep versionCode").exec()
if(execRes.isSuccess)
{
val result = execRes.out
var version: Int = 0
for(line in result)
{
val versionCode = line.substringAfter("=")
val versionCodeFiltered = versionCode.substringBefore(" ")
if(version < Integer.valueOf(versionCodeFiltered))
{
version = Integer.valueOf(versionCodeFiltered)
}
}
return version
}
}
return null
}
private fun getPackageDir(): String?
{
return try {
val p = getPkgInfo(yPkg)
p?.applicationInfo?.sourceDir
} catch (e: Exception) {
val execRes = Shell.su("dumpsys package com.google.android.youtube | grep codePath").exec()
if(execRes.isSuccess)
{
val result = execRes.out
for (line in result)
{
if(line.contains("data/app")) "${line.substringAfter("=")}/base.apk"
}
}
null
}
}
}

View File

@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:refreshing="@{viewModel.fetching}"
bind:onRefreshListener="@{()-> viewModel.fetchData()}">
bind:onRefreshListener="@{()-> viewModel.Companion.fetchData()}">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"

View File

@ -10,7 +10,7 @@
<variable
name="viewModel"
type="com.vanced.manager.ui.viewmodels.HomeViewModel" />
type="com.microg.manager.ui.viewmodels.HomeViewModel" />
</data>
@ -48,6 +48,7 @@
android:id="@+id/microg_installbtn"
style="@style/ButtonStyle"
android:text="@{viewModel.microg.buttonTxt}"
android:onClick="@{()-> viewModel.installMicrog()}"
app:icon="@{viewModel.microg.buttonIcon}"
app:layout_constraintBottom_toTopOf="@id/microg_uninstallbtn"
app:layout_constraintEnd_toEndOf="parent"
@ -112,6 +113,7 @@
<ImageView
android:id="@+id/microg_uninstallbtn"
style="@style/ClickableImageWidget.Red"
android:onClick="@{()-> viewModel.uninstallMicrog()}"
android:visibility="@{viewModel.microg.appInstalled ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -124,7 +126,8 @@
android:id="@+id/microg_downloading_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.microgProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:text="@{viewModel.Companion.microgProgress.downloadingFile}"
tools:visibility="visible" />
<ProgressBar
@ -132,14 +135,15 @@
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.microgProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:progress="@{viewModel.Companion.microgProgress.downloadProgress}"
tools:visibility="visible" />
<ProgressBar
android:id="@+id/microg_installing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.microgProgress.showInstallCircle ? View.VISIBLE : View.GONE}"
tools:visibility="visible" />
</LinearLayout>

View File

@ -10,7 +10,7 @@
<variable
name="viewModel"
type="com.vanced.manager.ui.viewmodels.HomeViewModel" />
type="com.music.manager.ui.viewmodels.HomeViewModel" />
</data>
@ -48,6 +48,7 @@
android:id="@+id/music_installbtn"
style="@style/ButtonStyle"
android:text="@{viewModel.music.buttonTxt}"
android:onClick="@{()-> viewModel.installMusic()}"
app:icon="@{viewModel.music.buttonIcon}"
app:layout_constraintBottom_toTopOf="@id/music_uninstallbtn"
app:layout_constraintEnd_toEndOf="parent"
@ -102,6 +103,7 @@
android:id="@+id/music_uninstallbtn"
style="@style/ClickableImageWidget.Red"
android:visibility="@{viewModel.music.appInstalled ? View.VISIBLE : View.GONE}"
android:onClick="@{()-> viewModel.uninstallMusic()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/music_title_buttons_barrier"
@ -113,7 +115,8 @@
android:id="@+id/music_downloading_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.musicProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:text="@{viewModel.Companion.musicProgress.downloadingFile}"
tools:visibility="visible" />
<ProgressBar
@ -121,14 +124,15 @@
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.musicProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:progress="@{viewModel.Companion.musicProgress.downloadProgress}"
tools:visibility="visible" />
<ProgressBar
android:id="@+id/music_installing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.musicProgress.showInstallCircle ? View.VISIBLE : View.GONE}"
tools:visibility="visible" />
</LinearLayout>

View File

@ -51,6 +51,7 @@
android:text="@{viewModel.vanced.buttonTxt}"
android:textColor="@color/White"
android:backgroundTint="?colorPrimary"
android:onClick="@{()-> viewModel.installVanced()}"
app:icon="@{viewModel.vanced.buttonIcon}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -65,6 +66,7 @@
<ImageView
android:id="@+id/vanced_uninstallbtn"
style="@style/ClickableImageWidget.Red"
android:onClick="@{()-> viewModel.uninstallVanced()}"
android:visibility="@{viewModel.vanced.appInstalled ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -114,7 +116,8 @@
android:id="@+id/vanced_downloading_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.vancedProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:text="@{viewModel.Companion.vancedProgress.downloadingFile}"
tools:visibility="visible" />
<ProgressBar
@ -122,14 +125,15 @@
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.vancedProgress.showDownloadBar ? View.VISIBLE : View.GONE}"
android:progress="@{viewModel.Companion.vancedProgress.downloadProgress}"
tools:visibility="visible" />
<ProgressBar
android:id="@+id/vanced_installing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="@{viewModel.Companion.vancedProgress.showInstallCircle ? View.VISIBLE : View.GONE}"
tools:visibility="visible" />
</LinearLayout>

View File

@ -10,7 +10,7 @@ org.gradle.jvmargs=-Xmx4096m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true
org.gradle.parallel=false
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
@ -19,5 +19,3 @@ android.useAndroidX=true
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
org.gradle.configureondemand=true