Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit a814c7de authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

EN: Request users to enable Bluetoooth/Location access

parent 3dad397d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ public class ForegroundServiceContext extends ContextWrapper {
        context.getSystemService(NotificationManager.class).createNotificationChannel(channel);
        return new Notification.Builder(context, channel.getId())
                .setOngoing(true)
                .setSmallIcon(android.R.drawable.stat_notify_error)
                .setContentTitle("Running in background")
                .setContentText("microG " + context.getClass().getSimpleName() + " is running in background.")
                .build();
+4 −0
Original line number Diff line number Diff line
@@ -9,6 +9,9 @@

    <uses-sdk tools:overrideLibrary="com.db.williamchart" />

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <application>
        <activity
            android:name="org.microg.gms.nearby.core.ui.ExposureNotificationsConfirmActivity"
@@ -26,6 +29,7 @@
            android:theme="@style/Theme.AppCompat.DayNight">
            <intent-filter android:priority="-100">
                <action android:name="com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
+3 −1
Original line number Diff line number Diff line
@@ -92,9 +92,11 @@ class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() {
                }

                reportedExposures.removeAll()
                if (mergedExposures.isNullOrEmpty()) {
                reportedExposures.addPreference(reportedExposuresNone)
                if (mergedExposures.isNullOrEmpty()) {
                    reportedExposuresNone.isVisible = true
                } else {
                    reportedExposuresNone.isVisible = false
                    for (exposure in mergedExposures) {
                        val minAttenuation = exposure.subs.map { it.attenuation }.minOrNull() ?: exposure.attenuation
                        val nearby = exposure.attenuation < 63 || minAttenuation < 55
+84 −6
Original line number Diff line number Diff line
@@ -5,18 +5,26 @@

package org.microg.gms.nearby.core.ui

import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.os.ResultReceiver
import android.provider.Settings
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.location.LocationManagerCompat
import androidx.lifecycle.lifecycleScope
import org.microg.gms.nearby.exposurenotification.*
import org.microg.gms.ui.getApplicationInfoIfExists


class ExposureNotificationsConfirmActivity : AppCompatActivity() {
    private var resultCode: Int = RESULT_CANCELED
        set(value) {
@@ -44,6 +52,8 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
                findViewById<TextView>(R.id.grant_permission_summary).text = getString(R.string.exposure_confirm_permission_description, selfApplicationInfo?.loadLabel(packageManager)
                        ?: packageName)
                checkPermissions()
                checkBluetooth()
                checkLocation()
            }
            CONFIRM_ACTION_STOP -> {
                findViewById<TextView>(android.R.id.title).text = getString(R.string.exposure_confirm_stop_title)
@@ -72,8 +82,28 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
        findViewById<Button>(R.id.grant_permission_button).setOnClickListener {
            requestPermissions()
        }
        findViewById<Button>(R.id.enable_bluetooth_button).setOnClickListener {
            requestBluetooth()
        }
        findViewById<Button>(R.id.enable_location_button).setOnClickListener {
            requestLocation()
        }
    }

    override fun onResume() {
        super.onResume()
        if (permissionNeedsHandling) checkPermissions()
        if (bluetoothNeedsHandling) checkBluetooth()
        if (locationNeedsHandling) checkLocation()
    }

    private fun updateButton() {
        findViewById<Button>(android.R.id.button1).isEnabled = !permissionNeedsHandling && !bluetoothNeedsHandling && !locationNeedsHandling
    }

    // Permissions
    private var permissionNeedsHandling: Boolean = false
    private var permissionRequestCode = 33
    private val permissions by lazy {
        if (Build.VERSION.SDK_INT >= 29) {
            arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION")
@@ -81,22 +111,70 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
            arrayOf("android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION")
        }
    }
    private var requestCode = 33
    private fun checkPermissions() {
        val needRequest = Build.VERSION.SDK_INT >= 23 && permissions.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
        findViewById<Button>(android.R.id.button1).isEnabled = !needRequest
        findViewById<View>(R.id.grant_permission_view).visibility = if (needRequest) View.VISIBLE else View.GONE
        permissionNeedsHandling = Build.VERSION.SDK_INT >= 23 && permissions.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
        findViewById<View>(R.id.grant_permission_view).visibility = if (permissionNeedsHandling) View.VISIBLE else View.GONE
        updateButton()
    }

    private fun requestPermissions() {
        if (Build.VERSION.SDK_INT >= 23) {
            requestPermissions(permissions, ++requestCode)
            requestPermissions(permissions, ++permissionRequestCode)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == this.requestCode) checkPermissions()
        if (requestCode == this.permissionRequestCode) checkPermissions()
    }

    // Bluetooth
    private var bluetoothNeedsHandling: Boolean = false
    private var bluetoothRequestCode = 112
    private fun checkBluetooth() {
        val adapter = BluetoothAdapter.getDefaultAdapter()
        bluetoothNeedsHandling = adapter?.isEnabled != true
        findViewById<View>(R.id.enable_bluetooth_view).visibility = if (adapter?.isEnabled == false) View.VISIBLE else View.GONE
        updateButton()
    }

    private fun requestBluetooth() {
        val adapter = BluetoothAdapter.getDefaultAdapter()
        findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.VISIBLE
        findViewById<View>(R.id.enable_bluetooth_button).visibility = View.INVISIBLE
        lifecycleScope.launchWhenStarted {
            if (adapter != null && !adapter.enableAsync(this@ExposureNotificationsConfirmActivity)) {
                requestBluetoothViaIntent()
            } else {
                checkBluetooth()
            }
            findViewById<View>(R.id.enable_bluetooth_spinner).visibility = View.INVISIBLE
            findViewById<View>(R.id.enable_bluetooth_button).visibility = View.VISIBLE
        }
    }

    private fun requestBluetoothViaIntent() {
        val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        startActivityForResult(intent, ++bluetoothRequestCode)
    }

    // Location
    private var locationNeedsHandling: Boolean = false
    private var locationRequestCode = 231
    private fun checkLocation() {
        locationNeedsHandling = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)
        findViewById<View>(R.id.enable_location_view).visibility = if (locationNeedsHandling) View.VISIBLE else View.GONE
        updateButton()
    }

    private fun requestLocation() {
        val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
        startActivityForResult(intent, ++locationRequestCode)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == bluetoothRequestCode) checkBluetooth()
    }

    override fun finish() {
+20 −25
Original line number Diff line number Diff line
@@ -12,16 +12,16 @@ import android.location.LocationManager
import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.util.Log
import android.view.View
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.AdvertiserService
import org.microg.gms.nearby.exposurenotification.ExposureDatabase
import org.microg.gms.nearby.exposurenotification.ScannerService
import org.microg.gms.nearby.exposurenotification.getExposureNotificationsServiceInfo
import org.microg.gms.nearby.exposurenotification.*
import org.microg.gms.ui.AppIconPreference
import org.microg.gms.ui.getApplicationInfoIfExists
import org.microg.gms.ui.navigate
@@ -37,6 +37,7 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
    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() }
@@ -63,8 +64,19 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
        }

        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)
            startActivity(intent)
                    startActivityForResult(intent, 144)
                } else {
                    turningBluetoothOn = false
                    updateStatus()
                }
            }
            true
        }

@@ -88,23 +100,6 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
        handler.removeCallbacks(updateContentRunnable)
    }

    private fun isLocationEnabled(): Boolean {
        val lm = requireContext().getSystemService(LOCATION_SERVICE) as LocationManager
        var gpsEnabled = false
        var networkEnabled = false

        try {
            gpsEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER)
        } catch (ex: Exception) {
        }

        try {
            networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        } catch (ex: Exception) {
        }
        return gpsEnabled || networkEnabled
    }

    private fun updateStatus() {
        lifecycleScope.launchWhenResumed {
            handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL)
@@ -114,8 +109,8 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
            val bluetoothSupported = ScannerService.isSupported(requireContext())
            val advertisingSupported = if (bluetoothSupported == true) AdvertiserService.isSupported(requireContext()) else bluetoothSupported

            exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !isLocationEnabled()
            exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null
            exposureLocationOff.isVisible = enabled && bluetoothSupported != false && !LocationManagerCompat.isLocationEnabled(requireContext().getSystemService(LOCATION_SERVICE) as LocationManager)
            exposureBluetoothOff.isVisible = enabled && bluetoothSupported == null && !turningBluetoothOn
            exposureBluetoothUnsupported.isVisible = enabled && bluetoothSupported == false
            exposureBluetoothNoAdvertisement.isVisible = enabled && bluetoothSupported == true && advertisingSupported != true

Loading