Merge pull request #22 from YTVanced/dev

Initial release
This commit is contained in:
Paulis Gributs 2020-06-30 22:43:59 +01:00 committed by GitHub
commit ffd7b6153a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
259 changed files with 6415 additions and 1491 deletions

45
.github/workflows/android.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: Signed APK Builder
on:
push:
branches:
- master
- dev
pull_request:
branches:
- master
- dev
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant rights
run: chmod +x ./gradlew
- name: Build project with Gradle
run: ./gradlew build
- name: Build Release APK with Gradle
run: ./gradlew assembleRelease
- name: Sign APK
uses: r0adkll/sign-android-release@v1
id: sign-app
with:
releaseDirectory: app/build/outputs/apk/release
signingKeyBase64: ${{ secrets.TOKEN }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
- name: Upload to GitHub
uses: actions/upload-artifact@v2
with:
name: 'Vanced-Manager'
path: ${{ steps.sign-app.outputs.signedReleaseFile }}

36
.github/workflows/debug.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Debug APK Builder
on:
push:
branches:
- master
- dev
pull_request:
branches:
- master
- dev
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant rights
run: chmod +x ./gradlew
- name: Build project with Gradle
run: ./gradlew build
- name: Build Release APK with Gradle
run: ./gradlew assembleDebug
- name: Upload to GitHub
uses: actions/upload-artifact@v2
with:
name: 'Vanced-Manager'
path: app/build/outputs/apk/debug/app-debug.apk

21
.gitignore vendored
View File

@ -1,14 +1,7 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
.gradle/
.idea/
.github/
build/
out/
app/src/main/java/com/vanced/manager/core/base/DummyJava.java
local.properties

View File

@ -1,122 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,2 +1,21 @@
# VancedInstaller
Vanced Installer
# Vanced Manager
Hi, when we released Vanced 15.05.54, people were upset because it used .apks format, which was way harder to install than a traditional .apk file. even tho we wrote clear instructions on how to install new Vanced, people still couldn't figure it out.
Then we thought, why don't we make a manager for vanced, which will download, update and uninstall Vanced and MicroG, have an easy and understandable UI and be less than 5mb. that's how Vanced Manager was born.
After 3 months of making, we are finally ready to introduce Vanced Manager to you. Vanced manager can easily install and uninstall vanced and microg, has various settings for customisation and better experience. Manager comes with easy-to-use interface, support for background download and installation*
##### *Due to changes in Android Oreo and up, also because of aggressive battery optimisations in some ROMs, feature may not be available for all devices.
## Vanced Developers
- xfileFIN
- KevinX8
- Zanezam
- Laura Almeida
## Vanced Manager Developer
- Xinto (X1nto)
## Credits
- topjohnwu for his wonderful [LibSU](https://github.com/topjohnwu/libsu)
- Mindorks for their amazing [PRDownloader](https://github.com/MindorksOpenOource/PRDownloader)
- aefyr for [SAI](https://github.com/aefyr/SAI), which was inspiration for our Manager
- 100rabhkr for [GetJson](https://github.com/100rabhkr/getjson) library

42
READMEME.md Normal file
View File

@ -0,0 +1,42 @@
![Signed APK Builder](https://github.com/X1nto/VancedInstaller/workflows/Signed%20APK%20Builder/badge.svg?branch=master)
# Prelude
Hi, my name is Steve Cock, I'm the main developer for the upcoming Vanced Manager. When xfileFIN first published Vanced 15.05.54, people were upset because new Vanced used split apk files. The reason for that was pretty simple:
1) YouTube itself does that
2) Split apk files reduce the size of the downloaded file itself
No one really thought there would be problems with this format, because installation was pretty simple, at least that's what xfile thought...
## Problems with .apks format
Main problems with new format were either with device CPU architecture or MemeUI shit with MiUI optimisations. We wrote instructions for VancedHelper but no one used it for troubleshooting. Then some users complained about new format and refused to upgrade to newest version (We don't give a fuck about that) because "I dOn'T WaNT To HaVe OnE MoRE apP To insTalL VanCeD" so we decided to make an installer for Vanced
# Vanced Manager
Ladies and gentlemen, I'm very proud to introduce the new **Vancad Manger 1.0.0™** (typo is intentional)
Vanced Manager is an universal utility for installing/updating Vanced and MicroG. It will push notifications once the update is ready (Now that's what I call pwetty epic).
Vanced manager comes with a slick UI ~~that was stolen from the new Magisk Manager (I'm very sorry John but I looked at your code for about 100 times).~~ Actually, while UI may look very similar to new Magisk Manager's UI, It's still very different (that's a blatant lie, I know).
Main Menu screenshot taken from tablet
![screenshot](https://i.imgur.com/r2jiq7J.png)
Isn't this lovely and beautiful?
## Manager (clap) Reviews (clap)
- 1337Potato: shit
- Response: Yes
- Noobbot: The app is not useful because I have YT Premium. Thank you bye
- Response: I hope you get sucked by a di-
- Vortextriangle: The app is so useful that I uninstalled it after installing Vanced
- Response: yo that's finna woke
## Credits
### Vanced Manager developers
- X1nto (UI, UX, Downloader, Installer, Signature Checker, PussiSlayer69, Collector of 400 BAT, Professional Liar)
### The Vanced Team
- xfileFIN
![xfileFIN](https://i.imgur.com/hLdzTVq.png)
- KevinX8
![KevinX8](https://i.imgur.com/cS9C7P8.png)
- Zanezam
![Zanezam](https://i.imgur.com/QVcXA6q.png)
- Laura Almeida
![Laura Almeida](https://i.imgur.com/ovVD939.png)

19
Vanced Manager.iml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="Vanced Manager" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

234
app/app.iml Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 29
@ -10,25 +11,38 @@ android {
applicationId "com.vanced.manager"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 8
versionName "1.0.0"
vectorDrawables.useSupportLibrary = true
}
lintOptions {
disable 'MissingTranslation', 'ExtraTranslation'
}
aaptOptions {
noCompress 'apk', '.apk'
}
applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
// To inline the bytecode built with JVM target 1.8 into
// bytecode that is being built with JVM target 1.6. (e.g. navArgs)
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@ -42,16 +56,18 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.0.0'
implementation 'androidx.navigation:navigation-ui:2.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.github.100rabhkr:GetJSON:1.0'
implementation 'com.github.topjohnwu.libsu:core:2.5.1'
implementation 'com.mindorks.android:prdownloader:0.6.0'
}

View File

@ -1,24 +0,0 @@
package com.vanced.manager
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.vanced.manager", appContext.packageName)
}
}

View File

@ -1,26 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.vanced.manager">
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:name=".core.App"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
tools:ignore="UnusedAttribute"
tools:replace="android:allowBackup">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
android:name=".ui.core.SplashScreenActivity"
android:label="@string/app_name"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name=".ui.MainActivity"
android:label="@string/app_name" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
<provider
android:authorities="${applicationId}.provider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider" />
</provider>
<service android:name=".core.installer.SplitInstallerService" />
<service android:name=".core.installer.RootSplitInstallerService" />
<service android:name=".core.installer.SplitInstaller" />
<service android:name=".core.installer.AppUninstallerService" />
<service android:name=".core.installer.AppInstallerService" />
<service android:name=".core.installer.AppInstaller" />
<service android:name=".core.downloader.VancedDownloadService" />
<service android:name=".core.downloader.MicrogDownloadService" />
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,26 +0,0 @@
package com.vanced.manager
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.navigation_home)
val navController = findNavController(R.id.mobile_navigation)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_home))
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}

View File

@ -0,0 +1,26 @@
package com.vanced.manager.adapter
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.vanced.manager.ui.fragments.ManagerChangelogFragment
import com.vanced.manager.ui.fragments.MicrogChangelogFragment
import com.vanced.manager.ui.fragments.VancedChangelogFragment
class SectionPageAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
private val fragmentItems = 3
override fun getItemCount(): Int {
return fragmentItems
}
override fun createFragment(position: Int): Fragment {
var fragment: Fragment? = null
when (position) {
0 -> fragment = VancedChangelogFragment()
1 -> fragment = MicrogChangelogFragment()
2 -> fragment = ManagerChangelogFragment()
}
return fragment!!
}
}

View File

@ -0,0 +1,24 @@
package com.vanced.manager.adapter
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.vanced.manager.ui.fragments.ManagerChangelogFragment
import com.vanced.manager.ui.fragments.VancedChangelogFragment
class SectionPageRootAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
private val fragmentItems = 2
override fun getItemCount(): Int {
return fragmentItems
}
override fun createFragment(position: Int): Fragment {
var fragment: Fragment? = null
when (position) {
0 -> fragment = VancedChangelogFragment()
1 -> fragment = ManagerChangelogFragment()
}
return fragment!!
}
}

View File

@ -0,0 +1,15 @@
package com.vanced.manager.core
import android.app.Application
import com.downloader.PRDownloader
import com.vanced.manager.utils.NotificationHelper.createNotifChannel
class App: Application() {
override fun onCreate() {
super.onCreate()
PRDownloader.initialize(applicationContext)
createNotifChannel(this)
}
}

View File

@ -0,0 +1,64 @@
package com.vanced.manager.core
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.ui.dialogs.DialogContainer.showSecurityDialog
import com.vanced.manager.ui.dialogs.DialogContainer.statementFalse
import com.vanced.manager.ui.fragments.UpdateCheckFragment
import com.vanced.manager.utils.InternetTools
import com.vanced.manager.R
import com.vanced.manager.ui.dialogs.DialogContainer.secondMiuiDialog
import com.vanced.manager.ui.dialogs.DialogContainer.showRootDialog
import com.vanced.manager.utils.MiuiHelper.isMiui
import com.vanced.manager.utils.MiuiHelper.isMiuiOptimisationsDisabled
// This activity will NOT be used in manifest
// since MainActivity will extend it
@SuppressLint("Registered")
open class Main: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkUpdates()
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val firstStart = prefs.getBoolean("firstStart", true)
val isUpgrading = prefs.getBoolean("isUpgrading", false)
val variant = prefs.getString("vanced_variant", "nonroot")
val shouldShowRootDialog = prefs.getBoolean("show_root_dialog", true)
val falseStatement = prefs.getBoolean("statement", true)
when {
firstStart -> showSecurityDialog(this)
!falseStatement -> statementFalse(this)
isUpgrading -> prefs.edit().putBoolean("isUpgrading", false).apply()
variant == "root" && shouldShowRootDialog -> showRootDialog(this)
!firstStart && !isMiuiOptimisationsDisabled() -> secondMiuiDialog(this)
}
}
override fun onPause() {
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isInstalling", false).apply()
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isVancedDownloading", false).apply()
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isMicrogDownloading", false).apply()
super.onPause()
}
private fun checkUpdates() {
val checkPrefs = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("auto_check_update", false)
if (checkPrefs) {
if (GetJson().isConnected(this) && InternetTools.isUpdateAvailable()) {
UpdateCheckFragment().show(supportFragmentManager, "Update")
} else Toast.makeText(this, getString(R.string.update_notfound), Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -0,0 +1,7 @@
package com.vanced.manager.core.base
import androidx.fragment.app.Fragment
open class BaseFragment : Fragment() {
}

View File

@ -0,0 +1,84 @@
package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.dezlum.codelabs.getjson.GetJson
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.OnStartOrResumeListener
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.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.NotificationHelper
import com.vanced.manager.utils.NotificationHelper.cancelNotif
import com.vanced.manager.utils.NotificationHelper.createBasicNotif
import java.util.concurrent.ExecutionException
class MicrogDownloadService: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
try {
downloadMicrog()
} catch (e: Exception) {
when (e) {
is ExecutionException, is InterruptedException -> Toast.makeText(this, "Unable to download Vanced", Toast.LENGTH_SHORT).show()
else -> throw e
}
}
stopSelf()
return START_NOT_STICKY
}
private fun downloadMicrog() {
val prefs = getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val apkUrl = GetJson().AsJSONObject("https://x1nto.github.io/VancedFiles/microg.json")
val dwnldUrl = apkUrl.get("url").asString
val channel = 420
PRDownloader.download(dwnldUrl, filesDir.path, "microg.apk")
.build()
.setOnStartOrResumeListener { OnStartOrResumeListener { prefs?.edit()?.putBoolean("isMicrogDownloading", true)?.apply() } }
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
NotificationHelper.displayDownloadNotif(
channel,
mProgress.toInt(),
getFileNameFromUrl(dwnldUrl),
this
)
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
prefs?.edit()?.putBoolean("isMicrogDownloading", false)?.apply()
cancelNotif(channel, this@MicrogDownloadService)
val intent = Intent(this@MicrogDownloadService, AppInstaller::class.java)
intent.putExtra("path", "${filesDir.path}/microg.apk")
intent.putExtra("pkg", "com.mgoogle.android.gms")
val mIntent = Intent(HomeFragment.MICROG_DOWNLOADED)
mIntent.action = HomeFragment.MICROG_DOWNLOADED
LocalBroadcastManager.getInstance(this@MicrogDownloadService).sendBroadcast(mIntent)
startService(intent)
}
override fun onError(error: Error) {
prefs?.edit()?.putBoolean("isMicrogDownloading", false)?.apply()
createBasicNotif(getString(R.string.error_downloading, "Microg"), channel, this@MicrogDownloadService)
}
})
}
override fun onDestroy() {
super.onDestroy()
cancelNotif(420, this)
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -0,0 +1,121 @@
package com.vanced.manager.core.downloader
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
import com.dezlum.codelabs.getjson.GetJson
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.OnStartOrResumeListener
import com.downloader.PRDownloader
import com.vanced.manager.R
import com.vanced.manager.core.installer.RootSplitInstallerService
import com.vanced.manager.core.installer.SplitInstaller
import com.vanced.manager.ui.fragments.HomeFragment
import com.vanced.manager.utils.InternetTools.baseUrl
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
import com.vanced.manager.utils.NotificationHelper.cancelNotif
import com.vanced.manager.utils.NotificationHelper.createBasicNotif
import com.vanced.manager.utils.NotificationHelper.displayDownloadNotif
import java.util.concurrent.ExecutionException
class VancedDownloadService: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
try {
downloadSplits()
} catch (e: Exception) {
when (e) {
is ExecutionException, is InterruptedException -> Toast.makeText(this, "Unable to download Vanced", Toast.LENGTH_SHORT).show()
else -> throw e
}
}
stopSelf()
return START_NOT_STICKY
}
private fun downloadSplits(
type: String = "arch"
) {
val baseUrl = PreferenceManager.getDefaultSharedPreferences(this).getString("install_url", baseUrl)
val vancedVer = GetJson().AsJSONObject("https://x1nto.github.io/VancedFiles/vanced.json").get("version").asString
val prefs = getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val variant = PreferenceManager.getDefaultSharedPreferences(this).getString("vanced_variant", "nonroot")
val lang = prefs?.getString("lang", "en")
val theme = prefs?.getString("theme", "dark")
val arch =
when {
Build.SUPPORTED_ABIS.contains("x86") -> "x86"
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a"
else -> "armeabi_v7a"
}
val url =
when (type) {
"arch" -> "$baseUrl/apks/v$vancedVer/$variant/Config/config.$arch.apk"
"theme" -> "$baseUrl/apks/v$vancedVer/$variant/Theme/$theme.apk"
"lang" -> "$baseUrl/apks/v$vancedVer/$variant/Language/split_config.$lang.apk"
"enlang" -> "$baseUrl/apks/v$vancedVer/$variant/Language/split_config.en.apk"
else -> throw NotImplementedError("This type of APK is NOT valid. What the hell did you even do?")
}
val channel = 69
PRDownloader
.download(url, cacheDir.path, getFileNameFromUrl(url))
.build()
.setOnStartOrResumeListener { OnStartOrResumeListener { prefs?.edit()?.putBoolean("isVancedDownloading", true)?.apply() } }
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
displayDownloadNotif(channel, mProgress.toInt(), getFileNameFromUrl(url), this)
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
when (type) {
"arch" -> downloadSplits("theme")
"theme" -> downloadSplits("lang")
"lang" -> {
if (lang == "en") {
prepareInstall(variant!!)
cancelNotif(channel, this@VancedDownloadService)
} else {
downloadSplits("enlang")
}
}
"enlang" -> {
prepareInstall(variant!!)
cancelNotif(channel, this@VancedDownloadService)
}
}
}
override fun onError(error: Error) {
createBasicNotif(getString(R.string.error_downloading, "Vanced"), channel, this@VancedDownloadService)
}
})
}
private fun prepareInstall(variant: String) {
val intent = Intent(HomeFragment.VANCED_DOWNLOADED)
intent.action = HomeFragment.VANCED_DOWNLOADED
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
if (variant == "root")
startService(Intent(this, RootSplitInstallerService::class.java))
else
startService(Intent(this, SplitInstaller::class.java))
}
override fun onDestroy() {
super.onDestroy()
cancelNotif(69, this)
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -0,0 +1,48 @@
package com.vanced.manager.core.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.widget.Toast
import androidx.preference.PreferenceManager
import com.vanced.manager.core.base.BaseFragment
open class About : BaseFragment() {
private var count = 0
private var startMillSec: Long = 0
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.setOnTouchListener { _, event: MotionEvent ->
val eventAction = event.action
if (eventAction == MotionEvent.ACTION_UP) {
val time = System.currentTimeMillis()
if (startMillSec == 0L || time - startMillSec > 3000) {
startMillSec = time
count = 1
} else {
count++
}
if (count == 5) {
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
val devSettings = prefs.getBoolean("devSettings", false)
if (!devSettings) {
Toast.makeText(requireContext(), "Dev options unlocked!", Toast.LENGTH_SHORT).show()
prefs.edit().putBoolean("devSettings", true).apply()
} else
Toast.makeText(requireContext(), "Dev options already unlocked", Toast.LENGTH_SHORT).show()
}
return@setOnTouchListener true
}
false
}
}
}

View File

@ -0,0 +1,127 @@
package com.vanced.manager.core.fragments
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.*
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.google.android.material.button.MaterialButton
import com.topjohnwu.superuser.Shell
import com.vanced.manager.R
import com.vanced.manager.core.base.BaseFragment
import com.vanced.manager.core.downloader.MicrogDownloadService
import com.vanced.manager.core.downloader.VancedDownloadService
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.ui.dialogs.DialogContainer.secondMiuiDialog
import com.vanced.manager.utils.MiuiHelper
import com.vanced.manager.utils.PackageHelper.uninstallApk
open class Home : BaseFragment(), View.OnClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val microginstallbtn = view.findViewById<MaterialButton>(R.id.microg_installbtn)
val vancedinstallbtn = view.findViewById<MaterialButton>(R.id.vanced_installbtn)
val microguninstallbtn = view.findViewById<ImageView>(R.id.microg_uninstallbtn)
val vanceduninstallbtn = view.findViewById<ImageView>(R.id.vanced_uninstallbtn)
val rootswitch = view.findViewById<MaterialButton>(R.id.root_switch)
val nonrootswitch = view.findViewById<MaterialButton>(R.id.nonroot_switch)
vancedinstallbtn.setOnClickListener(this)
microginstallbtn.setOnClickListener(this)
microguninstallbtn.setOnClickListener(this)
vanceduninstallbtn.setOnClickListener(this)
rootswitch.setOnClickListener(this)
nonrootswitch.setOnClickListener(this)
}
override fun onResume() {
super.onResume()
val prefs = activity?.getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val isInstalling = prefs?.getBoolean("isInstalling", false)
if (isInstalling!!) {
activity?.startService(Intent(activity, VancedDownloadService::class.java))
prefs.edit().putBoolean("isInstalling", false).apply()
}
}
override fun onClick(v: View?) {
val prefs = activity?.getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val defPrefs = getDefaultSharedPreferences(activity)
val isVancedDownloading: Boolean? = prefs?.getBoolean("isVancedDownloading", false)
val isMicrogDownloading: Boolean? = prefs?.getBoolean("isMicrogDownloading", false)
val variant = getDefaultSharedPreferences(activity).getString("vanced_variant", "nonroot")
val vancedPkgName =
if (variant == "root") {
"com.google.android.youtube"
} else {
"com.vanced.android.youtube"
}
when (v?.id) {
R.id.vanced_installbtn -> {
if (!isVancedDownloading!!) {
try {
activity?.cacheDir?.deleteRecursively()
} catch (e: Exception) {
Log.d("VMCache", "Unable to delete cacheDir")
}
if (prefs.getBoolean("valuesModified", false)) {
activity?.startService(
Intent(
activity,
VancedDownloadService::class.java
)
)
} else {
view?.findNavController()?.navigate(R.id.toInstallThemeFragment)
}
} else {
Toast.makeText(
activity,
"Please wait until installation finishes",
Toast.LENGTH_SHORT
).show()
}
}
R.id.microg_installbtn -> {
if (!isMicrogDownloading!!) {
try {
activity?.startService(Intent(activity, MicrogDownloadService::class.java))
} catch (e: Exception) {
Toast.makeText(activity, "Unable to start installation", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(activity, "Please wait until installation finishes", Toast.LENGTH_SHORT).show()
}
}
R.id.microg_uninstallbtn -> activity?.let { uninstallApk("com.mgoogle.android.gms", it) }
R.id.vanced_uninstallbtn -> activity?.let { uninstallApk(vancedPkgName, it) }
R.id.nonroot_switch -> writeToVariantPref("nonroot", R.anim.slide_in_left, R.anim.slide_out_right)
R.id.root_switch ->
if (Shell.rootAccess())
writeToVariantPref("root", R.anim.slide_in_right, R.anim.slide_out_left)
else {
writeToVariantPref("nonroot", R.anim.slide_in_left, R.anim.slide_out_right)
Toast.makeText(activity, "Root access not granted", Toast.LENGTH_SHORT).show()
}
}
}
private fun writeToVariantPref(variant: String, animIn: Int, animOut: Int) {
val prefs = getDefaultSharedPreferences(activity)
if (prefs.getString("vanced_variant", "nonroot") != variant) {
prefs.edit().putString("vanced_variant", variant).apply()
startActivity(Intent(activity, MainActivity::class.java))
activity?.overridePendingTransition(animIn, animOut)
activity?.finish()
} else Log.d("VMvariant", "$variant is already selected")
}
}

View File

@ -0,0 +1,37 @@
package com.vanced.manager.core.fragments
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.RadioButton
import android.widget.RadioGroup
import androidx.navigation.findNavController
import com.vanced.manager.R
import com.vanced.manager.core.base.BaseFragment
open class LanguageInstall : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val finishButton = view.findViewById<Button>(R.id.vanced_install_finish)
val langGroup = view.findViewById<RadioGroup>(R.id.lang_radiogroup)
val prefs = activity?.getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val langPref = prefs?.getString("lang", "en")
val button = langGroup.findViewWithTag<RadioButton>(langPref)
button.isChecked = true
finishButton.setOnClickListener {
val selectedLangId = langGroup.checkedRadioButtonId
val selectedButton = view.findViewById<RadioButton>(selectedLangId)
prefs?.edit()?.putString("lang", selectedButton.tag.toString())?.apply()
prefs?.edit()?.putBoolean("isInstalling", true)?.apply()
prefs?.edit()?.putBoolean("valuesModified", true)?.apply()
view.findNavController().navigate(R.id.action_installTo_homeFragment)
}
}
}

View File

@ -0,0 +1,32 @@
package com.vanced.manager.core.fragments
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.navigation.findNavController
import com.vanced.manager.R
import com.vanced.manager.core.base.BaseFragment
open class ThemeInstall : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val nextButton = view.findViewById<Button>(R.id.vanced_next_to_variant)
val themeGroup = view.findViewById<RadioGroup>(R.id.theme_radiogroup)
val prefs = activity?.getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
val themePref = prefs?.getString("theme", "dark")
val button = themeGroup.findViewWithTag<RadioButton>(themePref)
button.isChecked = true
nextButton.setOnClickListener {
val selectedThemeId = themeGroup.checkedRadioButtonId
val selectedButton = view.findViewById<RadioButton>(selectedThemeId)
prefs?.edit()?.putString("theme", selectedButton.tag.toString())?.apply()
view.findNavController().navigate(R.id.toInstallLanguageFragment)
}
}
}

View File

@ -0,0 +1,38 @@
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 callbackIntent = Intent(applicationContext, AppInstallerService::class.java)
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)
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -0,0 +1,93 @@
package com.vanced.manager.core.installer
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.annotation.Nullable
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.utils.MiuiHelper
import com.vanced.manager.utils.NotificationHelper
import com.vanced.manager.utils.NotificationHelper.createBasicNotif
class AppInstallerService: Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val notifId = 42
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Toast.makeText(this, "Installing...", Toast.LENGTH_SHORT).show()
Log.d(TAG, "Requesting user confirmation for installation")
createBasicNotif(getString(R.string.installing_app, "MicroG"), notifId, this)
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
}
}
PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed")
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isInstalling", false).apply()
val mIntent = Intent(MainActivity.INSTALL_COMPLETED)
mIntent.action = MainActivity.INSTALL_COMPLETED
mIntent.putExtra("package", "normal")
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
createBasicNotif(getString(
R.string.successfully_installed,
"Microg"
), notifId, this)
}
else -> {
sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999))
createBasicNotif(
getErrorMessage(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)),
notifId,
this
)
}
}
stopSelf()
return START_NOT_STICKY
}
private fun sendFailure(status: Int) {
val mIntent = Intent(MainActivity.INSTALL_FAILED)
mIntent.action = MainActivity.INSTALL_FAILED
mIntent.putExtra("errorMsg", getErrorMessage(status))
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
}
private fun getErrorMessage(status: Int): String {
return when (status) {
PackageInstaller.STATUS_FAILURE_ABORTED -> getString(R.string.installation_aborted)
PackageInstaller.STATUS_FAILURE_BLOCKED -> getString(R.string.installation_blocked)
PackageInstaller.STATUS_FAILURE_STORAGE -> getString(R.string.installation_storage)
PackageInstaller.STATUS_FAILURE_INVALID -> getString(R.string.installation_invalid)
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> getString(R.string.installation_incompatible)
PackageInstaller.STATUS_FAILURE_CONFLICT -> getString(R.string.installation_conflict)
else ->
if (MiuiHelper.isMiui())
getString(R.string.installation_miui)
else
getString(R.string.installation_failed)
}
}
@Nullable
override fun onBind(intent: Intent?): IBinder? {
return null
}
companion object{
const val TAG = "VMInstall"
}
}

View File

@ -0,0 +1,52 @@
package com.vanced.manager.core.installer
import android.app.Service
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Handler
import android.os.IBinder
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.ui.MainActivity
class AppUninstallerService: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val pkgName = intent?.getStringExtra("pkg")
when (intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d(AppInstallerService.TAG, "Requesting user confirmation for uninstallation")
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
}
}
PackageInstaller.STATUS_SUCCESS -> {
Handler().postDelayed({
val mIntent = Intent()
mIntent.action = MainActivity.APP_UNINSTALLED
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
Log.d("VMpm", "Successfully uninstalled $pkgName")
}, 500)
}
PackageInstaller.STATUS_FAILURE -> {
Handler().postDelayed({
val mIntent = Intent()
mIntent.action = MainActivity.APP_NOT_UNINSTALLED
mIntent.putExtra("pkgName", pkgName)
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
Log.d("VMpm", "Failed to uninstall $pkgName")
}, 500)
}
}
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@ -0,0 +1,144 @@
package com.vanced.manager.core.installer
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
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 com.topjohnwu.superuser.Shell
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.utils.FileInfo
import com.vanced.manager.utils.NotificationHelper.createBasicNotif
import java.io.File
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList
class RootSplitInstallerService: Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Shell.getShell {
val isRoot = it.isRoot
Log.d("AppLog", "isRoot ?$isRoot ")
AsyncTask.execute {
val apkFilesPath = cacheDir.path
val fileInfoList = getFileInfoList(apkFilesPath)
installSplitApkFiles(fileInfoList)
}
}
stopSelf()
return START_NOT_STICKY
}
@WorkerThread
private fun installSplitApkFiles(apkFiles: ArrayList<FileInfo>) {
var sessionId: Int?
val notifId = 666
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)!!)
}
for (apkFile in apkFiles) {
Log.d("AppLog", "installing APK : ${apkFile.name} ${apkFile.fileSize} ")
createBasicNotif(getString(R.string.installing_app, "Vanced"), notifId, this)
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: java.lang.Exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
process.destroyForcibly()
else
process.destroy()
throw RuntimeException(e)
}
process.waitFor()
val inputStr = process.inputStream.readBytes().toString(Charset.defaultCharset())
val errStr = process.errorStream.readBytes().toString(Charset.defaultCharset())
val isSucceeded = process.exitValue() == 0
Log.d("AppLog", "isSucceeded?$isSucceeded inputStr:$inputStr errStr:$errStr")
}
Log.d("AppLog", "committing...")
val installResult = Shell.su("pm install-commit $sessionId").exec()
Log.d("AppLog", "succeeded installing?${installResult.isSuccess}")
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isInstalling", false).apply()
if (installResult.isSuccess) {
val mIntent = Intent(MainActivity.INSTALL_COMPLETED)
mIntent.action = MainActivity.INSTALL_COMPLETED
mIntent.putExtra("package", "split")
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
createBasicNotif(getString(R.string.successfully_installed, "Vanced"), notifId, this)
} else {
val mIntent = Intent(MainActivity.INSTALL_FAILED)
mIntent.action = MainActivity.INSTALL_FAILED
mIntent.putExtra("errorMsg", getString(R.string.installation_signature))
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
createBasicNotif(getString(R.string.installation_signature), notifId, this)
}
}
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
}
}

View File

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

View File

@ -0,0 +1,111 @@
package com.vanced.manager.core.installer
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.annotation.Nullable
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.utils.MiuiHelper.isMiui
import com.vanced.manager.utils.NotificationHelper.createBasicNotif
class SplitInstallerService: Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val notifId = 666
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Toast.makeText(this, "Installing...", Toast.LENGTH_SHORT).show()
createBasicNotif(getString(R.string.installing_app, "Vanced"), notifId, this)
Log.d(TAG, "Requesting user confirmation for installation")
val confirmationIntent =
intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
}
}
PackageInstaller.STATUS_SUCCESS -> {
Log.d(TAG, "Installation succeed")
getSharedPreferences("installPrefs", Context.MODE_PRIVATE).edit().putBoolean("isInstalling", false).apply()
val mIntent = Intent(MainActivity.INSTALL_COMPLETED)
mIntent.action = MainActivity.INSTALL_COMPLETED
mIntent.putExtra("package", "split")
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
createBasicNotif(
getString(R.string.successfully_installed, "Vanced"),
notifId,
this
)
}
else -> {
sendFailure(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999))
createBasicNotif(
getErrorMessage(intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)),
notifId,
this
)
}
}
stopSelf()
return START_NOT_STICKY
}
private fun sendFailure(status: Int) {
val mIntent = Intent(MainActivity.INSTALL_FAILED)
mIntent.action = MainActivity.INSTALL_FAILED
mIntent.putExtra("errorMsg", getErrorMessage(status))
LocalBroadcastManager.getInstance(this).sendBroadcast(mIntent)
}
private fun getErrorMessage(status: Int): String {
return when (status) {
PackageInstaller.STATUS_FAILURE_ABORTED -> getString(R.string.installation_aborted)
PackageInstaller.STATUS_FAILURE_BLOCKED -> getString(R.string.installation_blocked)
PackageInstaller.STATUS_FAILURE_STORAGE -> getString(R.string.installation_storage)
PackageInstaller.STATUS_FAILURE_INVALID -> getString(R.string.installation_invalid)
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> getString(R.string.installation_incompatible)
PackageInstaller.STATUS_FAILURE_CONFLICT -> getString(R.string.installation_conflict)
else ->
if (isMiui())
getString(R.string.installation_miui)
else
getString(R.string.installation_failed)
}
}
private fun startForegroundNotif(text: String) {
val notifBuilder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
Notification.Builder(this, 666.toString()).setChannelId("69420")
else
Notification.Builder(this).setPriority(Notification.PRIORITY_DEFAULT)
notifBuilder.apply {
setContentTitle(getString(R.string.app_name))
setContentText(text)
setSmallIcon(R.drawable.ic_stat_name)
}
val notif = notifBuilder.build()
startForeground(666, notif)
}
@Nullable
override fun onBind(intent: Intent?): IBinder? {
return null
}
companion object{
const val TAG = "VMInstall"
}
}

View File

@ -0,0 +1,140 @@
package com.vanced.manager.ui
import android.content.*
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import androidx.databinding.DataBindingUtil
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.NavDestination
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.google.android.material.appbar.MaterialToolbar
import com.vanced.manager.R
import com.vanced.manager.core.Main
import com.vanced.manager.databinding.ActivityMainBinding
import com.vanced.manager.ui.dialogs.DialogContainer.installAlertBuilder
import com.vanced.manager.ui.dialogs.DialogContainer.launchVanced
import com.vanced.manager.ui.dialogs.DialogContainer.regularPackageInstalled
import com.vanced.manager.utils.ThemeHelper.setFinalTheme
class MainActivity : Main() {
private var isParent = true
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
setFinalTheme(this)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this
val toolbar: MaterialToolbar = findViewById(R.id.home_toolbar)
setSupportActionBar(toolbar)
val navHost = findNavController(R.id.bottom_nav_host)
val appBarConfiguration = AppBarConfiguration(navHost.graph)
toolbar.setupWithNavController(navHost, appBarConfiguration)
navHost.addOnDestinationChangedListener{_, currFrag: NavDestination, _ ->
isParent = when (currFrag.id) {
R.id.home_fragment -> true
else -> false
}
setDisplayHomeAsUpEnabled(!isParent)
}
registerReceivers()
}
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
INSTALL_COMPLETED -> {
if (intent.getStringExtra("package") == "split")
launchVanced(this@MainActivity)
else
regularPackageInstalled(getString(R.string.microg_installed), this@MainActivity)
}
INSTALL_FAILED -> installAlertBuilder(intent.getStringExtra("errorMsg") as String, this@MainActivity)
APP_UNINSTALLED -> {
restartActivity()
Log.d("VMpm", "test")
}
APP_NOT_UNINSTALLED -> installAlertBuilder(getString(R.string.failed_uninstall) + intent.getStringExtra("pkgName"), this@MainActivity)
}
}
}
override fun onPause() {
super.onPause()
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver)
}
override fun onResume() {
setFinalTheme(this)
super.onResume()
registerReceivers()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val navHost = findNavController(R.id.bottom_nav_host)
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
R.id.toolbar_about -> {
navHost.navigate(R.id.toAboutFragment)
return true
}
R.id.toolbar_settings -> {
navHost.navigate(R.id.action_settingsFragment)
return true
}
R.id.dev_settings -> {
navHost.navigate(R.id.toDevSettingsFragment)
return true
}
else -> super.onOptionsItemSelected(item)
}
return false
}
private fun setDisplayHomeAsUpEnabled(isNeeded: Boolean) {
val toolbar: MaterialToolbar = findViewById(R.id.home_toolbar)
when {
isNeeded -> toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp)
else -> toolbar.navigationIcon = null
}
}
private fun registerReceivers() {
val intentFilter = IntentFilter()
intentFilter.addAction(INSTALL_COMPLETED)
intentFilter.addAction(INSTALL_FAILED)
intentFilter.addAction(APP_UNINSTALLED)
intentFilter.addAction(APP_NOT_UNINSTALLED)
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter)
}
fun restartActivity() {
startActivity(Intent(this@MainActivity, MainActivity::class.java))
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
finish()
}
companion object {
const val INSTALL_COMPLETED = "Installation completed"
const val INSTALL_FAILED = "it just failed idk"
const val APP_UNINSTALLED = "App uninstalled"
const val APP_NOT_UNINSTALLED = "App not uninstalled"
}
}

View File

@ -0,0 +1,32 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.widget.ConstraintLayout
open class SlidingConstraintLayout : ConstraintLayout {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(
context,
attrs
)
var xFraction: Float
get() {
val width = width
return if (width != 0)
x / getWidth()
else
x
}
set(xFraction) {
val width = width
val newWidth =
if (width > 0)
xFraction * width
else
(1).toFloat()
x = newWidth
}
}

View File

@ -0,0 +1,33 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
open class SlidingLinearLayout: LinearLayout {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(
context,
attrs
)
var yFraction: Float
get() {
val height = height
return if (height != 0)
y / height
else
y
}
set(yFraction) {
val height = height
val newHeight =
if (height > 0)
yFraction * height
else
(1).toFloat()
y = newHeight
}
}

View File

@ -0,0 +1,31 @@
package com.vanced.manager.ui.core
import android.content.Context
import android.util.AttributeSet
import androidx.core.widget.NestedScrollView
open class SlidingNestedScrollView : NestedScrollView {
constructor(context: Context?) : super(context!!)
constructor(context: Context?, attrs: AttributeSet?) : super(
context!!,
attrs
)
var xFraction: Float
get() {
val width = width
return if (width != 0)
x / getWidth()
else
x
}
set(xFraction) {
val width = width
val newWidth =
if (width > 0)
xFraction * width
else
(1).toFloat()
x = newWidth
}
}

View File

@ -0,0 +1,18 @@
package com.vanced.manager.ui.core
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
class SplashScreenActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.SplashTheme)
super.onCreate(savedInstanceState)
startActivity(Intent(this@SplashScreenActivity, MainActivity::class.java))
finish()
}
}

View File

@ -1,31 +0,0 @@
package com.vanced.manager.ui.dashboard
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.vanced.manager.R
class DashboardFragment : Fragment() {
private lateinit var dashboardViewModel: DashboardViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
dashboardViewModel =
ViewModelProviders.of(this).get(DashboardViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_dashboard, container, false)
val textView: TextView = root.findViewById(R.id.text_dashboard)
dashboardViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}

View File

@ -1,13 +0,0 @@
package com.vanced.manager.ui.dashboard
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class DashboardViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is dashboard Fragment"
}
val text: LiveData<String> = _text
}

View File

@ -0,0 +1,140 @@
package com.vanced.manager.ui.dialogs
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat.startActivity
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import com.vanced.manager.R
import com.vanced.manager.core.downloader.VancedDownloadService
import com.vanced.manager.ui.MainActivity
import com.vanced.manager.utils.InternetTools.openUrl
import com.vanced.manager.utils.MiuiHelper
object DialogContainer {
fun showSecurityDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.welcome))
.setMessage(context.resources.getString(R.string.security_context))
.setCancelable(false)
.setPositiveButton(context.resources.getString(R.string.close)) { dialog, _ ->
run {
dialog.dismiss()
if (MiuiHelper.isMiui()) {
showMiuiDialog(context)
}
}
}
.create()
.show()
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit().putBoolean("firstStart", false).apply()
}
private fun showMiuiDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.miui_one_title))
.setMessage(context.getString(R.string.miui_one))
.setPositiveButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
.setNeutralButton(context.getString(R.string.guide)) { _, _ ->
openUrl("https://telegra.ph/How-to-install-v15-on-MIUI-02-11", R.color.Telegram, context)
}
.create()
.show()
}
fun showRootDialog(activity: Activity) {
AlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.hold_on))
.setMessage(activity.getString(R.string.disable_signature))
.setPositiveButton(activity.getString(R.string.button_dismiss)) { dialog, _ ->
dialog.dismiss()
PreferenceManager.getDefaultSharedPreferences(activity).edit().putBoolean("show_root_dialog", false).apply()
}
.setNeutralButton(activity.getString(R.string.guide)) { _, _ ->
openUrl("https://lmgtfy.com/?q=andnixsh+apk+verification+disable", R.color.Twitter, activity)
}
.create()
.show()
}
fun secondMiuiDialog(context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.miui_two_title))
.setMessage(context.getString(R.string.miui_two))
.setPositiveButton(context.getString(R.string.button_fine)) { dialog, _ ->
dialog.dismiss()
}
.setNeutralButton(context.getString(R.string.guide)) { _, _ ->
openUrl("https://telegra.ph/How-to-install-v15-on-MIUI-02-11", R.color.Telegram, context)
}
.create()
.show()
}
//Easter Egg
fun statementFalse(context: Context) {
AlertDialog.Builder(context)
.setTitle("Wait what?")
.setMessage("So this statement is false huh? I'll go with True!")
.setPositiveButton("wut?") { dialog, _ -> dialog.dismiss() }
.create()
.show()
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
prefs.edit().putBoolean("statement", true).apply()
}
fun installAlertBuilder(msg: String, context: Context) {
AlertDialog.Builder(context)
.setTitle(context.getString(R.string.error))
.setMessage(msg)
.setPositiveButton(context.getString(R.string.close)) { dialog, _ -> dialog.dismiss() }
.create()
.show()
}
fun regularPackageInstalled(msg: String, activity: MainActivity) {
AlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.success))
.setMessage(msg)
.setPositiveButton(activity.getString(R.string.close)) { _, _ -> activity.restartActivity() }
.setCancelable(false)
.create()
.show()
}
fun launchVanced(activity: MainActivity) {
val intent = Intent()
intent.component =
if (PreferenceManager.getDefaultSharedPreferences(activity).getString("vanced_variant", "nonroot") == "root")
ComponentName("com.google.android.youtube", "com.google.android.youtube.HomeActivity")
else
ComponentName("com.vanced.android.youtube", "com.google.android.youtube.HomeActivity")
AlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.success))
.setMessage(activity.getString(R.string.vanced_installed))
.setPositiveButton(activity.getString(R.string.launch)) { _, _ ->
run {
startActivity(activity, intent, null)
activity.finish()
}
}
.setNegativeButton(activity.getString(R.string.close)) { dialog, _ ->
run {
dialog.dismiss()
activity.restartActivity()
}
}
.setCancelable(false)
.create()
.show()
}
}

View File

@ -0,0 +1,34 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels
import com.vanced.manager.R
import com.vanced.manager.core.fragments.About
import com.vanced.manager.databinding.FragmentAboutBinding
import com.vanced.manager.ui.viewmodels.AboutViewModel
class AboutFragment : About() {
private lateinit var binding: FragmentAboutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.title = getString(R.string.title_about)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_about, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val viewModel: AboutViewModel by viewModels()
binding.viewModel = viewModel
}
}

View File

@ -0,0 +1,56 @@
package com.vanced.manager.ui.fragments
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.DialogFragment
import com.vanced.manager.R
class ChosenPreferenceDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (dialog != null && dialog?.window != null) {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
return inflater.inflate(R.layout.fragment_chosen_preferences, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val closebtn = view.findViewById<Button>(R.id.chosen_prefs_close)
val resetbtn = view.findViewById<Button>(R.id.chosen_prefs_reset)
val themetxt = view.findViewById<TextView>(R.id.chosen_theme)
val langtxt = view.findViewById<TextView>(R.id.chosen_lang)
val prefs = activity?.getSharedPreferences("installPrefs", Context.MODE_PRIVATE)
themetxt.text = activity?.getString(R.string.chosen_theme, prefs?.getString("theme", "dark"))
langtxt.text = activity?.getString(R.string.chosen_lang, prefs?.getString("lang", "en"))
closebtn.setOnClickListener { dismiss() }
resetbtn.setOnClickListener {
prefs?.edit()?.putString("theme", "dark")?.apply()
prefs?.edit()?.putString("lang", "en")?.apply()
prefs?.edit()?.putBoolean("valuesModified", false)?.apply()
dismiss()
}
}
}

View File

@ -0,0 +1,49 @@
package com.vanced.manager.ui.fragments
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
class DevSettingsFragment: PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.dev_settings, rootKey)
val ftSwitch: Preference? = findPreference("firststart_switch")
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
ftSwitch?.setOnPreferenceClickListener {
AlertDialog.Builder(requireContext())
.setTitle("FirstStart activated")
.setMessage("boolean will be activated on next app start")
.setPositiveButton("Restart") { _, _ ->
run {
startActivity(Intent(requireContext(), MainActivity::class.java))
activity?.finish()
}
}
.create()
.show()
prefs.edit().putBoolean("firstStart", true).apply()
true
}
val archPref: Preference? = findPreference("device_arch")
val supportedAbis: Array<String> = Build.SUPPORTED_ABIS
if (supportedAbis.contains("arm64-v8a") || supportedAbis.contains("x86_64")) {
archPref?.summary = "64bit"
} else {
archPref?.summary = "32bit"
}
}
}

View File

@ -0,0 +1,165 @@
package com.vanced.manager.ui.fragments
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.Animation
import android.view.animation.RotateAnimation
import android.widget.*
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.vanced.manager.R
import com.vanced.manager.adapter.SectionPageAdapter
import com.vanced.manager.adapter.SectionPageRootAdapter
import com.vanced.manager.core.fragments.Home
import com.vanced.manager.databinding.FragmentHomeBinding
import com.vanced.manager.ui.viewmodels.HomeViewModel
import com.vanced.manager.utils.PackageHelper.installApp
class HomeFragment : Home() {
private lateinit var binding: FragmentHomeBinding
private var isExpanded: Boolean = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.title = getString(R.string.title_home)
setHasOptionsMenu(true)
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val viewModel: HomeViewModel by viewModels()
binding.viewModel = viewModel
val variantPref = getDefaultSharedPreferences(activity).getString("vanced_variant", "nonroot")
registerReceivers()
if (variantPref == "root")
attachRootChangelog()
else {
attachNonrootChangelog()
if (!viewModel.microgInstalled) {
disableVancedButton()
}
}
view.findViewById<ImageButton>(R.id.changelog_button).setOnClickListener {
cardExpandCollapse()
}
}
private fun cardExpandCollapse() {
val viewPagerContainer = view?.findViewById<ViewPager2>(R.id.viewpager)
val tabLayoutContainer = view?.findViewById<TabLayout>(R.id.tablayout)
val arrow = view?.findViewById<ImageButton>(R.id.changelog_button)
if (isExpanded) {
viewPagerContainer?.visibility = View.GONE
tabLayoutContainer?.visibility = View.GONE
isExpanded = false
arrow?.animate()?.rotation(0F)?.interpolator = AccelerateDecelerateInterpolator()
} else {
viewPagerContainer?.visibility = View.VISIBLE
tabLayoutContainer?.visibility = View.VISIBLE
isExpanded = true
arrow?.animate()?.rotation(180F)?.interpolator = AccelerateDecelerateInterpolator()
}
}
override fun onPause() {
super.onPause()
activity?.let { LocalBroadcastManager.getInstance(it).unregisterReceiver(broadcastReceiver) }
}
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
MICROG_DOWNLOADED -> {
view?.findViewById<ProgressBar>(R.id.microg_installing)?.visibility = View.VISIBLE
activity?.let { installApp(it, it.filesDir.path + "/microg.apk", "com.mgoogle.android.gms") }
}
VANCED_DOWNLOADED -> {
view?.findViewById<ProgressBar>(R.id.vanced_installing)?.visibility = View.VISIBLE
}
}
}
}
private fun registerReceivers() {
val intentFilter = IntentFilter()
intentFilter.addAction(VANCED_DOWNLOADED)
intentFilter.addAction(MICROG_DOWNLOADED)
activity?.let {
LocalBroadcastManager.getInstance(it).registerReceiver(broadcastReceiver, intentFilter)
}
}
private fun attachNonrootChangelog() {
val sectionPageAdapter = SectionPageAdapter(this)
val tabLayout = view?.findViewById(R.id.tablayout) as TabLayout
val viewPager = view?.findViewById(R.id.viewpager) as ViewPager2
viewPager.adapter = sectionPageAdapter
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
when (position) {
0 -> tab.text = "Vanced"
1 -> tab.text = "MicroG"
2 -> tab.text = "Manager"
}
}.attach()
}
private fun attachRootChangelog() {
val sectionPageRootAdapter = SectionPageRootAdapter(this)
val tabLayout = view?.findViewById(R.id.tablayout) as TabLayout
val viewPager = view?.findViewById(R.id.viewpager) as ViewPager2
viewPager.adapter = sectionPageRootAdapter
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
when (position) {
0 -> tab.text = "Vanced"
1 -> tab.text = "Manager"
}
}.attach()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.toolbar_menu, menu)
super .onCreateOptionsMenu(menu, inflater)
}
private fun disableVancedButton() {
val vancedinstallbtn = view?.findViewById<MaterialButton>(R.id.vanced_installbtn)
vancedinstallbtn?.isEnabled = false
vancedinstallbtn?.backgroundTintList = ColorStateList.valueOf(Color.DKGRAY)
vancedinstallbtn?.setTextColor(ColorStateList.valueOf(Color.GRAY))
vancedinstallbtn?.icon = null
}
companion object {
const val VANCED_DOWNLOADED = "Vanced downloaded"
const val MICROG_DOWNLOADED = "MicroG downloaded"
}
}

View File

@ -0,0 +1,32 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.R
class ManagerChangelogFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_manager_changelog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val changelogTxt = view.findViewById<TextView>(R.id.manager_changelog)
if (GetJson().isConnected(activity)) {
val checkUrl = GetJson().AsJSONObject("https://vanced.app/api/v1/manager.json")
val changelog = checkUrl.get("changelog").asString
changelogTxt.text = changelog
}
}
}

View File

@ -0,0 +1,32 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.R
class MicrogChangelogFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_microg_changelog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val changelogTxt = view.findViewById<TextView>(R.id.microg_changelog)
if (GetJson().isConnected(activity)) {
val checkUrl = GetJson().AsJSONObject("https://x1nto.github.io/VancedFiles/microg.json")
val changelog = checkUrl.get("changelog").asString
changelogTxt.text = changelog
}
}
}

View File

@ -0,0 +1,67 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import androidx.preference.*
import com.vanced.manager.R
import com.vanced.manager.utils.MiuiHelper.isMiui
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
activity?.title = getString(R.string.title_settings)
setHasOptionsMenu(true)
val updateCheck: Preference? = findPreference("update_check")
updateCheck?.setOnPreferenceClickListener {
val fm = childFragmentManager.beginTransaction()
val updateDialog = UpdateCheckFragment()
updateDialog.show(fm, "Update Center")
true
}
val themeSwitch: ListPreference? = findPreference("theme_mode")
themeSwitch?.summary =
preferenceScreen.sharedPreferences.getString("theme_mode", "Follow System")
themeSwitch?.setOnPreferenceChangeListener { _, _ ->
activity?.recreate()
true
}
val accentSwitch: ListPreference? = findPreference("accent_color")
accentSwitch?.summary = preferenceScreen.sharedPreferences.getString("accent_color", "Blue")
accentSwitch?.setOnPreferenceChangeListener { _, _ ->
activity?.recreate()
true
}
val chosenPrefs: Preference? = findPreference("vanced_chosen_modes")
chosenPrefs?.setOnPreferenceClickListener {
val fm = childFragmentManager.beginTransaction()
val chosenPrefsDialog = ChosenPreferenceDialogFragment()
chosenPrefsDialog.show(fm, "Chosen Preferences")
true
}
val installUrl: Preference? = findPreference("install_url")
installUrl?.setOnPreferenceClickListener {
val fm = childFragmentManager.beginTransaction()
val chosenPrefsDialog = URLChangeFragment()
chosenPrefsDialog.show(fm, "Install URL")
true
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val devSettings = PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("devSettings", false)
if (devSettings) {
inflater.inflate(R.menu.dev_settings_menu, menu)
}
super .onCreateOptionsMenu(menu, inflater)
}
}

View File

@ -0,0 +1,43 @@
package com.vanced.manager.ui.fragments
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import com.google.android.material.button.MaterialButton
import com.vanced.manager.R
import com.vanced.manager.utils.InternetTools.baseUrl
class URLChangeFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (dialog != null && dialog?.window != null) {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
return inflater.inflate(R.layout.fragment_custom_url, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val urlField = view.findViewById<EditText>(R.id.url_input)
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
urlField.hint = prefs.getString("install_url", baseUrl)
view.findViewById<MaterialButton>(R.id.url_save).setOnClickListener {
prefs.edit().putString("install_url", urlField.text.toString()).apply()
dismiss()
}
view.findViewById<MaterialButton>(R.id.url_reset).setOnClickListener {
prefs.edit().putString("install_url", baseUrl).apply()
dismiss()
}
}
}

View File

@ -0,0 +1,101 @@
package com.vanced.manager.ui.fragments
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import com.dezlum.codelabs.getjson.GetJson
import androidx.preference.PreferenceManager
import com.downloader.Error
import com.downloader.OnDownloadListener
import com.downloader.PRDownloader
import com.google.android.material.button.MaterialButton
import com.vanced.manager.BuildConfig
import com.vanced.manager.R
import com.vanced.manager.utils.InternetTools.isUpdateAvailable
import com.vanced.manager.utils.PackageHelper.installApp
class UpdateCheckFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (dialog != null && dialog?.window != null) {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
return inflater.inflate(R.layout.fragment_update_check, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkUpdates()
view.findViewById<Button>(R.id.update_center_dismiss).setOnClickListener { dismiss() }
view.findViewById<MaterialButton>(R.id.update_center_recheck).setOnClickListener{ checkUpdates() }
}
private fun checkUpdates() {
val updatebtn = view?.findViewById<Button>(R.id.update_center_update)
val checkingTxt = view?.findViewById<TextView>(R.id.update_center_checking)
if (GetJson().isConnected(requireContext())) {
if (isUpdateAvailable()) {
view?.findViewById<Button>(R.id.update_center_recheck)?.visibility = View.GONE
checkingTxt?.text = getString(R.string.update_found)
updatebtn?.setOnClickListener {
upgradeManager()
}
} else checkingTxt?.text = getString(R.string.update_notfound)
} else {
checkingTxt?.text = getString(R.string.network_error)
}
}
private fun upgradeManager() {
val dwnldUrl = "https://github.com/VancedManager/releases/latest/download/manager.apk"
val loadBar = view?.findViewById<ProgressBar>(R.id.update_center_progressbar)
PRDownloader.download(dwnldUrl, activity?.filesDir?.path, "manager.apk")
.build()
.setOnProgressListener { progress ->
val mProgress = progress.currentBytes * 100 / progress.totalBytes
loadBar?.visibility = View.VISIBLE
loadBar?.progress = mProgress.toInt()
}
.start(object : OnDownloadListener{
override fun onDownloadComplete() {
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
prefs.getBoolean("isUpgrading", false)
prefs.edit().putBoolean("isUpgrading", true).apply()
activity?.let {
installApp(
it,
it.filesDir.path + "/manager.apk",
"com.vanced.manager")
}
}
override fun onError(error: Error?) {
Toast.makeText(activity, error.toString(), Toast.LENGTH_SHORT).show()
Log.e("VMUpgrade", error.toString())
}
})
}
}

View File

@ -0,0 +1,34 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.R
class VancedChangelogFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_vanced_changelog, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val changelogTxt = view.findViewById<TextView>(R.id.vanced_changelog)
if (GetJson().isConnected(activity)) {
val checkUrl = GetJson().AsJSONObject("https://vanced.app/api/v1/changelog/15_05_54.json")
val changelog = checkUrl.get("message").asString
changelogTxt.text = changelog
}
}
}

View File

@ -0,0 +1,20 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.vanced.manager.R
import com.vanced.manager.core.fragments.LanguageInstall
class VancedLanguageSelectionFragment : LanguageInstall() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.title = getString(R.string.title_install)
return inflater.inflate(R.layout.fragment_vanced_language_selection, container, false)
}
}

View File

@ -0,0 +1,20 @@
package com.vanced.manager.ui.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.vanced.manager.R
import com.vanced.manager.core.fragments.ThemeInstall
class VancedThemeSelectionFragment : ThemeInstall() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
activity?.title = getString(R.string.title_install)
return inflater.inflate(R.layout.fragment_vanced_theme_selection, container, false)
}
}

View File

@ -1,31 +0,0 @@
package com.vanced.manager.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.vanced.manager.R
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
homeViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}

View File

@ -1,13 +0,0 @@
package com.vanced.manager.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class HomeViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
}

View File

@ -1,31 +0,0 @@
package com.vanced.manager.ui.notifications
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.vanced.manager.R
class NotificationsFragment : Fragment() {
private lateinit var notificationsViewModel: NotificationsViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
notificationsViewModel =
ViewModelProviders.of(this).get(NotificationsViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_notifications, container, false)
val textView: TextView = root.findViewById(R.id.text_notifications)
notificationsViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}

View File

@ -1,13 +0,0 @@
package com.vanced.manager.ui.notifications
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class NotificationsViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is notifications Fragment"
}
val text: LiveData<String> = _text
}

View File

@ -0,0 +1,21 @@
package com.vanced.manager.ui.viewmodels
import android.app.Application
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import com.vanced.manager.R
open class AboutViewModel(application: Application): AndroidViewModel(application) {
fun openUrl(Url: String) {
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(getApplication(), R.color.GitHub))
val customTabsIntent = builder.build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
customTabsIntent.launchUrl(getApplication(), Uri.parse(Url))
}
}

View File

@ -0,0 +1,159 @@
package com.vanced.manager.ui.viewmodels
import android.app.Application
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Intent
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.R
import com.vanced.manager.utils.InternetTools.displayJsonInt
import com.vanced.manager.utils.InternetTools.displayJsonString
import com.vanced.manager.utils.PackageHelper.isPackageInstalled
class HomeViewModel(application: Application): AndroidViewModel(application) {
private val variant = getDefaultSharedPreferences(application).getString("vanced_variant", "nonroot")
private val connected: Boolean = GetJson().isConnected(application)
private val vancedPkgName: String =
if (variant== "root") {
"com.google.android.youtube"
} else {
"com.vanced.android.youtube"
}
private val pm = application.packageManager
val vancedInstallButtonTxt: MutableLiveData<String> = MutableLiveData()
val vancedInstallButtonIcon: MutableLiveData<Drawable> = MutableLiveData()
val microgInstalled: Boolean = isPackageInstalled("com.mgoogle.android.gms", application.packageManager)
val vancedInstalled: Boolean = isPackageInstalled(vancedPkgName, application.packageManager)
val vancedInstalledVersion: MutableLiveData<String> = MutableLiveData()
val microgInstalledVersion: MutableLiveData<String> = MutableLiveData()
val vancedVersion: MutableLiveData<String> = MutableLiveData()
val microgVersion: MutableLiveData<String> = MutableLiveData()
private val vancedInstalledVersionCode = getPkgVerCode(vancedInstalled, vancedPkgName)
private val microgInstalledVersionCode = getPkgVerCode(microgInstalled, "com.mgoogle.android.gms")
private val vancedVersionCode = displayJsonInt("vanced.json", "versionCode", application)
private val microgVersionCode = displayJsonInt("microg.json", "versionCode", application)
val microgInstallButtonTxt = compareInt(microgInstalledVersionCode, microgVersionCode, application)
val microgInstallButtonIcon = compareIntDrawable(microgInstalledVersionCode, microgVersionCode, application)
val nonrootModeSelected: Boolean = variant == "nonroot"
fun openMicrogSettings() {
try {
val intent = Intent()
intent.component = ComponentName(
"com.mgoogle.android.gms",
"org.microg.gms.ui.SettingsActivity"
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(getApplication(), intent, null)
} catch (e: ActivityNotFoundException) {
Toast.makeText(getApplication(), "App not installed", Toast.LENGTH_SHORT).show()
}
}
fun openUrl(Url: String) {
val color: Int =
when (Url) {
"https://discord.gg/TUVd7rd" -> R.color.Discord
"https://t.me/joinchat/AAAAAEHf-pi4jH1SDlAL4w" -> R.color.Telegram
"https://twitter.com/YTVanced" -> R.color.Twitter
"https://reddit.com/r/vanced" -> R.color.Reddit
"https://vanced.app" -> R.color.Vanced
"https://brave.com/van874" -> R.color.Brave
else -> R.color.Vanced
}
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(getApplication(), color))
val customTabsIntent = builder.build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
customTabsIntent.launchUrl(getApplication(), Uri.parse(Url))
}
private fun getPkgInfo(toCheck: Boolean, pkg: String, application: Application): String {
return if (toCheck) {
pm.getPackageInfo(pkg, 0).versionName
} else {
application.getString(R.string.unavailable)
}
}
private fun getPkgVerCode(toCheck: Boolean, pkg: String): Int {
return if (toCheck) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
pm.getPackageInfo(pkg, 0).longVersionCode.and(0xFFFFFFFF).toInt()
else
pm.getPackageInfo(pkg, 0).versionCode
} else 0
}
private fun compareInt(int1: Int, int2: Int, application: Application): String {
return if (connected)
when {
int2 == 0 -> application.getString(R.string.install)
int1 > int2 -> application.getString(R.string.update)
int2 == int1 -> application.getString(R.string.button_reinstall)
else -> application.getString(R.string.install)
} else application.getString(R.string.install)
}
private fun compareIntDrawable(int1: Int, int2: Int, application: Application): Drawable? {
return if (connected)
when {
int2 == 0 -> application.getDrawable(R.drawable.ic_download)
int1 > int2 -> application.getDrawable(R.drawable.ic_update)
int2 == int1 -> application.getDrawable(R.drawable.ic_done)
else -> application.getDrawable(R.drawable.ic_download)
} else application.getDrawable(R.drawable.ic_download)
}
init {
vancedVersion.value = displayJsonString("vanced.json","version", application)
microgVersion.value = displayJsonString("microg.json","version", application)
vancedInstalledVersion.value = getPkgInfo(vancedInstalled, vancedPkgName, application)
microgInstalledVersion.value = getPkgInfo(microgInstalled, "com.mgoogle.android.gms", application)
vancedInstallButtonIcon.value =
if (variant == "nonroot") {
if (microgInstalled)
compareIntDrawable(vancedVersionCode, vancedInstalledVersionCode, application)
else
null
} else
compareIntDrawable(vancedVersionCode, vancedInstalledVersionCode, application)
vancedInstallButtonTxt.value =
if (variant == "nonroot") {
if (microgInstalled) {
compareInt(vancedVersionCode, vancedInstalledVersionCode, application)
} else {
application.getString(R.string.no_microg)
}
} else
compareInt(vancedVersionCode, vancedInstalledVersionCode, application)
}
}

View File

@ -0,0 +1,14 @@
package com.vanced.manager.utils
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
open class FileInfo(val name: String, val fileSize: Long, val file: File? = null) {
open fun getInputStream(): InputStream =
if (file!= null)
FileInputStream(file)
else
throw NotImplementedError("need some way to create InputStream")
}

View File

@ -0,0 +1,68 @@
package com.vanced.manager.utils
import android.content.Context
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import com.dezlum.codelabs.getjson.GetJson
import com.vanced.manager.BuildConfig
import com.vanced.manager.R
import java.lang.Exception
import java.lang.IllegalStateException
object InternetTools {
fun openUrl(Url: String, color: Int, context: Context) {
val builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(context, color))
val customTabsIntent = builder.build()
customTabsIntent.launchUrl(context, Uri.parse(Url))
}
fun getFileNameFromUrl(url: String) = url.substring(url.lastIndexOf('/')+1, url.length)
fun displayJsonString(json: String, obj: String, context: Context): String {
val installUrl = PreferenceManager.getDefaultSharedPreferences(context).getString("install_url", baseUrl)
return if (GetJson().isConnected(context)) {
try {
GetJson().AsJSONObject("$installUrl/$json").get(obj).asString
} catch (e: Exception) {
when (e) {
is InterruptedException, is IllegalStateException -> GetJson().AsJSONObject("https://x1nto.github.io/VancedFiles/$json").get(obj).asString
else -> throw e
}
}
} else {
context.getString(R.string.unavailable)
}
}
fun displayJsonInt(json: String, obj: String, context: Context): Int {
val installUrl = PreferenceManager.getDefaultSharedPreferences(context).getString("install_url", baseUrl)
return if (GetJson().isConnected(context)) {
try {
GetJson().AsJSONObject("$installUrl/$json").get(obj).asInt
} catch (e: Exception) {
when (e) {
is InterruptedException, is IllegalStateException -> GetJson().AsJSONObject("https://x1nto.github.io/VancedFiles/$json").get(obj).asInt
else -> throw e
}
}
} else 0
}
fun isUpdateAvailable(): Boolean {
val checkUrl = GetJson().AsJSONObject("https://vanced.app/api/v1/manager.json")
val remoteVersion = checkUrl.get("versionCode").asInt
return remoteVersion > BuildConfig.VERSION_CODE
}
const val baseUrl = "https://vanced.app/api/v1"
}

View File

@ -0,0 +1,43 @@
package com.vanced.manager.utils
import android.text.TextUtils
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
object MiuiHelper {
fun isMiui(): Boolean {
return !TextUtils.isEmpty(getSystemProps("ro.miui.ui.version.name"))
}
fun isMiuiOptimisationsDisabled(): Boolean {
return if (isMiui())
getSystemProps("persist.sys.miui_optimization") == "0"
else
true
}
private fun getSystemProps(propname: String): String? {
val line: String
var input: BufferedReader? = null
try {
val p = Runtime.getRuntime().exec("getprop $propname")
input = BufferedReader(InputStreamReader(p.inputStream), 1024)
line = input.readLine()
input.close()
} catch (e: IOException) {
return null
} finally {
if (input != null) {
try {
input.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
return line
}
}

View File

@ -0,0 +1,73 @@
package com.vanced.manager.utils
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import com.vanced.manager.R
object NotificationHelper {
fun createNotifChannel(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notifChannel = NotificationChannel(
"69420",
context.getString(R.string.notif_channel_name),
NotificationManager.IMPORTANCE_HIGH
)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(notifChannel)
}
}
fun displayDownloadNotif(channel: Int, progress:Int, filename: String, context: Context) {
val notifBuilder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
Notification.Builder(context, channel.toString()).setChannelId("69420")
else
Notification.Builder(context).setPriority(Notification.PRIORITY_HIGH)
notifBuilder.apply {
setContentTitle(context.getString(R.string.app_name))
setContentText(context.getString(R.string.downloading_file, filename))
setSmallIcon(R.drawable.ic_stat_name)
setOnlyAlertOnce(true)
setOngoing(true)
}
val notif = notifBuilder.build()
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.apply {
notifBuilder.setProgress(100, progress, false)
notify(channel, notif)
}
}
fun createBasicNotif(text: String, channel: Int, context: Context) {
val notifBuilder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
Notification.Builder(context, channel.toString()).setChannelId("69420")
else
Notification.Builder(context).setPriority(Notification.PRIORITY_DEFAULT)
notifBuilder.apply {
setContentTitle(context.getString(R.string.app_name))
setContentText(text)
setSmallIcon(R.drawable.ic_stat_name)
}
val notif = notifBuilder.build()
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(channel, notif)
}
fun cancelNotif(id: Int, context: Context) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(id)
}
}

View File

@ -0,0 +1,58 @@
package com.vanced.manager.utils
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import com.vanced.manager.core.installer.AppInstallerService
import com.vanced.manager.core.installer.AppUninstallerService
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
object PackageHelper {
fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try {
packageManager.getPackageInfo(packageName, 0)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
}
@Throws(IOException::class)
fun installApp(
context: Context,
path: String,
pkg: String?
) {
val callbackIntent = Intent(context.applicationContext, AppInstallerService::class.java)
val pendingIntent = PendingIntent.getService(context.applicationContext, 0, callbackIntent, 0)
val packageInstaller = context.packageManager.packageInstaller
val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
params.setAppPackageName(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 uninstallApk(pkg: String, activity: Activity) {
val callbackIntent = Intent(activity.applicationContext, AppUninstallerService::class.java)
callbackIntent.putExtra("pkg", pkg)
val pendingIntent = PendingIntent.getService(activity.applicationContext, 0, callbackIntent, 0)
activity.packageManager.packageInstaller.uninstall(pkg, pendingIntent.intentSender)
}
}

View File

@ -0,0 +1,48 @@
package com.vanced.manager.utils
import android.content.res.Configuration
import androidx.preference.PreferenceManager
import com.vanced.manager.R
import com.vanced.manager.ui.MainActivity
object ThemeHelper {
fun setFinalTheme(activity: MainActivity) {
val currentAccent = PreferenceManager.getDefaultSharedPreferences(activity).getString("accent_color", "Blue")
when (PreferenceManager.getDefaultSharedPreferences(activity)
.getString("theme_mode", "Follow System")) {
"Light" -> activity.setTheme(getLightAccent(currentAccent))
"Dark" -> activity.setTheme(getDarkAccent(currentAccent))
"Follow System" -> {
when (activity.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> activity.setTheme(getDarkAccent(currentAccent))
Configuration.UI_MODE_NIGHT_NO -> activity.setTheme(getLightAccent(currentAccent))
}
}
else -> getLightAccent("Blue")
}
}
private fun getDarkAccent(accentColor: String?): Int {
return when (accentColor) {
"Blue" -> R.style.DarkTheme_Blue
"Red" -> R.style.DarkTheme_Red
"Green" -> R.style.DarkTheme_Green
"Yellow" -> R.style.DarkTheme_Yellow
"Purple" -> R.style.DarkTheme_Purple
else -> R.style.DarkTheme_Blue
}
}
private fun getLightAccent(accentColor: String?): Int {
return when (accentColor) {
"Blue" -> R.style.LightTheme_Blue
"Red" -> R.style.LightTheme_Red
"Green" -> R.style.LightTheme_Green
"Yellow" -> R.style.LightTheme_Yellow
"Purple" -> R.style.LightTheme_Purple
else -> R.style.LightTheme_Blue
}
}
}

11
app/src/main/main.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="-100%"
android:toXDelta="0%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%"
android:toXDelta="0%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0%"
android:toXDelta="100%"
android:duration="500"/>
</set>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueFrom="0.8"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleY"
android:valueFrom="0.8"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:valueType="floatType"
android:valueFrom="-1.0"
android:valueTo="0"
android:propertyName="xFraction" />
</set>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueFrom="1.1"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleY"
android:valueFrom="1.1"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:valueType="floatType"
android:valueFrom="1.0"
android:valueTo="0"
android:propertyName="xFraction" />
</set>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.8"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.8"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
</set>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="-1.0"
android:propertyName="xFraction" />
</set>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="1.1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="1.1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
</set>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1.0"
android:propertyName="xFraction" />
</set>

View File

@ -0,0 +1,46 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="24dp"
android:height="24dp"
android:viewportWidth="2373.913"
android:viewportHeight="2373.913"
android:tint="#FFFFFF">
<group android:translateX="186.95653"
android:translateY="186.95653">
<path
android:pathData="M1004.92,1881.1c-38.2,0.05 -76.47,-1.45 -114.57,0.42c-51.76,2.55 -81.84,-18.16 -90.74,-70.96c-7.49,-44.41 -13.2,-90.61 -30.51,-131.43c-15.34,-36.18 -40.29,-72.3 -70.22,-97.5c-83.85,-70.62 -178.04,-88.12 -279.91,-36c-16.76,8.57 -36.28,11.64 -54.35,17.76c-44.7,15.15 -76.87,1.99 -100.01,-39.68c-37.07,-66.74 -75.6,-132.69 -114.44,-198.43c-26.16,-44.27 -21.81,-81.72 19.36,-114.5c18.97,-15.11 34.6,-34.64 54.31,-48.55c72.54,-51.21 94,-120.05 91.6,-207.5c-2.02,-73.79 -23.93,-128.07 -79.03,-177.07c-131.04,-116.54 -130.5,-96.77 -38.4,-254.62c19.24,-32.97 38.08,-66.16 57.32,-99.13c41.41,-70.96 54.33,-75.72 134.39,-49.89c34.65,11.18 69.02,23.28 103.91,33.66c101.86,30.29 254.34,-57.92 278.42,-161.01c11.05,-47.28 20.7,-94.88 31.43,-142.24c8.42,-37.18 32.04,-56.47 70.31,-56.57c83.34,-0.23 166.68,0.02 250.01,-0.19c40.55,-0.11 65.26,19.16 73.99,58.78c10.44,47.42 14.73,97.39 33.08,141.51c15.63,37.56 42.09,74.68 73.09,100.99c82.04,69.63 174.55,87.18 274.79,35.85c18.26,-9.35 39.69,-12.3 59.29,-19.26c42.92,-15.23 73.52,-2.18 95.76,37.26c39.19,69.52 79.65,138.32 119.78,207.31c22.41,38.53 18.11,72.63 -15.69,102.47c-13.01,11.49 -24.36,25.49 -38.81,34.62c-105.9,66.87 -127.21,167.78 -109.49,281c5,31.96 22.73,65.36 43.68,90.58c29.68,35.74 67.12,65.23 102.43,96.04c33.98,29.66 40.49,63.13 18.36,101.95c-40.4,70.85 -81.55,141.28 -121.74,212.25c-21.43,37.85 -52.64,47.95 -92.63,35.44c-43.04,-13.47 -85.74,-28.06 -128.91,-41.12c-106.14,-32.11 -256.7,54.16 -281.98,161.54c-10.73,45.58 -20.37,91.42 -30.39,137.17c-8.68,39.59 -32.96,59.33 -73.71,59.05C1084.79,1880.83 1044.85,1881.04 1004.92,1881.1z"
android:strokeLineJoin="round"
android:strokeWidth="76"
android:fillColor="#00000000"
android:strokeLineCap="round">
<aapt:attr name="android:strokeColor">
<gradient
android:startY="1642.6245"
android:startX="322.9971"
android:endY="287.2871"
android:endX="1678.3345"
android:type="linear">
<item android:offset="1.065558E-7" android:color="#FF2E73FF"/>
<item android:offset="1" android:color="#FFFF0032"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M1270.42,895.24L886.12,647.3c-16.68,-9.72 -38.08,-4.08 -47.8,12.59l-0.75,1.28c-9.72,16.67 -4.09,38.07 12.59,47.79l367.49,221.11c23.91,14.39 23.77,49.1 -0.25,63.29l-369.18,218.11c-16.76,9.58 -22.58,30.93 -13,47.69l0.73,1.29c9.58,16.76 30.93,22.57 47.69,12.99l386.24,-244.83C1318.69,997.67 1318.97,926.57 1270.42,895.24z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M1074.21,926.45L884.98,819.87c-24.49,-13.8 -54.77,3.9 -54.77,32v213.18c0,28.11 30.28,45.8 54.77,32l189.22,-106.59C1099.15,976.41 1099.15,940.5 1074.21,926.45z">
<aapt:attr name="android:fillColor">
<gradient
android:startY="1058.4124"
android:startX="808.329"
android:endY="858.5059"
android:endX="1008.2355"
android:type="linear">
<item android:offset="0" android:color="#FF2E73FF"/>
<item android:offset="1" android:color="#FFFF0032"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More