Skip to content

Commit

Permalink
fix(espresso): fix tests relating to to new background location permi…
Browse files Browse the repository at this point in the history
…ssion prompt
  • Loading branch information
growse committed Jul 31, 2024
1 parent 04df53f commit 69e98dc
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import junit.framework.AssertionFailedError
import kotlin.random.Random
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlinx.datetime.Clock
import org.hamcrest.Matcher
import org.owntracks.android.R
import org.owntracks.android.preferences.Preferences
Expand Down Expand Up @@ -209,7 +210,11 @@ fun grantNotificationAndForegroundPermissions() {
/** Who knows what order these will appear in. */
fun grantMapActivityPermissions() {
grantNotificationAndForegroundPermissions()
clickDialogNegativeButton()
// Wait for the dialog to appear
if (Build.VERSION.SDK_INT >= 29) {
waitUntilVisible(onView(withId(android.R.id.button2)))
clickDialogNegativeButton()
}
}

/**
Expand Down Expand Up @@ -317,3 +322,26 @@ fun getText(matcher: ViewInteraction): String {

return text
}

fun waitUntilVisible(matcher: ViewInteraction, timeout: Duration = 1.seconds) {
matcher.perform(
object : ViewAction {
override fun getConstraints(): Matcher<View> {
return ViewMatchers.isAssignableFrom(TextView::class.java)
}

override fun getDescription(): String {
return "Wait until this is visible"
}

override fun perform(uiController: UiController, view: View) {
val endTime = Clock.System.now().plus(timeout)
do {
if (view.visibility == View.VISIBLE) {
return
}
uiController.loopMainThreadUntilIdle()
} while (Clock.System.now() < endTime)
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ class GMSMapActivityTests : TestWithAnActivity<MapActivity>(MapActivity::class.j
}

@Test
fun welcomeActivityShouldNotRunWhenFirstStartPreferencesSet() {
fun welcomeActivityWhenFirstStartPreferencesSetShouldNotRun() {
setNotFirstStartPreferences()
launchActivity()
grantMapActivityPermissions()
assertDisplayed(R.id.google_map_view)
}

@Test
fun mapActivityShouldPromptForLocationServicesOnFirstTime() {
fun mapActivityWhenRunForFirstTimePromptsForLocationServices() {
try {
disableDeviceLocation()
setNotFirstStartPreferences()
Expand Down
106 changes: 57 additions & 49 deletions project/app/src/main/java/org/owntracks/android/ui/map/MapActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -359,33 +359,27 @@ class MapActivity :
Timber.d("Location Services disabled")
if ((explicitUserAction || !preferences.userDeclinedEnableLocationServices)) {
Timber.d("Showing location services dialog")
if (!this::locationServicesAlertDialog.isInitialized) {
locationServicesAlertDialog =
MaterialAlertDialogBuilder(this)
.setCancelable(true)
.setIcon(R.drawable.ic_baseline_location_disabled_24)
.setTitle(getString(R.string.deviceLocationDisabledDialogTitle))
.setMessage(getString(R.string.deviceLocationDisabledDialogMessage))
.setPositiveButton(
getString(R.string.deviceLocationDisabledDialogPositiveButtonLabel)) { _, _ ->
locationServicesLauncher.launch(
Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
preferences.userDeclinedEnableLocationServices = true
}
.create()
}
if (!locationServicesAlertDialog.isShowing) {
locationServicesAlertDialog.show()
}
MaterialAlertDialogBuilder(this)
.setCancelable(true)
.setIcon(R.drawable.ic_baseline_location_disabled_24)
.setTitle(getString(R.string.deviceLocationDisabledDialogTitle))
.setMessage(getString(R.string.deviceLocationDisabledDialogMessage))
.setPositiveButton(
getString(R.string.deviceLocationDisabledDialogPositiveButtonLabel)) { _, _ ->
locationServicesLauncher.launch(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
preferences.userDeclinedEnableLocationServices = true
}
.show()
} else {
Timber.d(
"Not requesting location services. " +
"Explicit=false, previously declined=${preferences.userDeclinedEnableLocationServices}")
}
false
} else {
Timber.d("Location services enabled")
true
}
}
Expand Down Expand Up @@ -453,11 +447,17 @@ class MapActivity :

/**
* User has declined to enable background location permissions. Log this in the preferences so we
* don't keep asking
* don't keep asking.
*
* This may have been called by the user calling cancel on the material dialog in the onResume
* flow so we need to check for location services next
*/
private fun backgroundLocationPermissionDenied() {
Timber.d("Background location permission denied")
preferences.userDeclinedEnableBackgroundLocationPermissions = true
if (checkAndRequestLocationServicesEnabled(false)) {
viewModel.requestLocationUpdatesForBlueDot()
}
}

enum class CheckPermissionsResult {
Expand Down Expand Up @@ -530,6 +530,25 @@ class MapActivity :
}
}

private fun checkAndRequestBackgroundLocationPermissions(): CheckPermissionsResult {
Timber.d("Checking and requesting background location permissions")
return if (!requirementsChecker.hasBackgroundLocationPermission()) {
Timber.d("No background location permission")
if (!preferences.userDeclinedEnableBackgroundLocationPermissions &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Timber.d("Requesting background location permissions")
backgroundLocationPermissionRequester.requestLocationPermissions(this) { true }
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST
} else {
Timber.d("Not requesting background location permission")
CheckPermissionsResult.NO_PERMISSIONS_NOT_LAUNCHED_REQUEST
}
} else {
preferences.userDeclinedEnableBackgroundLocationPermissions = true
CheckPermissionsResult.HAS_PERMISSIONS
}
}

override fun onResume() {
val mapFragment =
supportFragmentManager.fragmentFactory.instantiate(
Expand All @@ -544,34 +563,23 @@ class MapActivity :
updateMonitoringModeMenu()
viewModel.updateMyLocationStatus()

// Request Notification permissions
when (checkAndRequestNotificationPermissions()) {
CheckPermissionsResult.HAS_PERMISSIONS,
CheckPermissionsResult.NO_PERMISSIONS_NOT_LAUNCHED_REQUEST -> {
// Request Location permissions
when (checkAndRequestLocationPermissions(false)) {
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST -> {
Timber.d("Launched location permission request")
}
CheckPermissionsResult.NO_PERMISSIONS_NOT_LAUNCHED_REQUEST -> {
Timber.d("No location permissions, not launched request")
}
CheckPermissionsResult.HAS_PERMISSIONS -> {
Timber.d("Has location permissions")
if (checkAndRequestLocationServicesEnabled(false)) {
viewModel.requestLocationUpdatesForBlueDot()
// Request background location permissions if needed
if (!requirementsChecker.hasBackgroundLocationPermission() &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
!preferences.userDeclinedEnableBackgroundLocationPermissions) {
backgroundLocationPermissionRequester.requestLocationPermissions(this) { true }
}
}
}
}
}
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST ->
Timber.d("Launched notification permission request, not asking for location permissions")
if (checkAndRequestNotificationPermissions() ==
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST) {
Timber.d("Launched notification permission request")
return
}
if (checkAndRequestLocationPermissions(false) ==
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST) {
Timber.d("Launched location permission request")
return
}
if (checkAndRequestBackgroundLocationPermissions() ==
CheckPermissionsResult.NO_PERMISSIONS_LAUNCHED_REQUEST) {
Timber.d("Launched background location permission request")
return
}
if (checkAndRequestLocationServicesEnabled(false)) {
viewModel.requestLocationUpdatesForBlueDot()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BackgroundLocationPermissionRequester(
// The user may have denied us once already, so show a rationale
Timber.d("Showing Background Location permission rationale")
MaterialAlertDialogBuilder(context)
.setCancelable(true)
.setCancelable(false)
.setIcon(R.drawable.baseline_share_location_24)
.setTitle(R.string.backgroundLocationPermissionRequestDialogTitle)
.setMessage(R.string.backgroundLocationPermissionRequestDialogText)
Expand Down

0 comments on commit 69e98dc

Please sign in to comment.