mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-11-11 14:49:24 +01:00
request BLUETOOTH_SCAN and ADVERTISE permissions on Android 12
This also adds a warning notification when the app doesn't have the required permission after an OS update.
This commit is contained in:
parent
4a5c98491b
commit
6cfc0aa255
@ -105,7 +105,11 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
|
||||
private var permissionNeedsHandling: Boolean = false
|
||||
private var permissionRequestCode = 33
|
||||
private val permissions by lazy {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
if (Build.VERSION.SDK_INT >= 31){
|
||||
arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN", "android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION")
|
||||
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= 29) {
|
||||
arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION")
|
||||
} else {
|
||||
arrayOf("android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION")
|
||||
|
@ -8,12 +8,13 @@ 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 android.util.Log
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.location.LocationManagerCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -31,6 +32,7 @@ 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
|
||||
@ -41,6 +43,7 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
|
||||
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)
|
||||
@ -50,6 +53,7 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
|
||||
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
|
||||
@ -80,12 +84,28 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
|
||||
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()
|
||||
|
||||
@ -110,6 +130,11 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() {
|
||||
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
|
||||
|
@ -76,4 +76,6 @@ Your identity or test result won't be shared with other people."</string>
|
||||
<string name="exposure_confirm_bluetooth_description">Bluetooth needs to be enabled.</string>
|
||||
<string name="exposure_confirm_location_description">Location access is required.</string>
|
||||
<string name="exposure_confirm_button">Enable</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_title">New Permissions required</string>
|
||||
<string name="pref_exposure_error_nearby_not_granted_description">Tap to grant required permissions to Exposure Notifications</string>
|
||||
</resources>
|
||||
|
@ -31,6 +31,14 @@
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_info_outline"
|
||||
android:key="pref_exposure_error_nearby_not_granted"
|
||||
android:title="@string/pref_exposure_error_nearby_not_granted_title"
|
||||
android:summary="@string/pref_exposure_error_nearby_not_granted_description"
|
||||
app:isPreferenceVisible="false"
|
||||
tools:isPreferenceVisible="true" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_alert"
|
||||
android:key="pref_exposure_error_bluetooth_unsupported"
|
||||
|
@ -147,7 +147,11 @@ class AdvertiserService : LifecycleService() {
|
||||
.setTxPowerLevel(AdvertisingSetParameters.TX_POWER_LOW)
|
||||
.setConnectable(false)
|
||||
.build()
|
||||
advertiser.startAdvertisingSet(params, data, null, null, null, setCallback as AdvertisingSetCallback)
|
||||
try {
|
||||
advertiser.startAdvertisingSet(params, data, null, null, null, setCallback as AdvertisingSetCallback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start advertising: Need android.permission.BLUETOOTH_ADVERTISE permission.", )
|
||||
}
|
||||
} else {
|
||||
nextSend = nextSend.coerceAtMost(180000)
|
||||
val settings = Builder()
|
||||
@ -156,7 +160,11 @@ class AdvertiserService : LifecycleService() {
|
||||
.setTxPowerLevel(ADVERTISE_TX_POWER_LOW)
|
||||
.setConnectable(false)
|
||||
.build()
|
||||
advertiser.startAdvertising(settings, data, callback)
|
||||
try {
|
||||
advertiser.startAdvertising(settings, data, callback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start advertising: Need android.permission.BLUETOOTH_ADVERTISE permission.", )
|
||||
}
|
||||
}
|
||||
synchronized(this) { advertising = true }
|
||||
sendingBytes = payload
|
||||
@ -204,7 +212,11 @@ class AdvertiserService : LifecycleService() {
|
||||
advertising = false
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
wantStartAdvertising = true
|
||||
advertiser?.stopAdvertisingSet(setCallback as AdvertisingSetCallback)
|
||||
try {
|
||||
advertiser?.stopAdvertisingSet(setCallback as AdvertisingSetCallback)
|
||||
} catch (e: SecurityException) {
|
||||
Log.i(TAG, "Tried calling stopAdvertisingSet without android.permission.BLUETOOTH_ADVERTISE permission.", )
|
||||
}
|
||||
} else {
|
||||
advertiser?.stopAdvertising(callback)
|
||||
}
|
||||
|
@ -42,3 +42,5 @@ const val CLEANUP_INTERVAL = 24 * 60 * 60 * 1000L
|
||||
|
||||
const val VERSION_1_0: Byte = 0x40
|
||||
const val VERSION_1_1: Byte = 0x50
|
||||
|
||||
const val NOTIFICATION_UPDATE_ACTION = "org.microg.gms.nearby.UPDATE_NOTIFICATION"
|
||||
|
@ -12,6 +12,7 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.location.LocationManager
|
||||
import android.os.Build
|
||||
@ -53,9 +54,14 @@ class NotifyService : LifecycleService() {
|
||||
private fun updateNotification() {
|
||||
val location = !LocationManagerCompat.isLocationEnabled(getSystemService(Context.LOCATION_SERVICE) as LocationManager)
|
||||
val bluetooth = BluetoothAdapter.getDefaultAdapter()?.state.let { it != BluetoothAdapter.STATE_ON && it != BluetoothAdapter.STATE_TURNING_ON }
|
||||
Log.d(TAG, "notify: location: $location, bluetooth: $bluetooth")
|
||||
val nearbyPermissions = arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN")
|
||||
val permissionNeedsHandling = Build.VERSION.SDK_INT >= 31 && nearbyPermissions.any {
|
||||
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
Log.d( TAG,"notify: location: $location, bluetooth: $bluetooth, permissionNeedsHandling: $permissionNeedsHandling")
|
||||
|
||||
val text: String = when {
|
||||
permissionNeedsHandling -> getString(R.string.exposure_notify_off_nearby)
|
||||
location && bluetooth -> getString(R.string.exposure_notify_off_bluetooth_location)
|
||||
location -> getString(R.string.exposure_notify_off_location)
|
||||
bluetooth -> getString(R.string.exposure_notify_off_bluetooth)
|
||||
@ -105,6 +111,7 @@ class NotifyService : LifecycleService() {
|
||||
addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
|
||||
if (Build.VERSION.SDK_INT >= 19) addAction(LocationManager.MODE_CHANGED_ACTION)
|
||||
addAction(LocationManager.PROVIDERS_CHANGED_ACTION)
|
||||
addAction(NOTIFICATION_UPDATE_ACTION)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -121,14 +121,18 @@ class ScannerService : LifecycleService() {
|
||||
Log.i(TAG, "Starting scanner for service $SERVICE_UUID for ${SCANNING_TIME_MS}ms")
|
||||
seenAdvertisements = 0
|
||||
wakeLock.acquire()
|
||||
scanner.startScan(
|
||||
listOf(ScanFilter.Builder()
|
||||
.setServiceUuid(SERVICE_UUID)
|
||||
.setServiceData(SERVICE_UUID, byteArrayOf(0), byteArrayOf(0))
|
||||
.build()),
|
||||
ScanSettings.Builder().build(),
|
||||
callback
|
||||
)
|
||||
try {
|
||||
scanner.startScan(
|
||||
listOf(ScanFilter.Builder()
|
||||
.setServiceUuid(SERVICE_UUID)
|
||||
.setServiceData(SERVICE_UUID, byteArrayOf(0), byteArrayOf(0))
|
||||
.build()),
|
||||
ScanSettings.Builder().build(),
|
||||
callback
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Couldn't start ScannerService, need android.permission.BLUETOOTH_SCAN permission.")
|
||||
}
|
||||
scanning = true
|
||||
lastStartTime = System.currentTimeMillis()
|
||||
handler.postDelayed(stopLaterRunnable, SCANNING_TIME_MS)
|
||||
|
@ -7,4 +7,5 @@
|
||||
<string name="exposure_notify_off_bluetooth">Bluetooth needs to be enabled to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_location">Location access is required to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_bluetooth_location">Bluetooth and Location access need to be enabled to receive Exposure Notifications.</string>
|
||||
<string name="exposure_notify_off_nearby">Exposure Notifications require additional permissions to work</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user