improve background location request flow

Instead of directly jumping to the settings screen (which is what the
"Request background location access" amounts to) and leaving the user
there without a clue what to do, we update the label, icon and button
with new text explaining what the user needs to do next.
This commit is contained in:
Marcus Hoffmann 2021-11-09 03:08:01 +01:00 committed by Marvin W
parent 6cfc0aa255
commit 80b3129356
5 changed files with 133 additions and 26 deletions

View File

@ -82,6 +82,9 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
findViewById<Button>(R.id.grant_permission_button).setOnClickListener { findViewById<Button>(R.id.grant_permission_button).setOnClickListener {
requestPermissions() requestPermissions()
} }
findViewById<Button>(R.id.grant_background_location_button).setOnClickListener {
requestBackgroundLocation()
}
findViewById<Button>(R.id.enable_bluetooth_button).setOnClickListener { findViewById<Button>(R.id.enable_bluetooth_button).setOnClickListener {
requestBluetooth() requestBluetooth()
} }
@ -98,50 +101,87 @@ class ExposureNotificationsConfirmActivity : AppCompatActivity() {
} }
private fun updateButton() { private fun updateButton() {
findViewById<Button>(android.R.id.button1).isEnabled = !permissionNeedsHandling && !bluetoothNeedsHandling && !locationNeedsHandling findViewById<Button>(android.R.id.button1).isEnabled =
!permissionNeedsHandling && !backgroundLocationNeedsHandling && !bluetoothNeedsHandling && !locationNeedsHandling
} }
// Permissions // Permissions
private var permissionNeedsHandling: Boolean = false private var permissionNeedsHandling: Boolean = false
private var backgroundLocationNeedsHandling: Boolean = false
private var permissionRequestCode = 33 private var permissionRequestCode = 33
private val permissions by lazy { private val permissions by lazy {
if (Build.VERSION.SDK_INT >= 31){ when {
arrayOf("android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_SCAN", "android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION") Build.VERSION.SDK_INT >= 31 -> {
// We shouldn't be needing the LOCATION permissions on 31+ anymore, at least when
} // apps making use of this target 31+ as well, but this needs more testing. See
else if (Build.VERSION.SDK_INT >= 29) { // https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#assert-never-for-location
arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION") arrayOf(
} else { "android.permission.BLUETOOTH_ADVERTISE",
arrayOf("android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION") "android.permission.BLUETOOTH_SCAN",
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION"
)
}
Build.VERSION.SDK_INT == 29 -> {
// We only can directly request background location permission on 29.
// We need it on 30 (and possibly later) as well, but it has to be requested in a two
// step process, see https://fosstodon.org/@utf8equalsX/104359649537615235
arrayOf(
"android.permission.ACCESS_BACKGROUND_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION"
)
}
else -> {
// Below 29 or equals 30
arrayOf(
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION"
)
}
} }
} }
private fun checkPermissions() { private fun checkPermissions() {
permissionNeedsHandling = Build.VERSION.SDK_INT >= 23 && permissions.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED } permissionNeedsHandling = Build.VERSION.SDK_INT >= 23 && permissions.any {
findViewById<View>(R.id.grant_permission_view).visibility = if (permissionNeedsHandling) View.VISIBLE else View.GONE ContextCompat.checkSelfPermission(
this,
it
) != PackageManager.PERMISSION_GRANTED
}
backgroundLocationNeedsHandling = Build.VERSION.SDK_INT >= 30
&& ContextCompat.checkSelfPermission(
this,
"android.permission.ACCESS_FINE_LOCATION"
) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
this,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
findViewById<View>(R.id.grant_permission_view).visibility =
if (permissionNeedsHandling) View.VISIBLE else View.GONE
findViewById<View>(R.id.grant_background_location_view).visibility =
if (!permissionNeedsHandling && backgroundLocationNeedsHandling) View.VISIBLE else View.GONE
updateButton() updateButton()
} }
private fun requestPermissions() { private fun requestPermissions() {
when { if (Build.VERSION.SDK_INT >= 23) {
Build.VERSION.SDK_INT >= 30 -> requestPermissions( requestPermissions(permissions, ++permissionRequestCode)
permissions.toSet().minus("android.permission.ACCESS_BACKGROUND_LOCATION").toTypedArray(), ++permissionRequestCode }
) }
Build.VERSION.SDK_INT >= 23 -> requestPermissions(permissions, ++permissionRequestCode)
private fun requestBackgroundLocation() {
if (Build.VERSION.SDK_INT >= 23) {
requestPermissions(arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION"), ++permissionRequestCode)
} }
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == this.permissionRequestCode) { if (requestCode == this.permissionRequestCode) checkPermissions()
when {
Build.VERSION.SDK_INT >= 30 && permissions.contains("android.permission.ACCESS_FINE_LOCATION") ->
requestPermissions(
arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION"),
++permissionRequestCode
)
else -> checkPermissions()
}
}
} }
// Bluetooth // Bluetooth

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorAccent">
<path
android:fillColor="#000"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
<path
android:fillColor="#000"
android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
</vector>

View File

@ -90,6 +90,54 @@
android:textColor="?android:attr/textColorPrimaryInverse" /> android:textColor="?android:attr/textColorPrimaryInverse" />
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/grant_background_location_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="?attr/colorAccent"
android:clipToPadding="false"
android:paddingLeft="16dp"
android:paddingTop="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:id="@+id/grant_background_location_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignTop="@id/grant_background_location_summary"
android:layout_alignBottom="@id/grant_background_location_summary"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_outline_location_on"
app:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/grant_background_location_summary"
style="@style/TextAppearance.AppCompat.Small.Inverse"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="16dp"
android:layout_toRightOf="@id/grant_background_location_icon"
android:layout_weight="1"
android:text="@string/exposure_grant_background_location_description"/>
<Button
android:id="@+id/grant_background_location_button"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/grant_background_location_summary"
android:layout_alignLeft="@id/grant_background_location_summary"
android:layout_marginLeft="-16dp"
android:text="@string/exposure_grant_background_location_button"
android:textColor="?android:attr/textColorPrimaryInverse" />
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/enable_bluetooth_view" android:id="@+id/enable_bluetooth_view"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -66,4 +66,8 @@ Deine Identität oder das Testergebnis werden nicht geteilt."</string>
<string name="exposure_confirm_bluetooth_description">Bluetooth muss eingeschaltet sein.</string> <string name="exposure_confirm_bluetooth_description">Bluetooth muss eingeschaltet sein.</string>
<string name="exposure_confirm_location_description">Standortzugriff muss eingeschaltet sein.</string> <string name="exposure_confirm_location_description">Standortzugriff muss eingeschaltet sein.</string>
<string name="exposure_confirm_button">Aktivieren</string> <string name="exposure_confirm_button">Aktivieren</string>
<string name="pref_exposure_error_nearby_not_granted_title">Neue Berechtigung benötigt</string>
<string name="pref_exposure_error_nearby_not_granted_description">Tippe hier um die benötigten Berechtigungen zu erteilen</string>
<string name="exposure_grant_background_location_description">Fast geschafft! Du musst den Zugriff auf den Standort im Hintergrund erlauben indem du auf dem nächsten Bildschirm \'Immer zulassen\' auswählst und dann hierher zurück kommst.</string>
<string name="exposure_grant_background_location_button">Einstellungen Öffnen</string>
</resources> </resources>

View File

@ -78,4 +78,6 @@ Your identity or test result won&apos;t be shared with other people."</string>
<string name="exposure_confirm_button">Enable</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_title">New Permissions required</string>
<string name="pref_exposure_error_nearby_not_granted_description">Tap to grant required permissions to Exposure Notifications</string> <string name="pref_exposure_error_nearby_not_granted_description">Tap to grant required permissions to Exposure Notifications</string>
<string name="exposure_grant_background_location_description">Almost there! You will need to enable background location access by selecting the \'Allow all the time\' option on the next screen. Then press back.</string>
<string name="exposure_grant_background_location_button">Update Settings</string>
</resources> </resources>