mirror of https://github.com/YTVanced/VancedMicroG
195 lines
9.2 KiB
Kotlin
195 lines
9.2 KiB
Kotlin
/*
|
|
* SPDX-FileCopyrightText: 2020, microG Project Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package org.microg.gms.nearby.core.ui
|
|
|
|
import android.bluetooth.BluetoothAdapter
|
|
import android.content.Context.LOCATION_SERVICE
|
|
import android.content.Intent
|
|
import android.content.pm.PackageManager
|
|
import android.location.LocationManager
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.os.Handler
|
|
import android.provider.Settings
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.core.location.LocationManagerCompat
|
|
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 org.microg.gms.nearby.exposurenotification.*
|
|
import org.microg.gms.ui.AppIconPreference
|
|
import org.microg.gms.ui.getApplicationInfoIfExists
|
|
import org.microg.gms.ui.navigate
|
|
|
|
|
|
class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
|
|
private lateinit var exposureEnableInfo: Preference
|
|
private lateinit var exposureBluetoothOff: Preference
|
|
private lateinit var exposureLocationOff: Preference
|
|
private lateinit var exposureNearbyNotGranted: Preference
|
|
private lateinit var exposureBluetoothUnsupported: Preference
|
|
private lateinit var exposureBluetoothNoAdvertisement: Preference
|
|
private lateinit var exposureApps: PreferenceCategory
|
|
private lateinit var exposureAppsNone: Preference
|
|
private lateinit var collectedRpis: Preference
|
|
private lateinit var advertisingId: Preference
|
|
private var turningBluetoothOn: Boolean = false
|
|
private val handler = Handler()
|
|
private val updateStatusRunnable = Runnable { updateStatus() }
|
|
private val updateContentRunnable = Runnable { updateContent() }
|
|
private var permissionRequestCode = 33
|
|
|
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
addPreferencesFromResource(R.xml.preferences_exposure_notifications)
|
|
}
|
|
|
|
override fun onBindPreferences() {
|
|
exposureEnableInfo = preferenceScreen.findPreference("pref_exposure_enable_info") ?: exposureEnableInfo
|
|
exposureBluetoothOff = preferenceScreen.findPreference("pref_exposure_error_bluetooth_off") ?: exposureBluetoothOff
|
|
exposureLocationOff = preferenceScreen.findPreference("pref_exposure_error_location_off") ?: exposureLocationOff
|
|
exposureNearbyNotGranted = preferenceScreen.findPreference("pref_exposure_error_nearby_not_granted") ?: exposureNearbyNotGranted
|
|
exposureBluetoothUnsupported = preferenceScreen.findPreference("pref_exposure_error_bluetooth_unsupported") ?: exposureBluetoothUnsupported
|
|
exposureBluetoothNoAdvertisement = preferenceScreen.findPreference("pref_exposure_error_bluetooth_no_advertise") ?: exposureBluetoothNoAdvertisement
|
|
exposureApps = preferenceScreen.findPreference("prefcat_exposure_apps") ?: exposureApps
|
|
exposureAppsNone = preferenceScreen.findPreference("pref_exposure_apps_none") ?: exposureAppsNone
|
|
collectedRpis = preferenceScreen.findPreference("pref_exposure_collected_rpis") ?: collectedRpis
|
|
advertisingId = preferenceScreen.findPreference("pref_exposure_advertising_id") ?: advertisingId
|
|
|
|
exposureLocationOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
|
startActivity(intent)
|
|
true
|
|
}
|
|
|
|
exposureBluetoothOff.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
lifecycleScope.launchWhenStarted {
|
|
turningBluetoothOn = true
|
|
it.isVisible = false
|
|
val adapter = BluetoothAdapter.getDefaultAdapter()
|
|
if (adapter != null && !adapter.enableAsync(requireContext())) {
|
|
turningBluetoothOn = false
|
|
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
|
|
startActivityForResult(intent, 144)
|
|
} else {
|
|
turningBluetoothOn = false
|
|
updateStatus()
|
|
}
|
|
}
|
|
true
|
|
}
|
|
|
|
exposureNearbyNotGranted.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
|
requestPermissions(nearbyPermissions, ++permissionRequestCode)
|
|
true
|
|
}
|
|
|
|
collectedRpis.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
findNavController().navigate(requireContext(), R.id.openExposureRpis)
|
|
true
|
|
}
|
|
}
|
|
|
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
if (requestCode == this.permissionRequestCode) {
|
|
updateStatus()
|
|
// Tell the NotifyService that it should update the notification
|
|
val intent = Intent(NOTIFICATION_UPDATE_ACTION)
|
|
requireContext().sendBroadcast(intent)
|
|
}
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
|
|
updateStatus()
|
|
updateContent()
|
|
}
|
|
|
|
override fun onPause() {
|
|
super.onPause()
|
|
|
|
handler.removeCallbacks(updateStatusRunnable)
|
|
handler.removeCallbacks(updateContentRunnable)
|
|
}
|
|
|
|
private fun updateStatus() {
|
|
val appContext = requireContext().applicationContext
|
|
lifecycleScope.launchWhenResumed {
|
|
handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL)
|
|
val enabled = getExposureNotificationsServiceInfo(appContext).configuration.enabled
|
|
exposureEnableInfo.isVisible = !enabled
|
|
|
|
val bluetoothSupported = ScannerService.isSupported(appContext)
|
|
val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(appContext) else bluetoothSupported
|
|
|
|
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
|
val nearbyPermissionsGranted = Build.VERSION.SDK_INT >= 31 || nearbyPermissions.all {
|
|
ContextCompat.checkSelfPermission(appContext, it) == PackageManager.PERMISSION_GRANTED
|
|
}
|
|
exposureNearbyNotGranted.isVisible = enabled && !nearbyPermissionsGranted
|
|
exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(appContext.getSystemService(LOCATION_SERVICE) as LocationManager)
|
|
exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null && !turningBluetoothOn
|
|
exposureBluetoothUnsupported.isVisible = enabled && bluetoothSupported == false
|
|
exposureBluetoothNoAdvertisement.isVisible = enabled && bluetoothSupported == true && advertisingSupported != true
|
|
|
|
advertisingId.isVisible = enabled && advertisingSupported == true
|
|
}
|
|
}
|
|
|
|
private fun updateContent() {
|
|
val context = requireContext()
|
|
lifecycleScope.launchWhenResumed {
|
|
handler.postDelayed(updateContentRunnable, UPDATE_CONTENT_INTERVAL)
|
|
val (apps, lastHourKeys, currentId) = ExposureDatabase.with(context) { database ->
|
|
val apps = database.appList.map { packageName ->
|
|
context.packageManager.getApplicationInfoIfExists(packageName)
|
|
}.filterNotNull().mapIndexed { idx, applicationInfo ->
|
|
val pref = AppIconPreference(context)
|
|
pref.order = idx
|
|
pref.title = applicationInfo.loadLabel(context.packageManager)
|
|
pref.icon = applicationInfo.loadIcon(context.packageManager)
|
|
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
findNavController().navigate(requireContext(), R.id.openExposureAppDetails, bundleOf(
|
|
"package" to applicationInfo.packageName
|
|
))
|
|
true
|
|
}
|
|
pref.key = "pref_exposure_app_" + applicationInfo.packageName
|
|
pref
|
|
}
|
|
val lastHourKeys = database.hourRpiCount
|
|
val currentId = database.currentRpiId
|
|
Triple(apps, lastHourKeys, currentId)
|
|
}
|
|
collectedRpis.summary = getString(R.string.pref_exposure_collected_rpis_summary, lastHourKeys)
|
|
if (currentId != null) {
|
|
advertisingId.isVisible = true
|
|
advertisingId.summary = currentId.toString()
|
|
} else {
|
|
advertisingId.isVisible = false
|
|
}
|
|
exposureApps.removeAll()
|
|
if (apps.isEmpty()) {
|
|
exposureApps.addPreference(exposureAppsNone)
|
|
} else {
|
|
for (app in apps) {
|
|
exposureApps.addPreference(app)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private const val UPDATE_STATUS_INTERVAL = 1000L
|
|
private const val UPDATE_CONTENT_INTERVAL = 60000L
|
|
}
|
|
}
|