mirror of
https://github.com/YTVanced/VancedManager
synced 2024-11-25 12:45:12 +00:00
started code cleanup
This commit is contained in:
parent
5681b6fb4f
commit
160a5684f7
30 changed files with 809 additions and 1024 deletions
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
|
@ -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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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? {
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
27
app/src/main/java/com/vanced/manager/model/ProgressModel.kt
Normal file
27
app/src/main/java/com/vanced/manager/model/ProgressModel.kt
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
Loading…
Reference in a new issue