Loading play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading play-services-nearby-core-ui/src/main/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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> Loading play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppPreferencesFragment.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsConfirmActivity.kt +84 −6 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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") Loading @@ -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() { Loading play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt +20 −25 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() } Loading @@ -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 } Loading @@ -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) Loading @@ -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 Loading
play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading
play-services-nearby-core-ui/src/main/AndroidManifest.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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> Loading
play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsAppPreferencesFragment.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsConfirmActivity.kt +84 −6 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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") Loading @@ -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() { Loading
play-services-nearby-core-ui/src/main/kotlin/org/microg/gms/nearby/core/ui/ExposureNotificationsPreferencesFragment.kt +20 −25 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() } Loading @@ -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 } Loading @@ -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) Loading @@ -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