UI: Unify preferences "microg@d831bbc"
This commit is contained in:
parent
97d91d8c45
commit
b96a8d4727
29 changed files with 742 additions and 795 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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...");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in a new issue