mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2025-01-30 20:47:48 +01:00
Profile Manager: Add configuration features
This commit is contained in:
parent
3bbae67fda
commit
6e21b52bfe
@ -7,10 +7,13 @@ package org.microg.gms.profile
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.XmlResourceParser
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.microg.gms.settings.SettingsContract
|
import org.microg.gms.settings.SettingsContract
|
||||||
import org.microg.gms.settings.SettingsContract.Profile
|
import org.microg.gms.settings.SettingsContract.Profile
|
||||||
|
import org.microg.gms.utils.FileXmlResourceParser
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -19,18 +22,67 @@ object ProfileManager {
|
|||||||
const val PROFILE_REAL = "real"
|
const val PROFILE_REAL = "real"
|
||||||
const val PROFILE_AUTO = "auto"
|
const val PROFILE_AUTO = "auto"
|
||||||
const val PROFILE_NATIVE = "native"
|
const val PROFILE_NATIVE = "native"
|
||||||
|
const val PROFILE_USER = "user"
|
||||||
|
const val PROFILE_SYSTEM = "system"
|
||||||
|
|
||||||
private var initialized = false
|
private var activeProfile: String? = null
|
||||||
|
|
||||||
private fun getProfileFromSettings(context: Context) = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.PROFILE)) { it.getString(0) }
|
private fun getUserProfileFile(context: Context): File = File(context.filesDir, "device_profile.xml")
|
||||||
private fun getAutoProfile(context: Context): String {
|
private fun getSystemProfileFile(context: Context): File = File("/system/etc/microg_device_profile.xml")
|
||||||
|
private fun getProfileResId(context: Context, profile: String) = context.resources.getIdentifier("${context.packageName}:xml/profile_$profile".toLowerCase(Locale.US), null, null)
|
||||||
|
|
||||||
|
fun getConfiguredProfile(context: Context): String = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.PROFILE)) { it.getString(0) } ?: PROFILE_AUTO
|
||||||
|
|
||||||
|
fun getAutoProfile(context: Context): String {
|
||||||
|
if (hasProfile(context, PROFILE_SYSTEM) && isAutoProfile(context, PROFILE_SYSTEM)) return PROFILE_SYSTEM
|
||||||
val profile = "${android.os.Build.PRODUCT}_${android.os.Build.VERSION.SDK_INT}"
|
val profile = "${android.os.Build.PRODUCT}_${android.os.Build.VERSION.SDK_INT}"
|
||||||
if (hasProfile(context, profile)) return profile
|
if (hasProfile(context, profile) && isAutoProfile(context, profile)) return profile
|
||||||
return PROFILE_NATIVE
|
return PROFILE_NATIVE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProfileResId(context: Context, profile: String) = context.resources.getIdentifier("${context.packageName}:xml/profile_$profile".toLowerCase(Locale.US), null, null)
|
fun hasProfile(context: Context, profile: String): Boolean = when (profile) {
|
||||||
private fun hasProfile(context: Context, profile: String): Boolean = getProfileResId(context, profile) != 0
|
PROFILE_AUTO -> hasProfile(context, getAutoProfile(context))
|
||||||
|
PROFILE_NATIVE, PROFILE_REAL -> true
|
||||||
|
PROFILE_USER -> getUserProfileFile(context).exists()
|
||||||
|
PROFILE_SYSTEM -> getSystemProfileFile(context).exists()
|
||||||
|
else -> getProfileResId(context, profile) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getProfileXml(context: Context, profile: String): XmlResourceParser? = kotlin.runCatching {
|
||||||
|
when (profile) {
|
||||||
|
PROFILE_AUTO -> getProfileXml(context, getAutoProfile(context))
|
||||||
|
PROFILE_NATIVE, PROFILE_REAL -> null
|
||||||
|
PROFILE_USER -> FileXmlResourceParser(getUserProfileFile(context))
|
||||||
|
PROFILE_SYSTEM -> FileXmlResourceParser(getSystemProfileFile(context))
|
||||||
|
else -> {
|
||||||
|
val profileResId = getProfileResId(context, profile)
|
||||||
|
if (profileResId == 0) return@runCatching null
|
||||||
|
context.resources.getXml(profileResId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
|
fun isAutoProfile(context: Context, profile: String): Boolean = kotlin.runCatching {
|
||||||
|
when (profile) {
|
||||||
|
PROFILE_AUTO -> false
|
||||||
|
PROFILE_REAL -> false
|
||||||
|
PROFILE_NATIVE -> true
|
||||||
|
else -> getProfileXml(context, profile)?.use {
|
||||||
|
var next = it.next()
|
||||||
|
while (next != XmlPullParser.END_DOCUMENT) {
|
||||||
|
when (next) {
|
||||||
|
XmlPullParser.START_TAG -> when (it.name) {
|
||||||
|
"profile" -> {
|
||||||
|
return@use it.getAttributeBooleanValue(null, "auto", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next = it.next()
|
||||||
|
}
|
||||||
|
} == true
|
||||||
|
}
|
||||||
|
}.getOrDefault(false)
|
||||||
|
|
||||||
private fun getProfileData(context: Context, profile: String, realData: Map<String, String>): Map<String, String> {
|
private fun getProfileData(context: Context, profile: String, realData: Map<String, String>): Map<String, String> {
|
||||||
try {
|
try {
|
||||||
if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return realData
|
if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return realData
|
||||||
@ -38,7 +90,7 @@ object ProfileManager {
|
|||||||
if (profileResId == 0) return realData
|
if (profileResId == 0) return realData
|
||||||
val resultData = mutableMapOf<String, String>()
|
val resultData = mutableMapOf<String, String>()
|
||||||
resultData.putAll(realData)
|
resultData.putAll(realData)
|
||||||
context.resources.getXml(profileResId).use {
|
getProfileXml(context, profile)?.use {
|
||||||
var next = it.next()
|
var next = it.next()
|
||||||
while (next != XmlPullParser.END_DOCUMENT) {
|
while (next != XmlPullParser.END_DOCUMENT) {
|
||||||
when (next) {
|
when (next) {
|
||||||
@ -61,7 +113,7 @@ object ProfileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getActiveProfile(context: Context) = getProfileFromSettings(context).let { if (it != PROFILE_AUTO) it else getAutoProfile(context) }
|
private fun getProfile(context: Context) = getConfiguredProfile(context).let { if (it != PROFILE_AUTO) it else getAutoProfile(context) }
|
||||||
private fun getSerialFromSettings(context: Context): String? = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.SERIAL)) { it.getString(0) }
|
private fun getSerialFromSettings(context: Context): String? = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.SERIAL)) { it.getString(0) }
|
||||||
private fun saveSerial(context: Context, serial: String) = SettingsContract.setSettings(context, Profile.getContentUri(context)) { put(Profile.SERIAL, serial) }
|
private fun saveSerial(context: Context, serial: String) = SettingsContract.setSettings(context, Profile.getContentUri(context)) { put(Profile.SERIAL, serial) }
|
||||||
|
|
||||||
@ -99,9 +151,7 @@ object ProfileManager {
|
|||||||
|
|
||||||
// From profile
|
// From profile
|
||||||
try {
|
try {
|
||||||
val profileResId = getProfileResId(context, profile)
|
getProfileXml(context, profile)?.use {
|
||||||
if (profileResId != 0) {
|
|
||||||
context.resources.getXml(profileResId).use {
|
|
||||||
var next = it.next()
|
var next = it.next()
|
||||||
while (next != XmlPullParser.END_DOCUMENT) {
|
while (next != XmlPullParser.END_DOCUMENT) {
|
||||||
when (next) {
|
when (next) {
|
||||||
@ -112,24 +162,23 @@ object ProfileManager {
|
|||||||
next = it.next()
|
next = it.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, e)
|
Log.w(TAG, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback
|
// Fallback
|
||||||
return "008741A0B2C4D6E8"
|
return randomSerial("008741A0B2C4D6E8")
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
private fun getEffectiveProfileSerial(context: Context, profile: String): String {
|
fun getSerial(context: Context, profile: String = getProfile(context), local: Boolean = false): String {
|
||||||
getSerialFromSettings(context)?.let { return it }
|
if (!local) getSerialFromSettings(context)?.let { return it }
|
||||||
val serialTemplate = getProfileSerialTemplate(context, profile)
|
val serialTemplate = getProfileSerialTemplate(context, profile)
|
||||||
val serial = when {
|
val serial = when {
|
||||||
profile == PROFILE_REAL && serialTemplate != android.os.Build.UNKNOWN -> serialTemplate
|
profile == PROFILE_REAL && serialTemplate != android.os.Build.UNKNOWN -> serialTemplate
|
||||||
else -> randomSerial(serialTemplate)
|
else -> randomSerial(serialTemplate)
|
||||||
}
|
}
|
||||||
saveSerial(context, serial)
|
if (!local) saveSerial(context, serial)
|
||||||
return serial
|
return serial
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,29 +259,67 @@ object ProfileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyProfile(context: Context, profile: String) {
|
private fun applyProfile(context: Context, profile: String, serial: String = getSerial(context, profile)) {
|
||||||
val profileData = getProfileData(context, profile, getRealData()) ?: getRealData()
|
val profileData = getProfileData(context, profile, getRealData())
|
||||||
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
|
for ((key, value) in profileData) {
|
||||||
|
Log.v(TAG, "<data key=\"$key\" value=\"$value\" />")
|
||||||
|
}
|
||||||
|
}
|
||||||
applyProfileData(profileData)
|
applyProfileData(profileData)
|
||||||
Build.SERIAL = getEffectiveProfileSerial(context, profile)
|
Build.SERIAL = serial
|
||||||
Log.d(TAG, "Using Serial ${Build.SERIAL}")
|
Log.d(TAG, "Using Serial ${Build.SERIAL}")
|
||||||
|
activeProfile = profile
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProfileName(context: Context, profile: String): String? = getProfileName { getProfileXml(context, profile) }
|
||||||
|
|
||||||
|
private fun getProfileName(parserCreator: () -> XmlResourceParser?): String? = parserCreator()?.use {
|
||||||
|
var next = it.next()
|
||||||
|
while (next != XmlPullParser.END_DOCUMENT) {
|
||||||
|
when (next) {
|
||||||
|
XmlPullParser.START_TAG -> when (it.name) {
|
||||||
|
"profile" -> {
|
||||||
|
return@use it.getAttributeValue(null, "name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next = it.next()
|
||||||
|
}
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setProfile(context: Context, profile: String?) {
|
fun setProfile(context: Context, profile: String?) {
|
||||||
|
val changed = getProfile(context) != profile
|
||||||
|
val newProfile = profile ?: PROFILE_AUTO
|
||||||
|
val newSerial = if (changed) getSerial(context, newProfile, true) else getSerial(context)
|
||||||
SettingsContract.setSettings(context, Profile.getContentUri(context)) {
|
SettingsContract.setSettings(context, Profile.getContentUri(context)) {
|
||||||
put(Profile.PROFILE, profile)
|
put(Profile.PROFILE, newProfile)
|
||||||
put(Profile.SERIAL, null as String?)
|
if (changed) put(Profile.SERIAL, newSerial)
|
||||||
|
}
|
||||||
|
if (changed && activeProfile != null) applyProfile(context, newProfile, newSerial)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importUserProfile(context: Context, file: File): Boolean {
|
||||||
|
val profileName = getProfileName { FileXmlResourceParser(file) } ?: return false
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "Importing user profile '$profileName'")
|
||||||
|
file.copyTo(getUserProfileFile(context))
|
||||||
|
if (activeProfile == PROFILE_USER) applyProfile(context, PROFILE_USER)
|
||||||
|
return true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, e)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
applyProfile(context, profile ?: PROFILE_AUTO)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun ensureInitialized(context: Context) {
|
fun ensureInitialized(context: Context) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (initialized) return
|
|
||||||
try {
|
try {
|
||||||
val profile = getActiveProfile(context)
|
val profile = getProfile(context)
|
||||||
|
if (activeProfile == profile) return
|
||||||
applyProfile(context, profile)
|
applyProfile(context, profile)
|
||||||
initialized = true
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, e)
|
Log.w(TAG, e)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 microG Project Team
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.microg.gms.utils
|
||||||
|
|
||||||
|
import android.content.res.XmlResourceParser
|
||||||
|
import android.util.Xml
|
||||||
|
import org.xmlpull.v1.XmlPullParser
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileReader
|
||||||
|
import java.io.Reader
|
||||||
|
|
||||||
|
class FileXmlResourceParser(private val reader: Reader, private val parser: XmlPullParser = Xml.newPullParser()) :
|
||||||
|
XmlResourceParser,
|
||||||
|
XmlPullParser by parser,
|
||||||
|
Closeable by reader {
|
||||||
|
constructor(file: File) : this(FileReader(file))
|
||||||
|
|
||||||
|
init {
|
||||||
|
parser.setInput(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeNameResource(index: Int): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeListValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
options: Array<String?>?, defaultValue: Int
|
||||||
|
): Int {
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeBooleanValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
defaultValue: Boolean
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toBooleanStrictOrNull() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeResourceValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
defaultValue: Int
|
||||||
|
): Int {
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeIntValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
defaultValue: Int
|
||||||
|
): Int {
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeUnsignedIntValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
defaultValue: Int
|
||||||
|
): Int {
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeFloatValue(
|
||||||
|
namespace: String?, attribute: String?,
|
||||||
|
defaultValue: Float
|
||||||
|
): Float {
|
||||||
|
val s = getAttributeValue(namespace, attribute)
|
||||||
|
return s?.toFloat() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeListValue(
|
||||||
|
index: Int,
|
||||||
|
options: Array<String?>?, defaultValue: Int
|
||||||
|
): Int {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeBooleanValue(index: Int, defaultValue: Boolean): Boolean {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toBooleanStrictOrNull() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeResourceValue(index: Int, defaultValue: Int): Int {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeIntValue(index: Int, defaultValue: Int): Int {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeUnsignedIntValue(index: Int, defaultValue: Int): Int {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toInt() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAttributeFloatValue(index: Int, defaultValue: Float): Float {
|
||||||
|
val s = getAttributeValue(index)
|
||||||
|
return s?.toFloat() ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIdAttribute(): String? {
|
||||||
|
return getAttributeValue(null, "id")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClassAttribute(): String? {
|
||||||
|
return getAttributeValue(null, "class")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIdAttributeResourceValue(defaultValue: Int): Int {
|
||||||
|
return getAttributeResourceValue(null, "id", defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStyleAttribute(): Int {
|
||||||
|
return getAttributeResourceValue(null, "style", 0)
|
||||||
|
}
|
||||||
|
}
|
@ -5,31 +5,122 @@
|
|||||||
|
|
||||||
package org.microg.gms.ui
|
package org.microg.gms.ui
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.text.format.DateUtils
|
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.lifecycle.lifecycleScope
|
||||||
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceCategory
|
import androidx.preference.PreferenceCategory
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.google.android.gms.R
|
import com.google.android.gms.R
|
||||||
import org.microg.gms.checkin.getCheckinServiceInfo
|
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() {
|
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 statusCategory: PreferenceCategory
|
||||||
private lateinit var status: Preference
|
private lateinit var status: Preference
|
||||||
private lateinit var androidId: Preference
|
private lateinit var androidId: Preference
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private val updateRunnable = Runnable { updateStatus() }
|
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?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
addPreferencesFromResource(R.xml.preferences_device_registration)
|
addPreferencesFromResource(R.xml.preferences_device_registration)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindPreferences() {
|
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
|
statusCategory = preferenceScreen.findPreference("prefcat_device_registration_status") ?: statusCategory
|
||||||
status = preferenceScreen.findPreference("pref_device_registration_status") ?: status
|
status = preferenceScreen.findPreference("pref_device_registration_status") ?: status
|
||||||
androidId = preferenceScreen.findPreference("pref_device_registration_android_id") ?: androidId
|
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() {
|
override fun onResume() {
|
||||||
@ -43,13 +134,19 @@ class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateStatus() {
|
private fun updateStatus() {
|
||||||
|
handler.removeCallbacks(updateRunnable)
|
||||||
handler.postDelayed(updateRunnable, UPDATE_INTERVAL)
|
handler.postDelayed(updateRunnable, UPDATE_INTERVAL)
|
||||||
val appContext = requireContext().applicationContext
|
val appContext = requireContext().applicationContext
|
||||||
lifecycleScope.launchWhenResumed {
|
lifecycleScope.launchWhenResumed {
|
||||||
|
configureProfilePreference()
|
||||||
|
serial.summary = ProfileManager.getSerial(appContext)
|
||||||
val serviceInfo = getCheckinServiceInfo(appContext)
|
val serviceInfo = getCheckinServiceInfo(appContext)
|
||||||
statusCategory.isVisible = serviceInfo.configuration.enabled
|
statusCategory.isVisible = serviceInfo.configuration.enabled
|
||||||
if (serviceInfo.lastCheckin > 0) {
|
if (serviceInfo.lastCheckin > 0) {
|
||||||
status.summary = getString(R.string.checkin_last_registration, DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0))
|
status.summary = getString(
|
||||||
|
R.string.checkin_last_registration,
|
||||||
|
DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0)
|
||||||
|
)
|
||||||
androidId.isVisible = true
|
androidId.isVisible = true
|
||||||
androidId.summary = serviceInfo.androidId.toString(16)
|
androidId.summary = serviceInfo.androidId.toString(16)
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,12 +11,18 @@
|
|||||||
android:title="Device profile">
|
android:title="Device profile">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="pref_device_profile"
|
android:key="pref_device_profile"
|
||||||
|
android:persistent="false"
|
||||||
android:title="Select profile"
|
android:title="Select profile"
|
||||||
tools:summary="Automatic (Google Pixel 3, Android 11)" />
|
tools:summary="Automatic (Google Pixel 3, Android 11)" />
|
||||||
<Preference
|
<Preference
|
||||||
android:key="pref_device_profile_import"
|
android:key="pref_device_profile_import"
|
||||||
android:summary="Import device profile from file"
|
android:summary="Import device profile from file"
|
||||||
android:title="Import profile" />
|
android:title="Import custom profile" />
|
||||||
|
<Preference
|
||||||
|
android:enabled="false"
|
||||||
|
android:key="pref_device_serial"
|
||||||
|
android:title="Serial"
|
||||||
|
tools:summary="123456" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="prefcat_device_registration_status"
|
android:key="prefcat_device_registration_status"
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
~ SPDX-FileCopyrightText: 2021, microG Project Team
|
~ SPDX-FileCopyrightText: 2021 microG Project Team
|
||||||
~ SPDX-License-Identifier: Apache-2.0
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
-->
|
-->
|
||||||
<profile name="Google Nexus 5X (Android 8.1.0)" product="bullhead" sdk="27" id="bullhead_27">
|
<profile name="Google Nexus 5X (Android 8.1.0)" product="bullhead" sdk="27" id="bullhead_27" auto="true">
|
||||||
<!-- Data from OPM3.171019.016, Mar 2018 -->
|
<!-- Data from OPM3.171019.016, Mar 2018 -->
|
||||||
<data key="Build.BOARD" value="bullhead" />
|
<data key="Build.BOARD" value="bullhead" />
|
||||||
<data key="Build.BOOTLOADER" value="BHZ31b" />
|
<data key="Build.BOOTLOADER" value="BHZ31b" />
|
||||||
@ -27,6 +27,7 @@
|
|||||||
<data key="Build.VERSION.CODENAME" value="REL" />
|
<data key="Build.VERSION.CODENAME" value="REL" />
|
||||||
<data key="Build.VERSION.INCREMENTAL" value="6d95f5a143" />
|
<data key="Build.VERSION.INCREMENTAL" value="6d95f5a143" />
|
||||||
<data key="Build.VERSION.RELEASE" value="8.1.0" />
|
<data key="Build.VERSION.RELEASE" value="8.1.0" />
|
||||||
|
<data key="Build.VERSION.SECURITY_PATCH" value="2021-10-05" />
|
||||||
<data key="Build.VERSION.SDK" value="27" />
|
<data key="Build.VERSION.SDK" value="27" />
|
||||||
<data key="Build.VERSION.SDK_INT" value="27" />
|
<data key="Build.VERSION.SDK_INT" value="27" />
|
||||||
<data key="Build.SUPPORTED_ABIS" value="arm64-v8a,armeabi-v7a,armeabi" />
|
<data key="Build.SUPPORTED_ABIS" value="arm64-v8a,armeabi-v7a,armeabi" />
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2022 microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
<profile name="Motorola Moto G (LineageOS 14.1)" product="lineage_falcon" sdk="25" id="lineage_falcon_25" auto="true">
|
||||||
|
<!-- Data from LineageOS 14.1-20190207-NIGHTLY-falcon, Feb 2019 -->
|
||||||
|
<data key="Build.BOARD" value="MSM8226" />
|
||||||
|
<data key="Build.BOOTLOADER" value="0x4118" />
|
||||||
|
<data key="Build.BRAND" value="motorola" />
|
||||||
|
<data key="Build.CPU_ABI" value="armeabi-v7a" />
|
||||||
|
<data key="Build.CPU_ABI2" value="armeabi" />
|
||||||
|
<data key="Build.DEVICE" value="falcon_umts" />
|
||||||
|
<data key="Build.DISPLAY" value="lineage_falcon-userdebug 7.1.2 NJH47F f4535aec29" />
|
||||||
|
<data key="Build.FINGERPRINT" value="motorola/falcon_retuglb/falcon_umts:5.1/LPB23.13-58/58:user/release-keys" />
|
||||||
|
<data key="Build.HARDWARE" value="qcom" />
|
||||||
|
<data key="Build.HOST" value="lineage-runner" />
|
||||||
|
<data key="Build.ID" value="NJH47F" />
|
||||||
|
<data key="Build.MANUFACTURER" value="motorola" />
|
||||||
|
<data key="Build.MODEL" value="Moto G" />
|
||||||
|
<data key="Build.PRODUCT" value="lineage_falcon" />
|
||||||
|
<data key="Build.RADIO" value="unknown" />
|
||||||
|
<data key="Build.TAGS" value="release-keys" />
|
||||||
|
<data key="Build.TIME" value="1549548437000" />
|
||||||
|
<data key="Build.TYPE" value="user" />
|
||||||
|
<data key="Build.USER" value="gitlab-runner" />
|
||||||
|
<data key="Build.VERSION.CODENAME" value="REL" />
|
||||||
|
<data key="Build.VERSION.INCREMENTAL" value="f4535aec29" />
|
||||||
|
<data key="Build.VERSION.RELEASE" value="7.1.2" />
|
||||||
|
<data key="Build.VERSION.SECURITY_PATCH" value="2019-01-05" />
|
||||||
|
<data key="Build.VERSION.SDK" value="25" />
|
||||||
|
<data key="Build.VERSION.SDK_INT" value="25" />
|
||||||
|
<data key="Build.SUPPORTED_ABIS" value="armeabi-v7a,armeabi" />
|
||||||
|
|
||||||
|
<serial template="TA9290XXXX" />
|
||||||
|
</profile>
|
Loading…
x
Reference in New Issue
Block a user