/* * Copyright (C) 2016 University of South Florida (sjbarbeau@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onebusaway.android.report.ui.util; import org.onebusaway.android.R; import org.onebusaway.android.app.Application; import org.onebusaway.android.report.constants.ReportConstants; import android.content.Context; import java.util.List; import edu.usf.cutr.open311client.models.Service; public class ServiceUtils { /** * Given a list of Open311 services (request types), mark which ones are transit-related in * place based on group, keyword, or text heuristic matching * * @param context * @param serviceList the list of Open311 services to potentially be marked as transit-related * @return true if the services were determined to be via all transit-related via heuristics, * false if heuristics matching wasn't used */ public static boolean markTransitServices(Context context, List<Service> serviceList) { boolean stopProblemFound = false; boolean tripProblemFound = false; // Search transit services by groups (this is the "right" way to group transit services) for (Service s : serviceList) { if (ServiceUtils.isTransitStopServiceByText(s.getGroup()) && !stopProblemFound) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP); stopProblemFound = true; } else if (ServiceUtils.isTransitTripServiceByText(s.getGroup()) && !tripProblemFound) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP); tripProblemFound = true; } } // Search transit services by keywords if (!stopProblemFound || !tripProblemFound) { for (Service s : serviceList) { if (ServiceUtils.isTransitStopServiceByText(s.getKeywords()) && !stopProblemFound) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP); stopProblemFound = true; } else if (ServiceUtils.isTransitTripServiceByText(s.getKeywords()) && !tripProblemFound) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP); tripProblemFound = true; } } } if (stopProblemFound && tripProblemFound) { // Yay! We had explicit matching via groups or keywords and didn't need to use heuristics return false; } // Search transit services by name and text matching heuristics - count matches int transitServiceCounter = 0; for (Service s : serviceList) { if (ServiceUtils.isTransitStopServiceByText(s.getService_name())) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP); stopProblemFound = true; transitServiceCounter++; } else if (ServiceUtils.isTransitTripServiceByText(s.getService_name())) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP); tripProblemFound = true; transitServiceCounter++; } } /** * If we've found a large number of potential transit services via heuristics search, assume all * services are transit related, and those without a group are stop-related */ if (transitServiceCounter >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD) { for (Service s : serviceList) { if (s.getGroup() == null) { s.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); s.setType(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP); } } return true; } // Add our own transit services if none have been found if (!stopProblemFound) { Service s1 = new Service(context.getString(R.string.ri_service_stop), ReportConstants.STATIC_TRANSIT_SERVICE_STOP); s1.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); serviceList.add(s1); } if (!tripProblemFound) { Service s2 = new Service(context.getString(R.string.ri_service_trip), ReportConstants.STATIC_TRANSIT_SERVICE_TRIP); s2.setGroup(ReportConstants.ISSUE_GROUP_TRANSIT); serviceList.add(s2); } return false; } /** * This method looks at the given text and predefined transit keywords (e.g., groups, keywords, * and service name), and tries to determine if the this is a transit stop service (i.e., stop * problem) * * @param text text to search for transit stop service match * @return true if the text is "transit stop-related" */ public static boolean isTransitStopServiceByText(String text) { String[] transitKeywords = Application.get().getResources(). getStringArray(R.array.report_stop_transit_category_keywords); for (String keyword : transitKeywords) { if (text != null && text.toLowerCase().contains(keyword)) { return true; } } return false; } /** * This method looks at the given text and predefined transit keywords (e.g., groups, keywords, * and service name), and tries to determine if the this is a transit trip service (i.e., trip * problem) * * @param text text to search for transit trip service match * @return true if the text is "transit trip-related" */ public static boolean isTransitTripServiceByText(String text) { String[] transitKeywords = Application.get().getResources(). getStringArray(R.array.report_trip_transit_category_keywords); for (String keyword : transitKeywords) { if (text != null && text.toLowerCase().contains(keyword)) { return true; } } return false; } /** * @param type Service type * @return true if it is a transit stop service */ public static boolean isTransitStopServiceByType(String type) { return ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP.equals(type) || ReportConstants.STATIC_TRANSIT_SERVICE_STOP.equals(type); } /** * @param type Service type * @return true if it is a transit trip service */ public static boolean isTransitTripServiceByType(String type) { return ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP.equals(type) || ReportConstants.STATIC_TRANSIT_SERVICE_TRIP.equals(type); } /** * @param type Service type * @return true if it is a transit service */ public static boolean isTransitServiceByType(String type) { return isTransitStopServiceByType(type) || isTransitTripServiceByType(type); } /** * @param type Service type * @return true if it is a transit service and it is coming from open311 endpoint */ public static boolean isTransitOpen311ServiceByType(String type) { return ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP.equals(type) || ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP.equals(type); } /** * This method determines if the given dynamic open311 field is for stop id. * * @param desc field description * @return true if the field description matches at least two keywords */ public static boolean isStopIdField(String desc) { String[] stopIdKeywords = Application.get().getResources(). getStringArray(R.array.report_stop_id_field_keywords); boolean didMatch = false; for (String keyword : stopIdKeywords) { if (desc != null && desc.toLowerCase().contains(keyword)) { if (didMatch) { // if this is the second matched keyword then return true return true; } else { didMatch = true; } } } return false; } }