UI: Unify preferences "microg@d831bbc"

This commit is contained in:
Cuynu 2024-10-02 23:46:17 +07:00
commit b96a8d4727
29 changed files with 742 additions and 795 deletions

View file

@ -25,9 +25,9 @@ import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static org.microg.gms.auth.AuthPrefs.isAuthVisible;
import static org.microg.gms.checkin.CheckinPrefs.hideLauncherIcon;
import static org.microg.gms.checkin.CheckinPrefs.isSpoofingEnabled;
import static org.microg.gms.checkin.CheckinPrefs.setSpoofingEnabled;
import static org.microg.gms.checkin.CheckinPreferences.hideLauncherIcon;
import static org.microg.gms.checkin.CheckinPreferences.isSpoofingEnabled;
import static org.microg.gms.checkin.CheckinPreferences.setSpoofingEnabled;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
import static org.microg.gms.common.Constants.GMS_VERSION_CODE;

View file

@ -16,7 +16,7 @@
package org.microg.gms.checkin;
import static org.microg.gms.checkin.CheckinPrefs.isSpoofingEnabled;
import static org.microg.gms.checkin.CheckinPreferences.isSpoofingEnabled;
import android.accounts.Account;
import android.accounts.AccountManager;
@ -43,7 +43,7 @@ public class CheckinManager {
LastCheckinInfo info = LastCheckinInfo.read(context);
if (!force && info.getLastCheckin() > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL)
return null;
if (!CheckinPrefs.isEnabled(context))
if (!CheckinPreferences.isEnabled(context))
return null;
List<CheckinClient.Account> accounts = new ArrayList<>();
AccountManager accountManager = AccountManager.get(context);

View file

@ -80,7 +80,7 @@ public class CheckinService extends IntentService {
protected void onHandleIntent(Intent intent) {
try {
ForegroundServiceContext.completeForegroundService(this, intent, TAG);
if (CheckinPrefs.isEnabled(this)) {
if (CheckinPreferences.isEnabled(this)) {
LastCheckinInfo info = CheckinManager.checkin(this, intent.getBooleanExtra(EXTRA_FORCE_CHECKIN, false));
if (info != null) {
Log.d(TAG, "Checked in as " + Long.toHexString(info.getAndroidId()));

View file

@ -41,7 +41,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
try {
boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction());
if (CheckinPrefs.isEnabled(context) || force) {
if (CheckinPreferences.isEnabled(context) || force) {
if (LastCheckinInfo.read(context).getLastCheckin() > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) {
CheckinService.schedule(context);
return;

View file

@ -30,7 +30,7 @@ import android.util.Log;
import androidx.legacy.content.WakefulBroadcastReceiver;
import org.microg.gms.checkin.CheckinPrefs;
import org.microg.gms.checkin.CheckinPreferences;
import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.ForegroundServiceContext;
@ -67,7 +67,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
if (LastCheckinInfo.read(context).getAndroidId() == 0) {
Log.d(TAG, "Ignoring " + intent + ": need to checkin first.");
if (CheckinPrefs.isEnabled(context)) {
if (CheckinPreferences.isEnabled(context)) {
// Do a check-in if we are not actually checked in,
// but should be, e.g. cleared app data
Log.d(TAG, "Requesting check-in...");

View file

@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.checkin
import android.content.Context
import android.content.Intent
import org.microg.gms.settings.SettingsContract
import org.microg.gms.settings.SettingsContract.CheckIn
import org.microg.gms.settings.SettingsContract.setSettings
object CheckinPreferences {
@JvmStatic
fun isEnabled(context: Context): Boolean {
val projection = arrayOf(CheckIn.ENABLED)
return SettingsContract.getSettings(
context,
CheckIn.getContentUri(context),
projection
) { c ->
c.getInt(0) != 0
}
}
@JvmStatic
fun isSpoofingEnabled(context: Context): Boolean {
val projection = arrayOf(CheckIn.BRAND_SPOOF)
return SettingsContract.getSettings(
context,
CheckIn.getContentUri(context),
projection
) { c ->
c.getInt(0) != 0
}
}
@JvmStatic
fun setSpoofingEnabled(context: Context, enabled: Boolean) {
setSettings(context, CheckIn.getContentUri(context)) {
put(CheckIn.BRAND_SPOOF, enabled)
}
}
@JvmStatic
fun hideLauncherIcon(context: Context, enabled: Boolean) {
setSettings(context, CheckIn.getContentUri(context)) {
put(CheckIn.HIDE_LAUNCHER_ICON, enabled)
}
}
@JvmStatic
fun setEnabled(context: Context, enabled: Boolean) {
SettingsContract.setSettings(context, CheckIn.getContentUri(context)) {
put(CheckIn.ENABLED, enabled)
}
if (enabled) {
context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null)
}
}
}

View file

@ -71,6 +71,15 @@ data class GcmPrefs(
gcmPrefs.setEnabled(context, config.enabled)
}
fun setEnabled(context: Context, enabled: Boolean) {
val prefs = get(context)
setSettings(context, Gcm.getContentUri(context)) {
put(Gcm.ENABLE_GCM, enabled)
}
prefs.setEnabled(context, enabled)
}
@JvmStatic
fun clearLastPersistedId(context: Context) {
setSettings(context, Gcm.getContentUri(context)) {
@ -79,6 +88,7 @@ data class GcmPrefs(
}
}
/**
* Call this whenever the enabled state of GCM has changed.
*/
@ -178,5 +188,4 @@ data class GcmPrefs(
put(Gcm.LAST_PERSISTENT_ID, newId)
}
}
}

View file

@ -16,7 +16,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import org.microg.gms.checkin.CheckinPrefs
import org.microg.gms.checkin.CheckinPreferences
import org.microg.gms.checkin.CheckinService
import org.microg.gms.checkin.LastCheckinInfo
import org.microg.gms.common.ForegroundServiceContext
@ -29,7 +29,7 @@ import kotlin.coroutines.suspendCoroutine
private const val TAG = "GmsGcmRegister"
private suspend fun ensureCheckinIsUpToDate(context: Context) {
if (!CheckinPrefs.isEnabled(context)) throw RuntimeException("Checkin disabled")
if (!CheckinPreferences.isEnabled(context)) throw RuntimeException("Checkin disabled")
val lastCheckin = LastCheckinInfo.read(context).lastCheckin
if (lastCheckin < System.currentTimeMillis() - CheckinService.MAX_VALID_CHECKIN_AGE) {
val resultData: Bundle = suspendCoroutine { continuation ->

View file

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.net.Uri
import android.provider.Settings
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.ImageView
import androidx.appcompat.content.res.AppCompatResources
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import org.microg.gms.base.core.R
class AppHeadingPreference : AppPreference, Preference.OnPreferenceClickListener {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context) : super(context)
init {
layoutResource = R.layout.preference_app_heading
onPreferenceClickListener = this
}
override fun onPreferenceClick(preference: Preference): Boolean {
if (packageName != null) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri: Uri = Uri.fromParts("package", packageName, null)
intent.data = uri
try {
context.startActivity(intent)
} catch (e: Exception) {
Log.w(TAG, "Failed to launch app", e)
}
return true
} else {
return false
}
}
}

View file

@ -11,8 +11,9 @@ import android.util.DisplayMetrics
import android.widget.ImageView
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import android.content.pm.ApplicationInfo
class AppIconPreference : Preference {
class AppIconPreference : AppPreference {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

View file

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
import android.content.Context
import android.content.pm.ApplicationInfo
import android.util.AttributeSet
import androidx.appcompat.content.res.AppCompatResources
import androidx.preference.Preference
abstract class AppPreference : Preference {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context) : super(context)
init {
isPersistent = false
}
private var packageNameField: String? = null
var applicationInfo: ApplicationInfo?
get() = context.packageManager.getApplicationInfoIfExists(packageNameField)
set(value) {
if (value == null && packageNameField != null) {
title = null
icon = null
} else if (value != null) {
val pm = context.packageManager
title = value.loadLabel(pm) ?: value.packageName
icon = value.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)
}
packageNameField = value?.packageName
}
var packageName: String?
get() = packageNameField
set(value) {
if (value == null && packageNameField != null) {
title = null
icon = null
} else if (value != null) {
val pm = context.packageManager
val applicationInfo = pm.getApplicationInfoIfExists(value)
title = applicationInfo?.loadLabel(pm)?.toString() ?: value
icon = applicationInfo?.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)
}
packageNameField = value
}
}

View file

@ -5,51 +5,163 @@
package org.microg.gms.ui
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
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.mgoogle.android.gms.R
import com.mgoogle.android.gms.databinding.DeviceRegistrationFragmentBinding
import org.microg.gms.checkin.ServiceInfo
import org.microg.gms.checkin.CheckinPreferences
import org.microg.gms.checkin.getCheckinServiceInfo
import org.microg.gms.checkin.setCheckinServiceConfiguration
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 DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragment) {
private lateinit var binding: DeviceRegistrationFragmentBinding
class DeviceRegistrationFragment : PreferenceFragmentCompat() {
private lateinit var switchBarPreference: SwitchBarPreference
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 onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DeviceRegistrationFragmentBinding.inflate(inflater, container, false)
binding.switchBarCallback = object : PreferenceSwitchBarCallback {
override fun onChecked(newStatus: Boolean) {
setEnabled(newStatus)
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)
}
@SuppressLint("RestrictedApi")
override fun onBindPreferences() {
switchBarPreference = preferenceScreen.findPreference("pref_checkin_enabled") ?: switchBarPreference
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
}
switchBarPreference.setOnPreferenceChangeListener { _, newValue ->
val newStatus = newValue as Boolean
CheckinPreferences.setEnabled(requireContext(), newStatus)
true
}
}
private fun configureProfilePreference() {
val context = requireContext()
val configuredProfile = ProfileManager.getConfiguredProfile(context)
val autoProfile = ProfileManager.getAutoProfile(context)
val autoProfileName = when (autoProfile) {
PROFILE_NATIVE -> getString(R.string.profile_name_native)
PROFILE_REAL -> getString(R.string.profile_name_real)
else -> ProfileManager.getProfileName(context, autoProfile)
}
val profiles =
mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL)
val profileNames = mutableListOf(getString(R.string.profile_name_auto, autoProfileName), getString(R.string.profile_name_native), getString(R.string.profile_name_real))
if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) {
profiles.add(PROFILE_SYSTEM)
profileNames.add(getString(R.string.profile_name_system, ProfileManager.getProfileName(context, PROFILE_SYSTEM)))
}
if (ProfileManager.hasProfile(context, PROFILE_USER)) {
profiles.add(PROFILE_USER)
profileNames.add(getString(R.string.profile_name_user, 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)
}
}
return binding.root
}
fun setEnabled(newStatus: Boolean) {
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
val info = getCheckinServiceInfo(appContext)
val newConfiguration = info.configuration.copy(enabled = newStatus)
setCheckinServiceConfiguration(appContext, newConfiguration)
displayServiceInfo(info.copy(configuration = newConfiguration))
}
}
private fun displayServiceInfo(serviceInfo: ServiceInfo) {
binding.checkinEnabled = serviceInfo.configuration.enabled
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()
switchBarPreference.isChecked = CheckinPreferences.isEnabled(requireContext())
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 {
displayServiceInfo(getCheckinServiceInfo(appContext))
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
}
}

View file

@ -1,164 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
import android.annotation.SuppressLint
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.mgoogle.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
@Suppress("Warnings")
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)
}
@SuppressLint("RestrictedApi")
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 autoProfileName = when (val autoProfile = ProfileManager.getAutoProfile(context)) {
PROFILE_NATIVE -> getString(R.string.profile_name_native)
PROFILE_REAL -> getString(R.string.profile_name_real)
else -> ProfileManager.getProfileName(context, autoProfile)
}
val profiles =
mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL)
val profileNames = mutableListOf(getString(R.string.profile_name_auto, autoProfileName), getString(R.string.profile_name_native), getString(R.string.profile_name_real))
if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) {
profiles.add(PROFILE_SYSTEM)
profileNames.add(getString(R.string.profile_name_system, ProfileManager.getProfileName(context, PROFILE_SYSTEM)))
}
if (ProfileManager.hasProfile(context, PROFILE_USER)) {
profiles.add(PROFILE_USER)
profileNames.add(getString(R.string.profile_name_user, 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 = true
}
}
}
companion object {
private const val UPDATE_INTERVAL = 1000L
}
}

View file

@ -1,10 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
interface PreferenceSwitchBarCallback {
fun onChecked(newStatus: Boolean)
}

View file

@ -56,16 +56,12 @@ class PushNotificationAllAppsFragment : PreferenceFragmentCompat() {
lifecycleScope.launchWhenResumed {
val apps = withContext(Dispatchers.IO) {
val res = database.appList.map { app ->
app to context.packageManager.getApplicationInfoIfExists(app.packageName)
}.map { (app, applicationInfo) ->
val pref = AppIconPreference(context)
pref.title = applicationInfo?.loadLabel(context.packageManager) ?: app.packageName
pref.packageName = app.packageName
pref.summary = when {
app.lastMessageTimestamp > 0 -> getString(R.string.gcm_last_message_at, DateUtils.getRelativeTimeSpanString(app.lastMessageTimestamp))
else -> null
}
pref.icon = applicationInfo?.loadIcon(context.packageManager)
?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
findNavController().navigate(requireContext(), R.id.openGcmAppDetailsFromAll, bundleOf(
"package" to app.packageName

View file

@ -5,58 +5,135 @@
package org.microg.gms.ui
import android.content.Intent
import android.net.Uri
import android.annotation.SuppressLint
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import android.text.format.DateUtils
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import com.mgoogle.android.gms.R
import com.mgoogle.android.gms.databinding.PushNotificationAppFragmentBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.microg.gms.gcm.GcmDatabase
import org.microg.gms.gcm.PushRegisterManager
class PushNotificationAppFragment : PreferenceFragmentCompat() {
private lateinit var appHeadingPreference: AppHeadingPreference
private lateinit var wakeForDelivery: TwoStatePreference
private lateinit var allowRegister: TwoStatePreference
private lateinit var status: Preference
private lateinit var unregister: Preference
private lateinit var unregisterCat: PreferenceCategory
class PushNotificationAppFragment : Fragment(R.layout.push_notification_fragment) {
lateinit var binding: PushNotificationAppFragmentBinding
val packageName: String?
private lateinit var database: GcmDatabase
private val packageName: String?
get() = arguments?.getString("package")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = PushNotificationAppFragmentBinding.inflate(inflater, container, false)
binding.callbacks = object : PushNotificationAppFragmentCallbacks {
override fun onAppClicked() {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri: Uri = Uri.fromParts("package", packageName, null)
intent.data = uri
try {
context!!.startActivity(intent)
} catch (e: Exception) {
Log.w(TAG, "Failed to launch app", e)
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_push_notifications_app)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
database = GcmDatabase(context)
}
@SuppressLint("RestrictedApi")
override fun onBindPreferences() {
appHeadingPreference = preferenceScreen.findPreference("pref_push_app_heading") ?: appHeadingPreference
wakeForDelivery = preferenceScreen.findPreference("pref_push_app_wake_for_delivery") ?: wakeForDelivery
allowRegister = preferenceScreen.findPreference("pref_push_app_allow_register") ?: allowRegister
unregister = preferenceScreen.findPreference("pref_push_app_unregister") ?: unregister
unregisterCat = preferenceScreen.findPreference("prefcat_push_app_unregister") ?: unregisterCat
status = preferenceScreen.findPreference("pref_push_app_status") ?: status
wakeForDelivery.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
database.setAppWakeForDelivery(packageName, newValue as Boolean)
database.close()
true
}
allowRegister.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val enabled = newValue as? Boolean ?: return@OnPreferenceChangeListener false
if (!enabled) {
val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()
if (registrations.isNotEmpty()) {
showUnregisterConfirm(R.string.gcm_unregister_after_deny_message)
}
}
database.setAppAllowRegister(packageName, enabled)
database.close()
true
}
unregister.onPreferenceClickListener = Preference.OnPreferenceClickListener {
showUnregisterConfirm(R.string.gcm_unregister_confirm_message)
true
}
}
private fun showUnregisterConfirm(unregisterConfirmDesc: Int) {
val pm = requireContext().packageManager
val applicationInfo = pm.getApplicationInfoIfExists(packageName)
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm)
?: packageName))
.setMessage(unregisterConfirmDesc)
.setPositiveButton(android.R.string.yes) { _, _ -> unregister() }
.setNegativeButton(android.R.string.no) { _, _ -> }.show()
}
private fun unregister() {
lifecycleScope.launchWhenResumed {
withContext(Dispatchers.IO) {
for (registration in database.getRegistrationsByApp(packageName)) {
PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null)
}
}
updateDetails()
}
childFragmentManager.findFragmentById(R.id.sub_preferences)?.arguments = arguments
return binding.root
}
override fun onResume() {
super.onResume()
val context = requireContext()
updateDetails()
}
private fun updateDetails() {
lifecycleScope.launchWhenResumed {
val pm = context.packageManager
val applicationInfo = pm.getApplicationInfoIfExists(packageName)
binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName
binding.appIcon = applicationInfo?.loadIcon(pm)
?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon)
appHeadingPreference.packageName = packageName
val app = packageName?.let { database.getApp(it) }
wakeForDelivery.isChecked = app?.wakeForDelivery ?: true
allowRegister.isChecked = app?.allowRegister ?: true
val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()
unregisterCat.isVisible = registrations.isNotEmpty()
val sb = StringBuilder()
if ((app?.totalMessageCount ?: 0L) == 0L) {
sb.append(getString(R.string.gcm_no_message_yet))
} else {
sb.append(getString(R.string.gcm_messages_counter, app?.totalMessageCount, app?.totalMessageBytes))
if (app?.lastMessageTimestamp != 0L) {
sb.append("\n").append(getString(R.string.gcm_last_message_at, DateUtils.getRelativeDateTimeString(context, app?.lastMessageTimestamp ?: 0L, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))
}
}
for (registration in registrations) {
sb.append("\n")
if (registration.timestamp == 0L) {
sb.append(getString(R.string.gcm_registered))
} else {
sb.append(getString(R.string.gcm_registered_since, DateUtils.getRelativeDateTimeString(context, registration.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))
}
}
status.summary = sb.toString()
database.close()
}
}
}
interface PushNotificationAppFragmentCallbacks {
fun onAppClicked()
}
override fun onPause() {
super.onPause()
database.close()
}
}

View file

@ -1,137 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
@file:Suppress("DEPRECATION")
package org.microg.gms.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.format.DateUtils
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import com.mgoogle.android.gms.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.microg.gms.gcm.GcmDatabase
import org.microg.gms.gcm.PushRegisterManager
class PushNotificationAppPreferencesFragment : PreferenceFragmentCompat() {
private lateinit var wakeForDelivery: TwoStatePreference
private lateinit var allowRegister: TwoStatePreference
private lateinit var status: Preference
private lateinit var unregister: Preference
private lateinit var unregisterCat: PreferenceCategory
private lateinit var database: GcmDatabase
private val packageName: String?
get() = arguments?.getString("package")
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_push_notifications_app)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
database = GcmDatabase(context)
}
@SuppressLint("RestrictedApi")
override fun onBindPreferences() {
wakeForDelivery = preferenceScreen.findPreference("pref_push_app_wake_for_delivery") ?: wakeForDelivery
allowRegister = preferenceScreen.findPreference("pref_push_app_allow_register") ?: allowRegister
unregister = preferenceScreen.findPreference("pref_push_app_unregister") ?: unregister
unregisterCat = preferenceScreen.findPreference("prefcat_push_app_unregister") ?: unregisterCat
status = preferenceScreen.findPreference("pref_push_app_status") ?: status
wakeForDelivery.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
database.setAppWakeForDelivery(packageName, newValue as Boolean)
database.close()
true
}
allowRegister.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
val enabled = newValue as? Boolean ?: return@OnPreferenceChangeListener false
if (!enabled) {
val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()
if (registrations.isNotEmpty()) {
showUnregisterConfirm(R.string.gcm_unregister_after_deny_message)
}
}
database.setAppAllowRegister(packageName, enabled)
database.close()
true
}
unregister.onPreferenceClickListener = Preference.OnPreferenceClickListener {
showUnregisterConfirm(R.string.gcm_unregister_confirm_message)
true
}
}
private fun showUnregisterConfirm(unregisterConfirmDesc: Int) {
val pm = requireContext().packageManager
val applicationInfo = pm.getApplicationInfoIfExists(packageName)
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm)
?: packageName))
.setMessage(unregisterConfirmDesc)
.setPositiveButton(android.R.string.yes) { _, _ -> unregister() }
.setNegativeButton(android.R.string.no) { _, _ -> }.show()
}
private fun unregister() {
lifecycleScope.launchWhenResumed {
withContext(Dispatchers.IO) {
for (registration in database.getRegistrationsByApp(packageName)) {
PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null)
}
}
updateDetails()
}
}
override fun onResume() {
super.onResume()
updateDetails()
}
private fun updateDetails() {
lifecycleScope.launchWhenResumed {
val app = packageName?.let { database.getApp(it) }
wakeForDelivery.isChecked = app?.wakeForDelivery ?: true
allowRegister.isChecked = app?.allowRegister ?: true
val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList()
unregisterCat.isVisible = registrations.isNotEmpty()
val sb = StringBuilder()
if ((app?.totalMessageCount ?: 0L) == 0L) {
sb.append(getString(R.string.gcm_no_message_yet))
} else {
sb.append(getString(R.string.gcm_messages_counter, app?.totalMessageCount, app?.totalMessageBytes))
if (app?.lastMessageTimestamp != 0L) {
sb.append("\n").append(getString(R.string.gcm_last_message_at, DateUtils.getRelativeDateTimeString(context, app?.lastMessageTimestamp ?: 0L, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))
}
}
for (registration in registrations) {
sb.append("\n")
if (registration.timestamp == 0L) {
sb.append(getString(R.string.gcm_registered))
} else {
sb.append(getString(R.string.gcm_registered_since, DateUtils.getRelativeDateTimeString(context, registration.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)))
}
}
status.summary = sb.toString()
database.close()
}
}
override fun onPause() {
super.onPause()
database.close()
}
}

View file

@ -2,61 +2,142 @@
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import android.os.Handler
import android.text.format.DateUtils
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.mgoogle.android.gms.R
import com.mgoogle.android.gms.databinding.PushNotificationFragmentBinding
import org.microg.gms.checkin.getCheckinServiceInfo
import org.microg.gms.gcm.ServiceInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.microg.gms.checkin.CheckinPreferences
import org.microg.gms.gcm.GcmDatabase
import org.microg.gms.gcm.GcmPrefs
import org.microg.gms.gcm.getGcmServiceInfo
import org.microg.gms.gcm.setGcmServiceConfiguration
@Suppress("Warnings")
class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) {
lateinit var binding: PushNotificationFragmentBinding
class PushNotificationFragment : PreferenceFragmentCompat() {
private lateinit var switchBarPreference: SwitchBarPreference
private lateinit var pushStatusCategory: PreferenceCategory
private lateinit var pushStatus: Preference
private lateinit var pushApps: PreferenceCategory
private lateinit var pushAppsAll: Preference
private lateinit var pushAppsNone: Preference
private lateinit var database: GcmDatabase
private val handler = Handler()
private val updateRunnable = Runnable { updateStatus() }
init {
setHasOptionsMenu(true)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
database = GcmDatabase(context)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = PushNotificationFragmentBinding.inflate(inflater, container, false)
binding.switchBarCallback = object : PreferenceSwitchBarCallback {
override fun onChecked(newStatus: Boolean) {
setEnabled(newStatus)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_push_notifications)
}
@SuppressLint("RestrictedApi")
override fun onBindPreferences() {
switchBarPreference = preferenceScreen.findPreference("pref_push_enabled") ?: switchBarPreference
pushStatusCategory = preferenceScreen.findPreference("prefcat_push_status") ?: pushStatusCategory
pushStatus = preferenceScreen.findPreference("pref_push_status") ?: pushStatus
pushApps = preferenceScreen.findPreference("prefcat_push_apps") ?: pushApps
pushAppsAll = preferenceScreen.findPreference("pref_push_apps_all") ?: pushAppsAll
pushAppsNone = preferenceScreen.findPreference("pref_push_apps_none") ?: pushAppsNone
pushAppsAll.setOnPreferenceClickListener {
findNavController().navigate(requireContext(), R.id.openAllGcmApps)
true
}
return binding.root
}
fun setEnabled(newStatus: Boolean) {
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
val info = getGcmServiceInfo(appContext)
val newConfiguration = info.configuration.copy(enabled = newStatus)
setGcmServiceConfiguration(appContext, newConfiguration)
displayServiceInfo(info.copy(configuration = newConfiguration))
switchBarPreference.setOnPreferenceChangeListener { _, newValue ->
val newStatus = newValue as Boolean
GcmPrefs.setEnabled(requireContext(), newStatus)
true
}
}
private fun displayServiceInfo(serviceInfo: ServiceInfo) {
binding.gcmEnabled = serviceInfo.configuration.enabled
}
override fun onResume() {
super.onResume()
switchBarPreference.isEnabled = CheckinPreferences.isEnabled(requireContext())
switchBarPreference.isChecked = GcmPrefs.get(requireContext()).isEnabled
updateStatus()
updateContent()
}
override fun onPause() {
super.onPause()
database.close()
handler.removeCallbacks(updateRunnable)
}
private fun updateStatus() {
handler.postDelayed(updateRunnable, UPDATE_INTERVAL)
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenResumed {
displayServiceInfo(getGcmServiceInfo(appContext))
binding.checkinEnabled = getCheckinServiceInfo(appContext).configuration.enabled
lifecycleScope.launchWhenStarted {
val statusInfo = getGcmServiceInfo(appContext)
switchBarPreference.isChecked = statusInfo.configuration.enabled
pushStatusCategory.isVisible = statusInfo != null && statusInfo.configuration.enabled
pushStatus.summary = if (statusInfo != null && statusInfo.connected) {
appContext.getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0))
} else {
appContext.getString(R.string.gcm_network_state_disconnected)
}
}
}
private fun updateContent() {
lifecycleScope.launchWhenResumed {
val context = requireContext()
val (apps, showAll) = withContext(Dispatchers.IO) {
val apps = database.appList.sortedByDescending { it.lastMessageTimestamp }
val res = apps.map { app ->
app to context.packageManager.getApplicationInfoIfExists(app.packageName)
}.mapNotNull { (app, info) ->
if (info == null) null else app to info
}.take(3).mapIndexed { idx, (app, applicationInfo) ->
val pref = AppIconPreference(context)
pref.order = idx
pref.applicationInfo = applicationInfo
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
findNavController().navigate(requireContext(), R.id.openGcmAppDetails, bundleOf(
"package" to app.packageName
))
true
}
pref.key = "pref_push_app_" + app.packageName
pref
}.let { it to (it.size < apps.size) }
database.close()
res
}
pushAppsAll.isVisible = showAll
pushApps.removeAll()
for (app in apps) {
pushApps.addPreference(app)
}
if (showAll) {
pushApps.addPreference(pushAppsAll)
} else if (apps.isEmpty()) {
pushApps.addPreference(pushAppsNone)
}
}
}
init {
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.add(0, MENU_ADVANCED, 0, R.string.menu_advanced)
super.onCreateOptionsMenu(menu, inflater)
@ -73,7 +154,7 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) {
}
companion object {
private const val UPDATE_INTERVAL = 1000L
private const val MENU_ADVANCED = Menu.FIRST
}
}
}

View file

@ -1,128 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
@file:Suppress("DEPRECATION")
package org.microg.gms.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.text.format.DateUtils
import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.mgoogle.android.gms.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.microg.gms.gcm.GcmDatabase
import org.microg.gms.gcm.getGcmServiceInfo
class PushNotificationPreferencesFragment : PreferenceFragmentCompat() {
private lateinit var pushStatusCategory: PreferenceCategory
private lateinit var pushStatus: Preference
private lateinit var pushApps: PreferenceCategory
private lateinit var pushAppsAll: Preference
private lateinit var pushAppsNone: Preference
private lateinit var database: GcmDatabase
private val handler = Handler()
private val updateRunnable = Runnable { updateStatus() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
database = GcmDatabase(context)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_push_notifications)
}
@SuppressLint("RestrictedApi")
override fun onBindPreferences() {
pushStatusCategory = preferenceScreen.findPreference("prefcat_push_status") ?: pushStatusCategory
pushStatus = preferenceScreen.findPreference("pref_push_status") ?: pushStatus
pushApps = preferenceScreen.findPreference("prefcat_push_apps") ?: pushApps
pushAppsAll = preferenceScreen.findPreference("pref_push_apps_all") ?: pushAppsAll
pushAppsNone = preferenceScreen.findPreference("pref_push_apps_none") ?: pushAppsNone
pushAppsAll.onPreferenceClickListener = Preference.OnPreferenceClickListener {
findNavController().navigate(requireContext(), R.id.openAllGcmApps)
true
}
}
override fun onResume() {
super.onResume()
updateStatus()
updateContent()
}
override fun onPause() {
super.onPause()
database.close()
handler.removeCallbacks(updateRunnable)
}
private fun updateStatus() {
try {
handler.postDelayed(updateRunnable, UPDATE_INTERVAL)
val appContext = requireContext().applicationContext
lifecycleScope.launchWhenStarted {
val statusInfo = getGcmServiceInfo(appContext)
pushStatusCategory.isVisible = statusInfo.configuration.enabled
pushStatus.summary = if (statusInfo.connected) {
getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0))
} else {
getString(R.string.gcm_network_state_disconnected)
}
}
} catch (_: Exception) {}
}
private fun updateContent() {
val appContext = requireContext().applicationContext
val context = requireContext()
lifecycleScope.launchWhenResumed {
val (apps, showAll) = withContext(Dispatchers.IO) {
val apps = database.appList.sortedByDescending { it.lastMessageTimestamp }
val res = apps.map { app ->
app to appContext.packageManager.getApplicationInfoIfExists(app.packageName)
}.mapNotNull { (app, info) ->
if (info == null) null else app to info
}.take(3).mapIndexed { idx, (app, applicationInfo) ->
val pref = AppIconPreference(appContext)
pref.order = idx
pref.title = applicationInfo.loadLabel(appContext.packageManager)
pref.icon = applicationInfo.loadIcon(appContext.packageManager)
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
findNavController().navigate(context, R.id.openGcmAppDetails, bundleOf(
"package" to app.packageName
))
true
}
pref.key = "pref_push_app_" + app.packageName
pref
}.let { it to (it.size < apps.size) }
database.close()
res
}
pushAppsAll.isVisible = showAll
pushApps.removeAll()
for (app in apps) {
pushApps.addPreference(app)
}
if (showAll) {
pushApps.addPreference(pushAppsAll)
} else if (apps.isEmpty()) {
pushApps.addPreference(pushAppsNone)
}
}
}
companion object {
private const val UPDATE_INTERVAL = 1000L
}
}

View file

@ -15,7 +15,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat
import com.mgoogle.android.gms.R
import org.microg.gms.checkin.CheckinPrefs
import org.microg.gms.checkin.CheckinPreferences
import org.microg.gms.gcm.GcmDatabase
import org.microg.gms.gcm.GcmPrefs
import org.microg.gms.settings.SettingsContract
@ -112,7 +112,7 @@ class SettingsFragment : ResourceSettingsFragment() {
findPreference<Preference>(PREF_GCM)?.setSummary(R.string.service_status_disabled_short)
}
findPreference<Preference>(PREF_CHECKIN)?.setSummary(if (CheckinPrefs.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short)
findPreference<Preference>(PREF_CHECKIN)?.setSummary(if (CheckinPreferences.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short)
findPreference<Preference>(PREF_PLAY)!!.setSummary(if (PlayPreferences.isLicensingEnabled(requireContext())) R.string.pref_play_summary_licensing_on else R.string.pref_play_summary_licensing_off)
lifecycleScope.launchWhenResumed {

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