Split play and other version

This commit is contained in:
世界 2023-11-09 13:05:56 +08:00
parent d10c6ebd7e
commit d45e2af1c2
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
8 changed files with 154 additions and 65 deletions

View file

@ -48,6 +48,14 @@ android {
}
}
flavorDimensions "vendor"
productFlavors {
play {
}
other {
}
}
splits {
abi {
enable true
@ -68,6 +76,8 @@ android {
applicationVariants.configureEach { variant ->
variant.outputs.configureEach {
outputFileName = (outputFileName as String).replace("-release", "")
outputFileName = (outputFileName as String).replace("-play", "")
outputFileName = (outputFileName as String).replace("-other", "")
}
}
}
@ -99,7 +109,7 @@ dependencies {
exclude group: 'com.google.guava', module: 'guava'
}
implementation 'com.google.guava:guava:32.1.2-android'
implementation 'com.google.android.play:app-update-ktx:2.1.0'
playImplementation 'com.google.android.play:app-update-ktx:2.1.0'
}
if (getProps("APPCENTER_TOKEN") != "") {

View file

@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent
import android.net.VpnService
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
@ -17,11 +16,6 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus
import com.google.android.play.core.install.model.UpdateAvailability
import io.nekohasekai.libbox.Libbox
import io.nekohasekai.libbox.ProfileContent
import io.nekohasekai.sfa.Application
@ -39,6 +33,7 @@ import io.nekohasekai.sfa.databinding.ActivityMainBinding
import io.nekohasekai.sfa.ktx.errorDialogBuilder
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
import io.nekohasekai.sfa.ui.shared.AbstractActivity
import io.nekohasekai.sfa.vendor.Vendor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -177,59 +172,11 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
}
private fun startIntegration() {
lifecycleScope.launch(Dispatchers.IO) {
if (Settings.checkUpdateEnabled) {
checkUpdate()
}
}
}
private fun checkUpdate() {
val appUpdateManager = AppUpdateManagerFactory.create(this)
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
when (appUpdateInfo.updateAvailability()) {
UpdateAvailability.UPDATE_NOT_AVAILABLE -> {
Log.d(TAG, "checkUpdate: not available")
if (Vendor.checkUpdateAvailable()) {
lifecycleScope.launch(Dispatchers.IO) {
if (Settings.checkUpdateEnabled) {
Vendor.checkUpdate(this@MainActivity, false)
}
UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS -> {
Log.d(TAG, "checkUpdate: in progress, status: ${appUpdateInfo.installStatus()}")
when (appUpdateInfo.installStatus()) {
InstallStatus.DOWNLOADED -> {
appUpdateManager.completeUpdate()
}
}
}
UpdateAvailability.UPDATE_AVAILABLE -> {
Log.d(TAG, "checkUpdate: available")
if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
appUpdateManager.startUpdateFlow(
appUpdateInfo,
this,
AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()
)
} else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
appUpdateManager.startUpdateFlow(
appUpdateInfo,
this,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
)
}
}
UpdateAvailability.UNKNOWN -> {
Log.d(TAG, "checkUpdate: unknown")
}
}
}
appUpdateInfoTask.addOnFailureListener {
Log.e(TAG, "checkUpdate: ", it)
}
appUpdateManager.registerListener { state ->
if (state.installStatus() == InstallStatus.DOWNLOADED) {
appUpdateManager.completeUpdate()
}
}
}

View file

@ -9,6 +9,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import io.nekohasekai.libbox.Libbox
@ -24,6 +25,7 @@ import io.nekohasekai.sfa.ktx.text
import io.nekohasekai.sfa.ui.MainActivity
import io.nekohasekai.sfa.ui.debug.DebugActivity
import io.nekohasekai.sfa.ui.profileoverride.ProfileOverrideActivity
import io.nekohasekai.sfa.vendor.Vendor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -58,12 +60,18 @@ class SettingsFragment : Fragment() {
reloadSettings()
}
}
if (!Vendor.checkUpdateAvailable()) {
binding.appSettingsCard.isVisible = false
}
binding.checkUpdateEnabled.addTextChangedListener {
lifecycleScope.launch(Dispatchers.IO) {
val newValue = EnabledType.valueOf(it).boolValue
Settings.checkUpdateEnabled = newValue
}
}
binding.checkUpdateButton.setOnClickListener {
Vendor.checkUpdate(activity, true)
}
binding.disableMemoryLimit.addTextChangedListener {
lifecycleScope.launch(Dispatchers.IO) {
val newValue = EnabledType.valueOf(it).boolValue

View file

@ -0,0 +1,9 @@
package io.nekohasekai.sfa.vendor
import android.app.Activity
interface VendorInterface {
fun checkUpdateAvailable(): Boolean
fun checkUpdate(activity: Activity, byUser: Boolean)
}

View file

@ -16,17 +16,20 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/appCenterCard"
android:id="@+id/appSettingsCard"
style="?attr/materialCardViewElevatedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginTop="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
android:paddingStart="16dp"
android:paddingTop="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -40,7 +43,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/check_update">
android:hint="@string/check_update_atomic">
<AutoCompleteTextView
android:layout_width="match_parent"
@ -51,6 +54,20 @@
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|end"
android:orientation="horizontal">
<Button
android:id="@+id/checkUpdateButton"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_update" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -82,6 +82,7 @@
<string name="core_version">Version</string>
<string name="core">Core</string>
<string name="core_data_size">Data Size</string>
<string name="check_update_atomic">Atomic Check Update</string>
<string name="check_update">Check Update</string>
<string name="title_app_settings">App Settings</string>
<string name="about_title">About</string>
@ -92,7 +93,7 @@
<string name="background_permission">Background permission</string>
<string name="background_permission_description">Apply for the necessary permissions in order for the VPN to function properly.\n\nIf you are using a device made by a Chinese company, the card may not disappear after the permission is granted.</string>
<string name="read_more">Read More</string>
<string name="request_background_permission">Ignore battery optimizations</string>
<string name="request_background_permission">Ignore Battery Optimizations</string>
<string name="import_remote_profile">Import remote profile</string>
<string name="import_remote_profile_message">Are you sure to import remote profile %s? You will connect to %s to download the configuration.</string>
@ -140,5 +141,7 @@
<string name="vpn_golang_version">Go Version</string>
<string name="vpn_app_type_other">Other</string>
<string name="vpn_core_type_unknown">Unknown</string>
<string name="no_updates_available">No updates available</string>
</resources>

View file

@ -0,0 +1,15 @@
package io.nekohasekai.sfa.vendor
import android.app.Activity
object Vendor : VendorInterface {
override fun checkUpdateAvailable(): Boolean {
return false
}
override fun checkUpdate(activity: Activity, byUser: Boolean) {
}
}

View file

@ -0,0 +1,80 @@
package io.nekohasekai.sfa.vendor
import android.app.Activity
import android.content.Context
import android.util.Log
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus
import com.google.android.play.core.install.model.UpdateAvailability
import io.nekohasekai.sfa.R
object Vendor : VendorInterface {
private const val TAG = "Vendor"
override fun checkUpdateAvailable(): Boolean {
return true
}
override fun checkUpdate(activity: Activity, byUser: Boolean) {
val appUpdateManager = AppUpdateManagerFactory.create(activity)
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
when (appUpdateInfo.updateAvailability()) {
UpdateAvailability.UPDATE_NOT_AVAILABLE -> {
Log.d(TAG, "checkUpdate: not available")
if (byUser) activity.showNoUpdatesDialog()
}
UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS -> {
Log.d(TAG, "checkUpdate: in progress, status: ${appUpdateInfo.installStatus()}")
when (appUpdateInfo.installStatus()) {
InstallStatus.DOWNLOADED -> {
appUpdateManager.completeUpdate()
}
}
}
UpdateAvailability.UPDATE_AVAILABLE -> {
Log.d(TAG, "checkUpdate: available")
if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
appUpdateManager.startUpdateFlow(
appUpdateInfo,
activity,
AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()
)
} else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
appUpdateManager.startUpdateFlow(
appUpdateInfo,
activity,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
)
}
}
UpdateAvailability.UNKNOWN -> {
if (byUser) activity.showNoUpdatesDialog()
}
}
}
appUpdateInfoTask.addOnFailureListener {
Log.e(TAG, "checkUpdate: ", it)
}
appUpdateManager.registerListener { state ->
if (state.installStatus() == InstallStatus.DOWNLOADED) {
appUpdateManager.completeUpdate()
}
}
}
private fun Context.showNoUpdatesDialog() {
MaterialAlertDialogBuilder(this)
.setTitle(io.nekohasekai.sfa.R.string.check_update)
.setMessage(R.string.no_updates_available)
.setPositiveButton(R.string.ok, null)
.show()
}
}