Skip to content

Commit

Permalink
Offer to hide AR quests if streetmeasure fails to install or fails to…
Browse files Browse the repository at this point in the history
… return a result (fixes #4849)
  • Loading branch information
westnordost committed Jan 31, 2024
1 parent 2683a20 commit a3c0a5a
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ object ApplicationConstants {
const val NOTIFICATIONS_CHANNEL_SYNC = "downloading"
const val NOTIFICATIONS_ID_SYNC = 1

const val STREETMEASURE = "de.westnordost.streetmeasure"

val IGNORED_RELATION_TYPES = setOf(
// could be useful, but sometimes/often very very large
"route", "route_master", "superroute", "network", "disused:route",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package de.westnordost.streetcomplete.quests

import android.content.ActivityNotFoundException
import android.os.Bundle
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import de.westnordost.streetcomplete.ApplicationConstants.STREETMEASURE
import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.data.meta.LengthUnit
import de.westnordost.streetcomplete.osm.Length
import de.westnordost.streetcomplete.screens.measure.ArQuestsDisabler
import de.westnordost.streetcomplete.screens.measure.MeasureContract
import de.westnordost.streetcomplete.util.ktx.isPackageInstalled
import de.westnordost.streetcomplete.util.ktx.openUri
import org.koin.android.ext.android.inject

/** Abstract superclass for all forms that let StreetMeasure measure stuff. */
abstract class AbstractArMeasureQuestForm<T>: AbstractOsmQuestForm<T>() {
private val arQuestsDisabler: ArQuestsDisabler by inject()

private val launcher = registerForActivityResult(MeasureContract(), ::onMeasuredInternal)

private var requestedARInstall: Boolean = false
private var requestedARMeasurement: Boolean = false

override fun onResume() {
super.onResume()
// returned to app without StreetMeasure installed but requested install before
if (requestedARInstall && !requireContext().packageManager.isPackageInstalled(STREETMEASURE)) {
showDisableARMeasureQuestsDialog(R.string.quest_disable_message_not_installed)
}
requestedARInstall = false
requestedARMeasurement = false
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(AR_INSTALL_REQUESTED, requestedARInstall)
outState.putBoolean(AR_MEASUREMENT_REQUESTED, requestedARMeasurement)
}

fun takeMeasurement(lengthUnit: LengthUnit, measureVertical: Boolean) {
try {
requestedARMeasurement = true
launcher.launch(MeasureContract.Params(lengthUnit, measureVertical))
} catch (e: ActivityNotFoundException) {
requestedARInstall = true
requestedARMeasurement = false
context?.openUri("market://details?id=$STREETMEASURE")
}
}

private fun onMeasuredInternal(length: Length?) {
// returned to app but StreetMeasure did not return a correct result (app crashed?)
if (length == null) {
showDisableARMeasureQuestsDialog(R.string.quest_disable_message_not_working)
return
}
onMeasured(length)
}

protected abstract fun onMeasured(length: Length)

private fun showDisableARMeasureQuestsDialog(@StringRes message: Int) {
val ctx = context ?: return
AlertDialog.Builder(ctx)
.setTitle(R.string.quest_disable_title)
.setMessage(
ctx.getString(message) +
"\n\n" +
ctx.getString(R.string.quest_disable_message_tape_measure)
)
.setPositiveButton(R.string.quest_disable_action) { _, _ ->
arQuestsDisabler.hideAllArQuests()
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}

companion object {
private const val AR_MEASUREMENT_REQUESTED = "ar_measurement_requested"
private const val AR_INSTALL_REQUESTED = "ar_install_requested"
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
package de.westnordost.streetcomplete.quests.max_height

import android.content.ActivityNotFoundException
import android.os.Bundle
import android.view.View
import androidx.core.view.isGone
import de.westnordost.streetcomplete.R
import de.westnordost.streetcomplete.databinding.QuestLengthBinding
import de.westnordost.streetcomplete.osm.Length
import de.westnordost.streetcomplete.quests.AbstractOsmQuestForm
import de.westnordost.streetcomplete.quests.AbstractArMeasureQuestForm
import de.westnordost.streetcomplete.screens.measure.ArSupportChecker
import de.westnordost.streetcomplete.screens.measure.MeasureContract
import de.westnordost.streetcomplete.util.ktx.openUri
import de.westnordost.streetcomplete.view.controller.LengthInputViewController
import org.koin.android.ext.android.inject

class AddMaxPhysicalHeightForm : AbstractOsmQuestForm<MaxPhysicalHeightAnswer>() {
class AddMaxPhysicalHeightForm : AbstractArMeasureQuestForm<MaxPhysicalHeightAnswer>() {

override val contentLayoutResId = R.layout.quest_length
private val binding by contentViewBinding(QuestLengthBinding::bind)
private val launcher = registerForActivityResult(MeasureContract(), ::onMeasured)
private val checkArSupport: ArSupportChecker by inject()
private var isARMeasurement: Boolean = false
private lateinit var lengthInput: LengthInputViewController
Expand Down Expand Up @@ -49,14 +45,10 @@ class AddMaxPhysicalHeightForm : AbstractOsmQuestForm<MaxPhysicalHeightAnswer>()

private fun takeMeasurement() {
val lengthUnit = lengthInput.unit ?: return
try {
launcher.launch(MeasureContract.Params(lengthUnit, true))
} catch (e: ActivityNotFoundException) {
context?.openUri("market://details?id=de.westnordost.streetmeasure")
}
takeMeasurement(lengthUnit, true)
}

private fun onMeasured(length: Length?) {
override fun onMeasured(length: Length) {
lengthInput.length = length
isARMeasurement = true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.westnordost.streetcomplete.quests.width

import android.content.ActivityNotFoundException
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
Expand All @@ -10,18 +9,15 @@ import de.westnordost.streetcomplete.databinding.QuestLengthBinding
import de.westnordost.streetcomplete.osm.ALL_ROADS
import de.westnordost.streetcomplete.osm.Length
import de.westnordost.streetcomplete.osm.hasDubiousRoadWidth
import de.westnordost.streetcomplete.quests.AbstractOsmQuestForm
import de.westnordost.streetcomplete.quests.AbstractArMeasureQuestForm
import de.westnordost.streetcomplete.screens.measure.ArSupportChecker
import de.westnordost.streetcomplete.screens.measure.MeasureContract
import de.westnordost.streetcomplete.util.ktx.openUri
import de.westnordost.streetcomplete.view.controller.LengthInputViewController
import org.koin.android.ext.android.inject

class AddWidthForm : AbstractOsmQuestForm<WidthAnswer>() {
class AddWidthForm : AbstractArMeasureQuestForm<WidthAnswer>() {

override val contentLayoutResId = R.layout.quest_length
private val binding by contentViewBinding(QuestLengthBinding::bind)
private val launcher = registerForActivityResult(MeasureContract(), ::onMeasured)
private val checkArSupport: ArSupportChecker by inject()
private var isARMeasurement: Boolean = false
private lateinit var lengthInput: LengthInputViewController
Expand Down Expand Up @@ -57,14 +53,10 @@ class AddWidthForm : AbstractOsmQuestForm<WidthAnswer>() {

private fun takeMeasurement() {
val lengthUnit = lengthInput.unit ?: return
try {
launcher.launch(MeasureContract.Params(lengthUnit, false))
} catch (e: ActivityNotFoundException) {
context?.openUri("market://details?id=de.westnordost.streetmeasure")
}
takeMeasurement(lengthUnit, false)
}

private fun onMeasured(length: Length?) {
override fun onMeasured(length: Length) {
lengthInput.length = length
isARMeasurement = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import org.koin.dsl.module

val arModule = module {
factory { ArSupportChecker(get()) }
factory { ArQuestsDisabler(get(), get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package de.westnordost.streetcomplete.screens.measure

import de.westnordost.streetcomplete.data.quest.QuestTypeRegistry
import de.westnordost.streetcomplete.data.visiblequests.VisibleQuestTypeController

class ArQuestsDisabler(
private val questTypeRegistry: QuestTypeRegistry,
private val visibleQuestTypeController: VisibleQuestTypeController
) {
private val arQuestNames = listOf(
"AddMaxPhysicalHeight",
"AddRoadWidth",
"AddCyclewayWidth"
)

fun hideAllArQuests() {
val arQuests = arQuestNames.mapNotNull { questTypeRegistry.getByName(it) }
visibleQuestTypeController.setVisibilities(arQuests.associateWith { false })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package de.westnordost.streetcomplete.screens.measure

import android.app.ActivityManager
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import androidx.core.content.getSystemService
import de.westnordost.streetcomplete.ApplicationConstants
import de.westnordost.streetcomplete.util.ktx.isPackageInstalled

class ArSupportChecker(private val context: Context) {
operator fun invoke(): Boolean = hasArMeasureSupport(context)
Expand All @@ -18,13 +18,6 @@ private fun hasArMeasureSupport(context: Context): Boolean =
// Google Play is required to lead the user through installing the app
&& (
// app is already installed
context.packageManager.isPackageInstalled("de.westnordost.streetmeasure")
context.packageManager.isPackageInstalled(ApplicationConstants.STREETMEASURE)
// or at least google play is installed
|| context.packageManager.isPackageInstalled("com.android.vending"))

private fun PackageManager.isPackageInstalled(packageName: String): Boolean =
try {
getPackageInfo(packageName, 0) != null
} catch (e: NameNotFoundException) {
false
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract
import androidx.core.os.bundleOf
import de.westnordost.streetcomplete.ApplicationConstants.STREETMEASURE
import de.westnordost.streetcomplete.data.meta.LengthUnit
import de.westnordost.streetcomplete.osm.Length
import de.westnordost.streetcomplete.osm.LengthInFeetAndInches
Expand All @@ -19,7 +20,7 @@ class MeasureContract : ActivityResultContract<MeasureContract.Params, Length?>(
LengthUnit.METER -> "meter"
LengthUnit.FOOT_AND_INCH -> "foot_and_inch"
}
val intent = context.packageManager.getLaunchIntentForPackage("de.westnordost.streetmeasure")
val intent = context.packageManager.getLaunchIntentForPackage(STREETMEASURE)
?: throw ActivityNotFoundException()
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
val attributes = context.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.westnordost.streetcomplete.util.ktx

import android.content.pm.PackageManager

fun PackageManager.isPackageInstalled(packageName: String): Boolean =
try {
getPackageInfo(packageName, 0) != null
} catch (e: PackageManager.NameNotFoundException) {
false
}
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ Additionally, some overlays allow you to add new data at the position of a displ
&lt;p&gt;Set each the start- and endpoint while pointing the phone straight down (so that you see the white arrow from above) to completely avoid this issue for horizontal measurements.&lt;/p&gt;
&lt;p&gt;For vertical measurements, you need to instead check that the startpoint does not seem to move in relation to the ground by looking at it from different directions.&lt;/p&gt;"</string>

<string name="quest_disable_action">Disable</string>
<string name="quest_disable_title">Disable this quest type?</string>
<string name="quest_disable_message_not_installed">"StreetMeasure is not installed (yet)."</string>
<string name="quest_disable_message_not_working">"StreetMeasure didn’t return a measurement.</string>
<string name="quest_disable_message_tape_measure">You could use a tape measure instead, but that might be a little awkward, after all.</string>

<!-- Notifications -->

<string name="unread_messages_message">You have %d unread messages in your inbox</string>
Expand Down

0 comments on commit a3c0a5a

Please sign in to comment.