0
0
Fork 0
mirror of https://github.com/YTVanced/VancedManager synced 2024-11-25 12:45:12 +00:00

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" /> android:resource="@drawable/ic_stat_name" />
<service android:name=".core.installer.SplitInstallerService" /> <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.AppUninstallerService" />
<service android:name=".core.installer.AppInstallerService" /> <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> </application>

View file

@ -1,8 +1,6 @@
package com.vanced.manager.core package com.vanced.manager.core
import android.app.Application import android.app.Application
import android.util.Log
import android.os.Build
import com.crowdin.platform.Crowdin import com.crowdin.platform.Crowdin
import com.crowdin.platform.CrowdinConfig import com.crowdin.platform.CrowdinConfig
import com.crowdin.platform.data.remote.NetworkType 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 package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import android.widget.Toast import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.downloader.Error import com.downloader.Error
import com.downloader.OnDownloadListener import com.downloader.OnDownloadListener
import com.downloader.PRDownloader import com.downloader.PRDownloader
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.core.installer.AppInstaller 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.AppUtils.installing
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getJsonString import com.vanced.manager.utils.InternetTools.getJsonString
import com.vanced.manager.utils.PackageHelper.install
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class MusicDownloadService: Service() { object MusicDownloader {
//private var downloadId: Long = 0 //private var downloadId: Long = 0
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { fun downloadMusic(context: Context) {
//registerReceiver(receiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
downloadMusic()
stopSelf()
return START_NOT_STICKY
}
private fun downloadMusic() {
CoroutineScope(Dispatchers.IO).launch { 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" val url = "https://vanced.app/api/v1/music/v$version.apk"
//downloadId = download(url, "apk", "music.apk", this@MusicDownloadService) //downloadId = download(url, "apk", "music.apk", this@MusicDownloadService)
PRDownloader.download(url, getExternalFilesDir("apk")?.path, "music.apk") PRDownloader.download(url, getExternalFilesDir("apk")?.path, "music.apk")
.build() .build()
.setOnStartOrResumeListener { installing = true } .setOnStartOrResumeListener {
installing = true
musicProgress.get()?.setDownloadingFile(getFileNameFromUrl(url))
musicProgress.get()?.showDownloadBar = true
}
.setOnProgressListener { progress -> .setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes musicProgress.get()?.setDownloadProgress(progress.currentBytes * 100 / progress.totalBytes)
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MUSIC_DOWNLOADING).putExtra("progress", mProgress.toInt()).putExtra("file", getFileNameFromUrl(url)))
} }
.start(object : OnDownloadListener { .start(object : OnDownloadListener {
override fun onDownloadComplete() { override fun onDownloadComplete() {
val intent = Intent(this@MusicDownloadService, AppInstaller::class.java) install("music", "${context.getExternalFilesDir("apk")}/music.apk", context)
intent.putExtra("path", "${getExternalFilesDir("apk")}/music.apk") musicProgress.get().showDownloadBar = false
intent.putExtra("pkg", "com.vanced.android.apps.youtube.music") musicProgress.get().showInstallCircle = true
localBroadcastManager.sendBroadcast(Intent(HomeFragment.MUSIC_INSTALLING))
startService(intent)
} }
override fun onError(error: Error?) { override fun onError(error: Error?) {
installing = false 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 package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.widget.Toast import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.downloader.Error import com.downloader.Error
import com.downloader.OnDownloadListener import com.downloader.OnDownloadListener
@ -15,13 +13,15 @@ import com.downloader.PRDownloader
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.core.installer.RootSplitInstallerService import com.vanced.manager.core.installer.RootSplitInstallerService
import com.vanced.manager.core.installer.SplitInstaller 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.AppUtils.installing
import com.vanced.manager.utils.InternetTools import com.vanced.manager.utils.InternetTools
import com.vanced.manager.utils.InternetTools.baseUrl import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.InternetTools.getObjectFromJson import com.vanced.manager.utils.InternetTools.getObjectFromJson
import com.vanced.manager.utils.PackageHelper.getPkgVerCode 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.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -30,7 +30,7 @@ import java.io.File
import java.io.IOException import java.io.IOException
import java.security.MessageDigest import java.security.MessageDigest
class VancedDownloadService: Service() { object VancedDownloader {
private var sha256Val: String? = null private var sha256Val: String? = null
@ -48,16 +48,15 @@ class VancedDownloadService: Service() {
//private var downloadId: Long = 0 //private var downloadId: Long = 0
//private var apkType: String = "arch" //private var apkType: String = "arch"
private var count: Int = 0 private var count: Int = 0
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
private var hashUrl = "" private var hashUrl = ""
private val yPkg = "com.google.android.youtube" private val yPkg = "com.google.android.youtube"
private val vancedVersionCode by lazy {runBlocking { InternetTools.getJsonInt("vanced.json", "versionCode", applicationContext) }} private val vancedVersionCode by lazy {runBlocking { InternetTools.getJsonInt("vanced.json", "versionCode", applicationContext) }}
private val vancedVersion by lazy { runBlocking { getObjectFromJson("$installUrl/vanced.json", "version") }} 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)) //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) defPrefs = PreferenceManager.getDefaultSharedPreferences(this)
installUrl = defPrefs.getString("install_url", baseUrl) installUrl = defPrefs.getString("install_url", baseUrl)
prefs = getSharedPreferences("installPrefs", Context.MODE_PRIVATE) prefs = getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
@ -73,12 +72,11 @@ class VancedDownloadService: Service() {
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a" Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a"
else -> "armeabi_v7a" else -> "armeabi_v7a"
} }
downloadSplits() downloadSplits(context)
stopSelf()
return START_NOT_STICKY
} }
private fun downloadSplits( private fun downloadSplits(context,
context: Context,
type: String = "theme" type: String = "theme"
) { ) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
@ -95,54 +93,57 @@ class VancedDownloadService: Service() {
//apkType = type //apkType = type
//downloadId = download(url, "apks", getFileNameFromUrl(url), this@VancedDownloadService) //downloadId = download(url, "apks", getFileNameFromUrl(url), this@VancedDownloadService)
PRDownloader PRDownloader
.download(url, getExternalFilesDir("apks")?.path, getFileNameFromUrl(url)) .download(url, getExternalFilesDir("apks")?.path, getFileNameFromUrl(url))
.build() .build()
.setOnStartOrResumeListener { installing = true } .setOnStartOrResumeListener {
.setOnProgressListener { progress -> installing = true
val mProgress = progress.currentBytes * 100 / progress.totalBytes vancedProgress.get()?.setDownloadingFile(getFileNameFromUrl(url))
localBroadcastManager.sendBroadcast(Intent(HomeFragment.VANCED_DOWNLOADING).putExtra("progress", mProgress.toInt()).putExtra("file", getFileNameFromUrl(url))) vancedProgress.get()?.showDownloadBar = true
} }
.start(object : OnDownloadListener { .setOnProgressListener { progress ->
override fun onDownloadComplete() { vancedProgress.get()?.setDownloadProgress(progress.currentBytes * 100 / progress.totalBytes)
when (type) { }
"theme" -> .start(object : OnDownloadListener {
if (variant == "root" && newInstaller == true) { override fun onDownloadComplete() {
if (ValidateTheme()) { when (type) {
if(downloadStockCheck()) "theme" ->
downloadSplits("arch") if (variant == "root" && newInstaller == true) {
else if (ValidateTheme()) {
prepareInstall(variant!!) if(downloadStockCheck())
downloadSplits(context, "arch")
else
prepareInstall(variant!!)
} else
downloadSplits(context, "theme")
} else } else
downloadSplits("theme") downloadSplits(context, "arch")
} else "arch" -> if (variant == "root" && newInstaller == true) downloadSplits(context, "stock") else downloadSplits(context, "lang")
downloadSplits("arch") "stock" -> downloadSplits(context, "dpi")
"arch" -> if (variant == "root" && newInstaller == true) downloadSplits("stock") else downloadSplits("lang") "dpi" -> downloadSplits(context, "lang")
"stock" -> downloadSplits("dpi") "lang" -> {
"dpi" -> downloadSplits("lang") count++
"lang" -> { if (count < lang?.count()!!)
downloadSplits(context, "lang")
else
prepareInstall(variant!!)
}
}
}
override fun onError(error: Error?) {
if (type == "lang") {
count++ count++
if (count < lang?.count()!!) if (count < lang?.count()!!)
downloadSplits("lang") downloadSplits(context, "lang")
else else
prepareInstall(variant!!) 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") val lang = prefs?.getString("lang", "en")
if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadId) { if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadId) {
when (apkType) { when (apkType) {
"arch" -> downloadSplits("theme") "arch" -> downloadSplits(context, "theme")
"theme" -> downloadSplits("lang") "theme" -> downloadSplits(context, "lang")
"lang" -> { "lang" -> {
if (lang == "en") { if (lang == "en") {
prepareInstall(variant!!) prepareInstall(variant!!)
//cancelNotif(channel, this@VancedDownloadService) //cancelNotif(channel, this@VancedDownloadService)
} else { } else {
downloadSplits("enlang") downloadSplits(context, "enlang")
} }
} }
"enlang" -> { "enlang" -> {
@ -196,12 +197,13 @@ class VancedDownloadService: Service() {
} }
*/ */
private fun prepareInstall(variant: String) { private fun prepareInstall(variant: String, context: Context) {
localBroadcastManager.sendBroadcast(Intent(HomeFragment.VANCED_INSTALLING)) vancedProgress.get()?.showDownloadBar = false
vancedProgress.get()?.showInstallCircle = true
if (variant == "root") if (variant == "root")
startService(Intent(this, RootSplitInstallerService::class.java)) installVancedRoot(context)
else else
startService(Intent(this, SplitInstaller::class.java)) installvanced(context)
} }
override fun onBind(intent: Intent?): IBinder? { 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.content.pm.PackageInstaller
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.microgProgress
import com.vanced.manager.ui.fragments.HomeFragment import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.musicProgress
import com.vanced.manager.utils.AppUtils.sendFailure
class AppInstallerService: Service() { class AppInstallerService: Service() {
@ -17,7 +16,6 @@ class AppInstallerService: Service() {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) { when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> { PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d(TAG, "Requesting user confirmation for installation") 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) val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try { try {
@ -28,10 +26,7 @@ class AppInstallerService: Service() {
} }
PackageInstaller.STATUS_SUCCESS -> { PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed") Log.d(TAG, "Installation succeed")
with(localBroadcastManager) { if (intent?.getStringExtra("app") == "microg") microgProgress.showInstallCircle = false else musicProgress.showInstallCircle = false
sendBroadcast(Intent(HomeFragment.REFRESH_HOME))
sendBroadcast(Intent(if (intent.getStringExtra("app") == "microg") HomeFragment.MICROG_INSTALLING else HomeFragment.MUSIC_INSTALLING))
}
} }
else -> sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999), this) 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.content.pm.PackageInstaller
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.vanced.manager.ui.viewmodels.HomeViewModel.Companion.fetchData
import com.vanced.manager.ui.fragments.HomeFragment import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class AppUninstallerService: Service() { class AppUninstallerService: Service() {
private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val pkgName = intent?.getStringExtra("pkg") val pkgName = intent?.getStringExtra("pkg")
when (intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) { when (intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
@ -25,18 +25,18 @@ class AppUninstallerService: Service() {
} catch (e: Exception) { } 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 -> { PackageInstaller.STATUS_SUCCESS -> {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
delay(500) delay(500)
localBroadcastManager.sendBroadcast(Intent(HomeFragment.REFRESH_HOME)) fetchData()
Log.d("VMpm", "Successfully uninstalled $pkgName") Log.d("VMpm", "Successfully uninstalled $pkgName")
} }
} }
PackageInstaller.STATUS_FAILURE -> { PackageInstaller.STATUS_FAILURE -> {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
delay(500) delay(500)
localBroadcastManager.sendBroadcast(Intent(HomeFragment.REFRESH_HOME)) fetchData()
Log.d("VMpm", "Failed to uninstall $pkgName") Log.d("VMpm", "Failed to uninstall $pkgName")
} }
} }

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

View file

@ -3,20 +3,14 @@ package com.vanced.manager.model
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build 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.baseUrl
import com.vanced.manager.utils.InternetTools.getJsonInt import com.vanced.manager.utils.InternetTools.getJsonInt
import com.vanced.manager.utils.InternetTools.getJsonString import com.vanced.manager.utils.InternetTools.getJsonString
import com.vanced.manager.utils.InternetTools.getObjectFromJson import com.vanced.manager.utils.InternetTools.getObjectFromJson
import com.vanced.manager.utils.PackageHelper.isPackageInstalled 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.Dispatchers
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
open class DataModel( open class DataModel(
private val jsonName: String, 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.os.Bundle
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager.getDefaultSharedPreferences import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin import com.crowdin.platform.Crowdin
import com.crowdin.platform.LoadingStateListener import com.crowdin.platform.LoadingStateListener
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.tabs.TabLayout 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.google.firebase.messaging.FirebaseMessaging
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.adapter.SectionVariantAdapter
import com.vanced.manager.databinding.ActivityMainBinding import com.vanced.manager.databinding.ActivityMainBinding
import com.vanced.manager.ui.dialogs.DialogContainer import com.vanced.manager.ui.dialogs.DialogContainer
import com.vanced.manager.ui.fragments.UpdateCheckFragment 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() val intent = Intent()
intent.component = 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") ComponentName("com.google.android.youtube", "com.google.android.youtube.HomeActivity")
else else
ComponentName("com.vanced.android.youtube", "com.google.android.youtube.HomeActivity") ComponentName("com.vanced.android.youtube", "com.google.android.youtube.HomeActivity")
MaterialAlertDialogBuilder(activity).apply {
setTitle(activity.getString(R.string.success)) MaterialAlertDialogBuilder(context).apply {
setMessage(activity.getString(R.string.vanced_installed)) setTitle(context.getString(R.string.success))
setPositiveButton(activity.getString(R.string.launch)) { _, _ -> setMessage(context.getString(R.string.vanced_installed))
startActivity(activity, intent, null) 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() create()
show() show()
} }

View file

@ -11,21 +11,14 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.topjohnwu.superuser.Shell
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.adapter.* import com.vanced.manager.adapter.SectionPageAdapter
import com.vanced.manager.core.downloader.MicrogDownloadService import com.vanced.manager.adapter.SectionPageRootAdapter
import com.vanced.manager.core.downloader.MusicDownloadService
import com.vanced.manager.core.downloader.VancedDownloadService
import com.vanced.manager.databinding.FragmentHomeBinding 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.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.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.AppUtils.installing import com.vanced.manager.utils.AppUtils.installing
import com.vanced.manager.utils.PackageHelper import com.vanced.manager.utils.PackageHelper
@ -55,12 +48,6 @@ open class HomeFragment : Fragment(), View.OnClickListener {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
with(binding) { 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) includeChangelogsLayout.changelogButton.setOnClickListener(this@HomeFragment)
includeVancedLayout.vancedCard.setOnLongClickListener { includeVancedLayout.vancedCard.setOnLongClickListener {
@ -107,83 +94,7 @@ open class HomeFragment : Fragment(), View.OnClickListener {
} }
override fun onClick(v: View?) { 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) { 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() R.id.changelog_button -> cardExpandCollapse()
} }
} }
@ -219,65 +130,6 @@ open class HomeFragment : Fragment(), View.OnClickListener {
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() { private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
when (intent.action) { 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 -> { INSTALL_FAILED -> {
with(binding) { with(binding) {
includeMicrogLayout.microgInstalling.visibility = View.GONE includeMicrogLayout.microgInstalling.visibility = View.GONE
@ -287,26 +139,12 @@ open class HomeFragment : Fragment(), View.OnClickListener {
installAlertBuilder(intent.getStringExtra("errorMsg") as String, requireActivity()) installAlertBuilder(intent.getStringExtra("errorMsg") as String, requireActivity())
installing = false installing = false
} }
REFRESH_HOME -> {
Log.d("VMRefresh", "Refreshing home page")
viewModel.fetchData()
}
} }
} }
} }
private fun registerReceivers() { private fun registerReceivers() {
val intentFilter = IntentFilter() 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) intentFilter.addAction(INSTALL_FAILED)
localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter) localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter)
} }
@ -317,17 +155,7 @@ open class HomeFragment : Fragment(), View.OnClickListener {
} }
companion object { 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"
const val INSTALL_FAILED = "install_failed" 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.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.LinearLayout
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.navigation.findNavController import androidx.fragment.app.Fragment
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import androidx.fragment.app.Fragment
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.vanced.manager.databinding.FragmentMainBinding
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.databinding.FragmentMainBinding
class MainFragment : Fragment() { 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.core.downloader.VancedDownloadService
import com.vanced.manager.utils.InternetTools.baseUrl import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getArrayFromJson 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.* import java.util.*
class VancedLanguageSelectionFragment : Fragment() { class VancedLanguageSelectionFragment : Fragment() {

View file

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

View file

@ -3,49 +3,67 @@ package com.vanced.manager.ui.viewmodels
import android.app.Application import android.app.Application
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.ComponentName import android.content.ComponentName
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import androidx.databinding.ObservableField
import androidx.databinding.ObservableBoolean import androidx.databinding.ObservableBoolean
import androidx.databinding.ObservableField
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.navigation.Navigation.findNavController
import androidx.preference.PreferenceManager.getDefaultSharedPreferences import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.crowdin.platform.Crowdin 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.R
import com.vanced.manager.model.DataModel 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.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
open class HomeViewModel(application: Application): AndroidViewModel(application) { open class HomeViewModel(application: Application): AndroidViewModel(application) {
val app = application
//val variant = getDefaultSharedPreferences(application).getString("vanced_variant", "nonroot") //val variant = getDefaultSharedPreferences(application).getString("vanced_variant", "nonroot")
var variant = "nonroot" var variant = "nonroot"
val fetching = ObservableBoolean()
val vanced = ObservableField<DataModel>() val vanced = ObservableField<DataModel>()
val microg = ObservableField<DataModel>() val microg = ObservableField<DataModel>()
val music = ObservableField<DataModel>() val music = ObservableField<DataModel>()
val manager = ObservableField<DataModel>() val manager = ObservableField<DataModel>()
val fetching = ObservableBoolean()
fun fetchData() { fun fetchData() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
fetching.set(true) fetching.set(true)
Crowdin.forceUpdate(getApplication()) Crowdin.forceUpdate(getApplication())
vanced.set(DataModel("vanced", variant, getApplication())) vanced.set(DataModel("vanced", variant, app))
microg.set(DataModel("microg", context = getApplication())) microg.set(DataModel("microg", context = app))
music.set(DataModel("music", context = getApplication())) music.set(DataModel("music", context = app))
manager.set(DataModel("manager", context = getApplication())) manager.set(DataModel("manager", context = app))
fetching.set(false) 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() { fun openMicrogSettings() {
try { try {
val intent = Intent() val intent = Intent()
@ -60,10 +78,9 @@ open class HomeViewModel(application: Application): AndroidViewModel(application
} }
} }
fun openUrl(Url: String) { fun openUrl(url: String) {
val customTabPrefs = getDefaultSharedPreferences(getApplication()).getBoolean("use_customtabs", true)
val color: Int = val color: Int =
when (Url) { when (url) {
"https://discord.gg/TUVd7rd" -> R.color.Discord "https://discord.gg/TUVd7rd" -> R.color.Discord
"https://t.me/joinchat/AAAAAEHf-pi4jH1SDlAL4w" -> R.color.Telegram "https://t.me/joinchat/AAAAAEHf-pi4jH1SDlAL4w" -> R.color.Telegram
"https://twitter.com/YTVanced" -> R.color.Twitter "https://twitter.com/YTVanced" -> R.color.Twitter
@ -73,17 +90,54 @@ open class HomeViewModel(application: Application): AndroidViewModel(application
else -> R.color.Vanced else -> R.color.Vanced
} }
if (customTabPrefs) { InternetTools.openUrl(url, color, getApplication())
val builder = CustomTabsIntent.Builder() }
builder.setToolbarColor(ContextCompat.getColor(getApplication(), color))
val customTabsIntent = builder.build() fun installVanced() {
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK if (!installing) {
customTabsIntent.launchUrl(getApplication(), Uri.parse(Url)) if (!fetching.get()) {
} else { if (variant == "nonroot" && !microg.get()?.isAppInstalled()!!) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(Url)) microgSnackbar.show()
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK } else {
startActivity(getApplication(), intent , null) 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 { init {

View file

@ -6,7 +6,10 @@ import android.content.pm.PackageInstaller
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.ui.fragments.HomeFragment 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 { object AppUtils {

View file

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

View file

@ -6,11 +6,18 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.util.Log
import com.vanced.manager.core.installer.AppUninstallerService 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 { object PackageHelper {
private const val yPkg = "com.google.android.youtube"
private const val apkInstallPath = "/data/adb/Vanced/"
fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean { fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try { return try {
packageManager.getPackageInfo(packageName, 0) packageManager.getPackageInfo(packageName, 0)
@ -37,18 +44,18 @@ object PackageHelper {
} }
fun uninstallApk(pkg: String, activity: Activity) { 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) 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) activity.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
} }
fun uninstallApk(pkg: String, applicationContext: Context): Boolean { fun uninstallApk(pkg: String, context: Context): Boolean {
val callbackIntent = Intent(applicationContext, AppUninstallerService::class.java) val callbackIntent = Intent(context, AppUninstallerService::class.java)
callbackIntent.putExtra("pkg", pkg) callbackIntent.putExtra("pkg", pkg)
val pendingIntent = PendingIntent.getService(applicationContext, 0, callbackIntent, 0) val pendingIntent = PendingIntent.getService(context, 0, callbackIntent, 0)
try { try {
applicationContext.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender) context.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
return true return true
} }
catch (e: Exception) catch (e: Exception)
@ -57,4 +64,477 @@ object PackageHelper {
return false; 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_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
bind:refreshing="@{viewModel.fetching}" bind:refreshing="@{viewModel.fetching}"
bind:onRefreshListener="@{()-> viewModel.fetchData()}"> bind:onRefreshListener="@{()-> viewModel.Companion.fetchData()}">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ org.gradle.jvmargs=-Xmx4096m
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # 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 # 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 # 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 # Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
@ -19,5 +19,3 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete": # Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official kotlin.code.style=official
org.gradle.configureondemand=true