VancedMicroG/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferenc...

163 lines
6.7 KiB
Kotlin

/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.text.format.DateUtils
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.google.android.gms.R
import org.microg.gms.checkin.getCheckinServiceInfo
import org.microg.gms.profile.ProfileManager
import org.microg.gms.profile.ProfileManager.PROFILE_AUTO
import org.microg.gms.profile.ProfileManager.PROFILE_NATIVE
import org.microg.gms.profile.ProfileManager.PROFILE_REAL
import org.microg.gms.profile.ProfileManager.PROFILE_SYSTEM
import org.microg.gms.profile.ProfileManager.PROFILE_USER
import java.io.File
import java.io.FileOutputStream
class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() {
private lateinit var deviceProfile: ListPreference
private lateinit var importProfile: Preference
private lateinit var serial: Preference
private lateinit var statusCategory: PreferenceCategory
private lateinit var status: Preference
private lateinit var androidId: Preference
private val handler = Handler()
private val updateRunnable = Runnable { updateStatus() }
private lateinit var profileFileImport: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
profileFileImport = registerForActivityResult(ActivityResultContracts.GetContent(), this::onFileSelected)
}
private fun onFileSelected(uri: Uri?) {
if (uri == null) return
try {
val context = requireContext()
val file = File.createTempFile("profile_", ".xml", context.cacheDir)
context.contentResolver.openInputStream(uri)?.use { inputStream ->
FileOutputStream(file).use { inputStream.copyTo(it) }
}
val success = ProfileManager.importUserProfile(context, file)
file.delete()
if (success && ProfileManager.isAutoProfile(context, PROFILE_USER)) {
ProfileManager.setProfile(context, PROFILE_USER)
}
updateStatus()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_device_registration)
}
override fun onBindPreferences() {
deviceProfile = preferenceScreen.findPreference("pref_device_profile") ?: deviceProfile
importProfile = preferenceScreen.findPreference("pref_device_profile_import") ?: importProfile
serial = preferenceScreen.findPreference("pref_device_serial") ?: serial
statusCategory = preferenceScreen.findPreference("prefcat_device_registration_status") ?: statusCategory
status = preferenceScreen.findPreference("pref_device_registration_status") ?: status
androidId = preferenceScreen.findPreference("pref_device_registration_android_id") ?: androidId
deviceProfile.setOnPreferenceChangeListener { _, newValue ->
ProfileManager.setProfile(requireContext(), newValue as String? ?: PROFILE_AUTO)
updateStatus()
true
}
importProfile.setOnPreferenceClickListener {
profileFileImport.launch("text/xml")
true
}
}
private fun configureProfilePreference() {
val context = requireContext()
val configuredProfile = ProfileManager.getConfiguredProfile(context)
val autoProfile = ProfileManager.getAutoProfile(context)
val autoProfileName = when (autoProfile) {
PROFILE_NATIVE -> "Native"
PROFILE_REAL -> "Real"
else -> ProfileManager.getProfileName(context, autoProfile)
}
val profiles =
mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL)
val profileNames = mutableListOf("Automatic: $autoProfileName", "Native", "Real")
if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) {
profiles.add(PROFILE_SYSTEM)
profileNames.add("System: ${ProfileManager.getProfileName(context, PROFILE_SYSTEM)}")
}
if (ProfileManager.hasProfile(context, PROFILE_USER)) {
profiles.add(PROFILE_USER)
profileNames.add("Custom: ${ProfileManager.getProfileName(context, PROFILE_USER)}")
}
for (profile in R.xml::class.java.declaredFields.map { it.name }
.filter { it.startsWith("profile_") }
.map { it.substring(8) }
.sorted()) {
val profileName = ProfileManager.getProfileName(context, profile)
if (profileName != null) {
profiles.add(profile)
profileNames.add(profileName)
}
}
deviceProfile.entryValues = profiles.toTypedArray()
deviceProfile.entries = profileNames.toTypedArray()
deviceProfile.value = configuredProfile
deviceProfile.summary =
profiles.indexOf(configuredProfile).takeIf { it >= 0 }?.let { profileNames[it] } ?: "Unknown"
}
override fun onResume() {
super.onResume()
updateStatus()
}
override fun onPause() {
super.onPause()
handler.removeCallbacks(updateRunnable)
}
private fun updateStatus() {
handler.removeCallbacks(updateRunnable)
handler.postDelayed(updateRunnable, UPDATE_INTERVAL)
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
configureProfilePreference()
serial.summary = ProfileManager.getSerial(appContext)
val serviceInfo = getCheckinServiceInfo(appContext)
statusCategory.isVisible = serviceInfo.configuration.enabled
if (serviceInfo.lastCheckin > 0) {
status.summary = getString(
R.string.checkin_last_registration,
DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0)
)
androidId.isVisible = true
androidId.summary = serviceInfo.androidId.toString(16)
} else {
status.summary = getString(R.string.checkin_not_registered)
androidId.isVisible = false
}
}
}
companion object {
private const val UPDATE_INTERVAL = 1000L
}
}