Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/ios-upgrade-from-legacy.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
title: Upgrading from the legacy iOS app
layout: page
parent: "Using Soundscape"
has_toc: false
---

# Upgrading from the legacy Soundscape iOS app

This page is for users of the legacy Microsoft Soundscape iOS app who are
Expand Down
46 changes: 32 additions & 14 deletions docs/testing/test-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@ has_toc: false
---

# Testing the Soundscape app
The app is a port of the Soundscape iOS app and the UI is designed to be pretty much the same.
Whilst we're interested in improving the UI in the long term, matching the iOS behaviour is the
most important goal for this initial release.
The Android and iOS apps are now built from a single shared codebase, so the UI and behaviour
described in this document apply to both unless a section specifically calls out a difference
between the two platforms.

Unless you are an STA member and can ping us on Slack, all feedback should go via the Help Desk by emailing <soundscapeAndroid@scottishtecharmy.support>.

## Requirements
The app currently requires Android 11 (API 30 - see <https://apilevels.com/>). We are hoping to drop this to Android 9 with some more work, but for now we only support Android 11 and later.
We don't know of any other requirements, but that's one of the thing this testing should help us understand.
* Android: Android 11 (API 30 - see <https://apilevels.com/>) or later.
* iOS: iOS 16 or later.

We don't know of any other requirements, but that's one of the things this testing should help us understand.

## Installing the app
The app is freely available on the Play Store [here](https://play.google.com/store/apps/details?id=org.scottishtecharmy.soundscape).
* Android: the app is freely available on the Play Store [here](https://play.google.com/store/apps/details?id=org.scottishtecharmy.soundscape).
* iOS: the rewritten app is currently only available via TestFlight, by invitation. If you're an STA member, ask on Slack for an invite; otherwise request one via the Help Desk by emailing <soundscapeAndroid@scottishtecharmy.support>. Once you have an invitation, install TestFlight from the App Store first and then follow the invitation link to install the beta build.

If you're updating from the older, Microsoft-authored iOS app rather than installing fresh, see [Upgrading from the legacy Soundscape iOS app]({{ "/ios-upgrade-from-legacy.html" | relative_url }}) for what's carried over automatically and what has changed.

## Running the app the first time
The first time you run the Soundscape app you will see a series of onboarding screens which let
Expand All @@ -39,7 +44,8 @@ the main screen:
<img src="{{ "/documentationScreens/homeScreen.png" | relative_url }}" width="200" alt="Screenshot of the Soundscape home screen">

Soundscape will now continue to run in the background. To exit it, click on the top right corner
to put the app to sleep, and then close the app (swipe up etc.).
to put the app to sleep, and then close the app (swipe up from the app switcher, or the
equivalent gesture on your device).

Soundscape is designed to be used with headphones.

Expand All @@ -52,7 +58,7 @@ Things that should happen on the Home screen and we're interested if they do not
If you've got to this point and it all seems to be working, then you can move on to more detailed testing.

### Test 1 - Go for a walk
As you move around, Soundscape should periodically describe your location and call out any points of interest that you pass e.g. Shops, Bus Stops etc. We're interested if there's anything that doesn't sound right. The app will consume a little bit of data as it downloads maps as you move around, but in general those are fairly small (< 50kb for a 600m square bit of map). The map tiles are cached so they will generally only be downloaded once.
As you move around, Soundscape should periodically describe your location and call out any points of interest that you pass e.g. Shops, Bus Stops etc. We're interested if there's anything that doesn't sound right. The app will consume a little bit of data as it downloads maps as you move around, but in general those are fairly small (< 50kb for a 600m square bit of map). The map tiles are cached so they will generally only be downloaded once. If you'd rather not use any mobile data at all, or want to test the app with no network connection, see Test 3 below on offline maps.

### Test 2 - Create a route and play it back
This uses a bit more of the UI, but once set up it should be fairly straightforward.
Expand All @@ -77,20 +83,32 @@ There should now be a route listed. Click on that and you can check that it's wh
#### Play the route
Click _Start Route_ on the _Route Details_ screen to start an audio beacon playing at the first waypoint of the route. The audio beacon will sound from the direction of the waypoint from where you are. When you're using the Soundscape app and your phone is unlocked, the direction used is the direction that the phone is pointing in. You can lock your phone and put it in your bag and then it will start using the direction in which your walking. The sound of the beacon will be different if you are walking towards it or away from it. If you stop moving and your phone is locked then any beacon will go quieter to indicate that there's no available direction data.

### Test 3 - Offline maps
Soundscape can download map data for a region so that it keeps working - map, callouts and Places Nearby included - with no Internet connection at all. See [Offline map extracts]({{ "/users/help-offline-map-extracts.html" | relative_url }}) for the kinds of extracts available (country, region and city).

1. Open the Menu hamburger in the top left and tap _Offline maps_.
1. You should see any extracts that cover your current location listed. Pick one and tap _Download offline map_. The first time anyone downloads a particular extract there can be a short delay while the server prepares it - after that it should start straight away. Larger extracts (e.g. a whole country) will take longer and use more storage than a city extract, so pick whichever is convenient for testing.
1. You can also find nearby extracts from any Location Details screen - look for a _Nearby offline maps_ button.
1. Once a download completes, turn on Airplane Mode (or otherwise disable WiFi and mobile data) and repeat Test 1 and Test 2 above. The map should still draw, and callouts and Places Nearby should still work using the downloaded data.
1. In Settings there's a _Search mode_ option (Auto/Online/Offline). With no network, Search should automatically fall back to offline data (Auto); you can also force this by setting it to _Offline_ so you can test that path even when you do have a network connection.
1. Downloaded maps can be removed again from the _Offline maps_ screen - tap on a downloaded map and choose _Delete offline map_ - which is worth checking too if you're short on storage.

We're interested in anything that doesn't work the same offline as it does online, how long downloads take, and whether the list of available extracts makes sense for your area.

## Providing debug location trace
The app can store up to an hour buffer of the user location recorded whilst the app is running. This feature is disabled by default, and even when enabled the data stays on the phone unless the user chooses to share it via interaction with the app. To use the feature:
1. Tap on the Menu hamburger in the top left, and then tap on "Settings" scroll to the bottom and you'll see the "Enable recording of travel" option. Click to enable/disable.
2. With the setting enabled, a new option appears in the Menu drawer below "About Soundscape" which is "Share recording of travel". If you want to share a GPX track you can click on that and you can then choose whether to use email/slack etc. to send the file to us to debug.
The file contains the data from the Android location services for up to the last hour that the app has been running. Don't share it with us if you don't want us to know where you've been. There's no identifying data in it, though obviously we'll know who sent it.
2. With the setting enabled, a new option appears in the Menu drawer below "About Soundscape" which is "Share recording of travel". If you want to share a GPX track you can click on that and you can then choose to send the file to us via email etc. using the standard Android share menu or iOS share sheet.
The file contains the location data recorded by the device's location services for up to the last hour that the app has been running. Don't share it with us if you don't want us to know where you've been. There's no identifying data in it, though obviously we'll know who sent it.

We can load the GPX file into our test code and it will generate the callouts that the user will have heard and we can see which road/path the app thought it was following, and figure out why callouts were generated incorrectly or not generated at all.
Enabling the setting is absolutely optional, but it is useful to us for debugging.


## Final notes
There are other features in the app, but for this first phase of testing the focus is those
above. If there's anything unclear in these instructions let us know. Once we have some feedback,
there'll be some bugs to fix, and then we'll do incremental releases. If you are interested in helping out
further on the project, take a look at the STA volunteer app for some available roles.
There are other features in the app, but the focus for this testing is those above. If there's
anything unclear in these instructions let us know. Once we have some feedback, there'll be some
bugs to fix, and then we'll do incremental releases. If you are interested in helping out further
on the project, take a look at the STA volunteer app for some available roles.

Thanks for reading!
10 changes: 9 additions & 1 deletion iosApp/iosApp/SplashView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,15 @@ final class SplashCoordinator: ObservableObject {
}

private func currentMinorVersion() -> String {
let raw = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "0.0.0"
// Must mirror PlatformInfo.appVersionName()/appVersionMinorTrimmed() exactly:
// CI pre-trims MARKETING_VERSION (CFBundleShortVersionString) to major.minor for
// TestFlight grouping, while AppVersionName keeps the full major.minor.patch. Reading
// CFBundleShortVersionString here would trim an already-trimmed value on those builds,
// producing a different string than the Kotlin side writes to the same "LastNewRelease"
// key and causing this splash and the release-notes dialog to fight over it forever.
let raw = (Bundle.main.infoDictionary?["AppVersionName"] as? String)
?? (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String)
?? "0.0.0"
if let lastDot = raw.range(of: ".", options: .backwards) {
return String(raw[..<lastDot.lowerBound])
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ fun SharedNewReleaseDialog(
dismissButton = {
TextButton(
modifier = Modifier.testTag("newReleaseDialogDismiss"),
onClick = { newReleaseDialog.value = false },
onClick = {
preferencesProvider?.putString(
PreferenceKeys.LAST_NEW_RELEASE,
appVersionMinorTrimmed(),
)
newReleaseDialog.value = false
},
) {
preferencesProvider?.putString(
PreferenceKeys.LAST_NEW_RELEASE,
appVersionMinorTrimmed(),
)
Text(text = stringResource(Res.string.new_version_info_completed))
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -24,7 +23,7 @@ import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign
import me.zhanghai.compose.preference.ProvidePreferenceLocals
import me.zhanghai.compose.preference.switchPreference
import me.zhanghai.compose.preference.SwitchPreference
import org.jetbrains.compose.resources.stringResource
import org.scottishtecharmy.soundscape.components.OnboardButton
import org.scottishtecharmy.soundscape.preferences.PreferenceDefaults
Expand Down Expand Up @@ -105,35 +104,31 @@ fun AccessibilityOnboardingScreen(
Spacer(modifier = Modifier.height(spacing.large))

ProvidePreferenceLocals {
LazyColumn(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
switchPreference(
key = PreferenceKeys.SHOW_MAP,
defaultValue = PreferenceDefaults.SHOW_MAP,
rememberState = { showMap },
modifier = Modifier.testTag("accessibilityOnboardingScreenShowMapToggle"),
title = {
Text(
text = stringResource(Res.string.settings_show_map),
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.focusable()
)
},
)

item {
OnboardButton(
text = stringResource(Res.string.ui_continue),
onClick = { onNavigate() },
SwitchPreference(
state = showMap,
title = {
Text(
text = stringResource(Res.string.settings_show_map),
color = MaterialTheme.colorScheme.onBackground,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.focusable()
.testTag("accessibilityOnboardingScreenContinueButton"),
)
}
}
},
modifier = Modifier
.fillMaxWidth()
.testTag("accessibilityOnboardingScreenShowMapToggle"),
)

OnboardButton(
text = stringResource(Res.string.ui_continue),
onClick = { onNavigate() },
modifier = Modifier
.fillMaxWidth()
.focusable()
.testTag("accessibilityOnboardingScreenContinueButton"),
)
}
}
}
Expand Down