OneBusAway / onebusaway-ios

OneBusAway for iOS, written in Swift.
Other
94 stars 36 forks source link

Improve user feedback process, including Open311 submissions #453

Open barbeau opened 7 years ago

barbeau commented 7 years ago

We recently improved the feedback process in OBA Android to better channel feedback to different locations based on the type of feedback. HART has expressed interest in implementing something similar on iOS, so I wanted to capture some of the current Android implementation details here as a jumping off point.

Details on the OBA Android UI are here: http://www.slideshare.net/sjbarbeau/onebusaway-new-issue-reporting-flow-in-onebusaway-android

After tapping on "Send feedback" in main menu, the first time the user does this they are asked to confirm their region (to prevent against feedback going to the wrong region, and to intercept "wrong region" feedback). On Android we ask "Are you in X"? If yes proceed to feedback, if no direct to region selection setting. We save this acknowledgment and reset it if the region is changed.

After the user confirms the region at least once, when they tap on "Send feedback" the following categories are shown (see slide 2 in above presentation for screenshots):

Implementing most of the above is fairly trivial - however, the Open311 submission would require a decent amount of UI work. This is because the problem reporting UI is dynamically driven by data in the Open311 server response. In other words, an agency defines the issue category types (including whether the answer is text, multiple choice, checkbox, etc.), and this is dynamically discovered from the Open311 server REST API (a lat/long for the reporting location is sent to the Open311 server, and it responds with valid categories for the location). There are also some UI design decisions that are driven because for this - you need the user to pick a stop or location before they can choose the type of issue they want to report.

We wrote our own Open311 Java client, but I'm hoping there are existing iOS-compatible libraries (Objective C or Swift) that could be leveraged. Here's what I could find from some quick Googling (feel free to add more):

Here's a general list of OSS related to Open311:

aaronbrethorst commented 7 years ago

That open311-mobile project looks promising, but it's licensed under GPL 3, which is unfortunately incompatible with Apache 2.0: https://www.apache.org/licenses/GPL-compatibility.html

I'll go do some hunting and see what I find. Thanks for the detailed writeup!

barbeau commented 7 years ago

Yeah, GPL is one reason we built our own Apache-licensed version for Java.

sdjacobs commented 7 years ago

Unfortunately I couldn't find any Objective-C or Swift Open-311 libraries, besides this very unfinished attempt and the open311-mobile GPL project. @aaronbrethorst have you played around with Google's Java-to-objC transcoder? Maybe this could be used in combination with CUTR's open311 client. I've never used it & I can't imagine that it would work perfectly (for one thing, how would it handle the Jackson dependency?) but perhaps it would be better than writing a new library from scratch.

aaronbrethorst commented 7 years ago

@sdjacobs I'm certainly willing to take a look, but I'd be surprised if it saved us a lot of time. Most of the effort on this will be around building the UI, and the transcoder can't do that. I think what probably would be most helpful for iOS would be a document outlining how the Android interfaces with the server and how it renders its UI.

I'm going to put together a quick design doc outlining the iOS work.

barbeau commented 7 years ago

The entire OBA Android implementation for the new issue reporting flow is implemented in this package: https://github.com/OneBusAway/onebusaway-android/tree/master/onebusaway-android/src/main/java/org/onebusaway/android/report

The majority of Open311-specific UI logic is in this Fragment: https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/java/org/onebusaway/android/report/ui/Open311ProblemFragment.java

Here are a few items on Android that took us a while to figure out, but shouldn't be difficult to implement if you follow the approach we settled on:

  1. Choosing Open311 endpoint vs. legacy OBA problem reporting API - Even though we have a list of Open311 endpoints for a region (note, not just one server), there is no guarantee that the entire region is covered by those Open311 servers. So, after the user picks the location to report a problem for, we query each Open311 server for that region (right now there is only 1 in Tampa) to determine if more than one issue request type (service) is returned - for example https://seeclickfix.com/open311/v2/services.json?lat=28.0586583&long=-82.416445. If more then one service is returned we proceed down the Open311 client code path (this is what happens if you report an issue in Pinellas or Hillsborough Counties, which should be the vast majority of Tampa region service area). If 0 or 1 services are returned, or if the region doesn't have any Open311 servers listed, we assume that particular area isn't being monitored by the Open311 server, and proceed down the legacy OBA trip/stop problem reporting API code path (this is what happens if you report an issue in Puget Sound currently). Open311 spec doesn't currently cover the concept of server discovery based on geographic areas that might be covered by more than one server, so this is an agreement we came to with SeeClickFix for how this should work. It may or may not work with other Open311 providers, but we'll cross that bridge when we come to it. I'd also like to raise this with Open311 community to see if we can get this added to the spec.
  2. We have to deal with SeeClickFix accounts that are entirely focused on transit (e.g., HART in Tampa, who has their own SeeClickFix account) as well as a mix of county/city/transit issues within a SeeClickFix account (e.g., PSTA in Pinellas County, who is a user on the county account) - We assume that most OBA users will be reporting transit-related issues, and therefore we want to put the transit-related issue categories (services) at the top of the drop down list but still allow users to report problems for other "non-transit" infrastructure - for example, here's how we split it out on Android:

image

If all issue categories are transit-related, then they should fall under a single "transit" category:

image

There is a concept of a group and keywords field for Open311 services - the "right" way to do this is for the group field to be set to transit for transit issues, and all other issue group fields be set to null (or something else). We've implemented this in Android. However, SeeClickFix hasn't implemented support for assigned groups to issue categories yet, so we're stuck with hacky heuristic-based matching for the current implementation - we've implemented this as well if all group fields are null. We look at the titles of the issue categories, and if there is >= 4 categories that have "transit-related" words in them, we assume all categories are transit related. Heuristics matching code is called at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/java/org/onebusaway/android/report/ui/InfrastructureIssueActivity.java#L787, and is implemented in a utility method at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/java/org/onebusaway/android/report/ui/util/ServiceUtils.java#L30.

Heuristics keywords we're using to identify "stop" related categories are at: https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/res/values/arrays.xml#L190:

Note the space unicode characters around "bus" - \u0020bus\u0020 (otherwise this matches to "business").

EDIT Jan 2 2018 - We're now using passenger as a stop heuristic keyword too (see https://github.com/OneBusAway/onebusaway-android/issues/826).

Heuristics keywords we're using to identify "trip (i.e., arrival time)" related categories are at: https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/res/values/arrays.xml#L197:

Unit tests that make sure the heuristic-based matching works with the current HART/PSTA deployments by querying the actual SeeClickFix API there is at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java#L40.

  1. We automatically populate stop_code field in the UI - this should again be simple with use of keywords field, but SeeClickFix doesn't support it. So, more heuristics matching based on issue category name. Heuristics matching code for this is at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/java/org/onebusaway/android/report/ui/util/ServiceUtils.java#L200, and uses the keywords listed at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/res/values/arrays.xml#L202:

    • stop
    • id
    • bus
  2. We have a OBA info that "anonymous" issues are reported under - For Open311 servers we allow the user to choose to remain anonymous and not enter first name, last name, email, and phone number. However, these fields must be populated for the server to accept a report. In that case, we submit the issue under an OBA name and email. Strings we use for this anonymous submission are at https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/res/values/donottranslate.xml#L170:

    • First name - OneBusAway
    • Last name - User
    • Email - issue-report@onebusaway.org
    • Phone - empty
  3. We add metadata in bottom of issue description before issue is submitted to server - We allow the user to type in their summary of the issue, and then we append metadata to the bottom of the description so it's easier for the agency to see more info.

Here's what we append for arrival time problems:

--------------------- 
service_date=01-03-2017; 
agency_name=Hillsborough Area Regional Transit; 
gtfs_stop_id=Hillsborough Area Regional Transit_1688; 
stop_name=30th St @ Annie St; 
route_id=Hillsborough Area Regional Transit_18; 
route_display_name=18; 
trip_id=Hillsborough Area Regional Transit_235407; 
trip_headsign=South to UATC/Downtown/MTC; 
predicted=true; 
vehicle_id=Hillsborough Area Regional Transit_1020; 
vehicle_location=28.080591201782227 -82.43084716796875; 
schedule_deviation=8.000 min late; 
stop_arrival_time=05:16 PM; 
stop_departure_time=05:16 PM;

Here's what we append for stop problem reports (basically, anything that's not an "arrival time" report):

--------------------- 
gtfs_stop_id=Hillsborough Area Regional Transit_7582; 
stop_name=56th St @ Mission Hills Av;

Please keep the exact same field names - we'd like this to be machine-readable so we can do bulk analysis of data

You can see example issues that have been submitted via OBA Android by looking any any recent issue in Hillsborough County: https://seeclickfix.com/hillsborough-county-fl

...as well as any issue in Pinellas County that has been assigned to "PSTA", such as: http://seeclickfix.com/issues/3131124-psta-bus-stops

That's what I can think of off the top of my head. Let me know if you have any questions when you start digging in, and I'll post again if I think of anything else.

barbeau commented 7 years ago

One edit for 3) above - we autopopulate the stop_code (not stop_id) in the UI based on the stop the user tapped on. stop_id is in the metadata that gets tacked onto the bottom of the report, but stop_code is the user-facing "Stop ID" that gets autopopulated in the UI. This is especially important for PSTA, as their stop_ids and stop_codes are different. For HART and many other agencies, stop_id and stop_code are the same.

aaronbrethorst commented 7 years ago

Current thoughts:

Users can reach the new Open311 UI options by opening a stop, which is where they are used to reporting problems with their stops and vehicles today already. They can also access the full "Send Feedback" experience from the Info tab which will display a modal view controller with four options, as seen in the accompanying screenshots.

If the current region has an Open311 server defined, use the new Open311 client library; otherwise use the existing "Report a Problem" UI.

Report a stop problem

From the Stop view controller:

A modal is presented. This page goes out to the server and hits the "Discover Services" endpoint, retrieving a list of available services, and populates a table based on the list.

From the Info tab:

The user's entry point is through a single item on the Info tab entitled "Send Feedback". When the user taps Send Feedback, they will see the UI modeled in the mockup below:

1 report a problem

Unlike Android, a piece of static text at the bottom of the view will tell them what region they have selected and provide them with a button to change their region if need be. The Update Region button will open the region picker UI.

Contact customer feedback

A table of all agencies in the current region with tappable options for sending email and making phone calls, modeled after Android.

Report a Stop Problem

A map with stops is displayed. The user selects a stop (or another point as they see fit). A new page is pushed onto the stack. This page goes out to the server and hits the "Discover Services" endpoint, retrieving a list of available services, and populates a table based on the list.

The table in both examples includes options like:

This table's contents are grouped into two sections (Transit and Other) based upon the same heuristics that Android uses.

2 report a stop problem

Selecting one of these options pushes a new page onto the stack. This new page contains a dynamically constructed form representing the selected service. For instance, for "Wifi on bus isn't working", the following form elements are dynamically created from the service data:

Static Text: "Hillsborough Area Regional Transit (HART) monitors SeeClickFix from 8am to 5pm on regular business days for non-emergency conditions. Please call 911 for emergencies." Number entry: "What is the 4- digit bus number? (This can be found above the interior windshield.)"

Forms that include "Stop ID" will have that field automatically populated by the stop ID that was selected from the map, if a stop was selected.

Plus, a series of standard fields that are included with every form:

3 benches

Report an arrival time problem

  1. Load the entire service list as with "Report a problem with this stop"
  2. Select the appropriate service—thereby bypassing the service selection screen—based on Sean's comments here: https://github.com/OneBusAway/onebusaway-iphone/issues/923#issuecomment-270437702
  3. Load a list of recent arrivals and departures and populate the current page with that list
  4. Allow the user to select one of those recent arrivals and departures
  5. Populate the remainder of the table as with "Report a problem with this stop"

Send App Feedback

Displays the email feedback UI.

Tasks

aaronbrethorst commented 6 years ago

Updated version of the above task breakdown: https://docs.google.com/document/d/13hZwNKAWit0Uouv1_5qF1RPsfAs2tXi6K5bMH4e7bD4/edit?usp=sharing