Skip to content

Commit

Permalink
Fix #875 - Implement user opt-in travel behavior data collection (#988)
Browse files Browse the repository at this point in the history
This commit implements an opt-in user-travel-behavior tracking feature to OBA. With this PR, after the user agrees to participate the application will collect the users' travel behaviors and push the results to a Firebase Firestore.

Once the user saves his/her email address, OBA starts collecting the following data:

* activity transitions
* arrivals and departures
* trip plans
* device information

See #988 (comment) for screenshots of UI and data.
  • Loading branch information
cagryInside authored and barbeau committed Jul 9, 2019
1 parent 6e17a7e commit 11e81df
Show file tree
Hide file tree
Showing 51 changed files with 3,274 additions and 136 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.0'
classpath 'com.google.gms:google-services:4.1.0'
classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31'
classpath 'com.google.gms:google-services:4.2.0'
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
#

android.enableJetifier=true
android.useAndroidX=true
android.useAndroidX=true
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Jan 25 09:21:55 EST 2019
#Fri Jun 21 16:46:28 PDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
15 changes: 14 additions & 1 deletion onebusaway-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ android {
dexOptions {
preDexLibraries true
}
compileSdkVersion 28
compileSdkVersion 29
buildToolsVersion '28.0.3'

defaultConfig {
Expand Down Expand Up @@ -124,6 +124,8 @@ android {
buildConfigField "String", "FIXED_REGION_PAYMENT_ANDROID_APP_ID", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_TITLE", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_BODY", "null"
buildConfigField "boolean", "FIXED_REGION_TRAVEL_BEHAVIOR_DATA_COLLECTION", "false"
buildConfigField "boolean", "FIXED_REGION_ENROLL_PARTICIPANTS_IN_STUDY", "false"
}

/**
Expand Down Expand Up @@ -168,6 +170,8 @@ android {
buildConfigField "String", "FIXED_REGION_PAYMENT_ANDROID_APP_ID", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_TITLE", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_BODY", "null"
buildConfigField "boolean", "FIXED_REGION_TRAVEL_BEHAVIOR_DATA_COLLECTION", "false"
buildConfigField "boolean", "FIXED_REGION_ENROLL_PARTICIPANTS_IN_STUDY", "false"
}

agencyY {
Expand Down Expand Up @@ -208,6 +212,8 @@ android {
buildConfigField "String", "FIXED_REGION_PAYMENT_ANDROID_APP_ID", "\"co.bytemark.hart\""
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_TITLE", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_BODY", "null"
buildConfigField "boolean", "FIXED_REGION_TRAVEL_BEHAVIOR_DATA_COLLECTION", "false"
buildConfigField "boolean", "FIXED_REGION_ENROLL_PARTICIPANTS_IN_STUDY", "false"
}
yrt {
// "YRT - York Region Transit - Canada" rebranding - https://play.google.com/store/apps/details?id=can.yrt.onebusaway
Expand Down Expand Up @@ -246,6 +252,8 @@ android {
buildConfigField "String", "FIXED_REGION_PAYMENT_ANDROID_APP_ID", "\"co.bytemark.york\""
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_TITLE", "null"
buildConfigField "String", "FIXED_REGION_PAYMENT_WARNING_BODY", "null"
buildConfigField "boolean", "FIXED_REGION_TRAVEL_BEHAVIOR_DATA_COLLECTION", "false"
buildConfigField "boolean", "FIXED_REGION_ENROLL_PARTICIPANTS_IN_STUDY", "false"
}
/**
* Add more rebranding flavors here...
Expand Down Expand Up @@ -411,6 +419,7 @@ dependencies {
implementation 'android.arch.lifecycle:common-java8:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
implementation 'commons-io:commons-io:2.4'
implementation 'org.apache.commons:commons-lang3:3.0'
// Open311 client library
implementation 'edu.usf.cutr:open311client:1.0.10'
// JSON data binding for OBA REST API responses
Expand Down Expand Up @@ -441,6 +450,10 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.1.0'
// WorkManager (Java only)
implementation 'androidx.work:work-runtime:2.0.0'
implementation "androidx.concurrent:concurrent-futures:1.0.0-beta01"
implementation "androidx.concurrent:concurrent-listenablefuture:1.0.0-beta01"
implementation "androidx.concurrent:concurrent-listenablefuture-callback:1.0.0-beta01"

}

apply plugin:'com.google.gms.google-services'
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
Expand Down Expand Up @@ -82,6 +83,7 @@
import org.onebusaway.android.map.bike.BikeshareMapController;
import org.onebusaway.android.map.googlemapsv2.bike.BikeStationOverlay;
import org.onebusaway.android.region.ObaRegionsTask;
import org.onebusaway.android.ui.HomeActivity;
import org.onebusaway.android.ui.LayersSpeedDialAdapter;
import org.onebusaway.android.util.LocationHelper;
import org.onebusaway.android.util.LocationUtils;
Expand Down Expand Up @@ -422,8 +424,13 @@ public void onRequestPermissionsResult(
} else {
mUserDeniedPermission = true;
}
} else if (HomeActivity.BATTERY_OPTIMIZATIONS_PERMISSION_REQUEST == requestCode) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
UIUtils.openBatteryIgnoreIntent(getActivity());
}
}
if (mOnLocationPermissionResultListener != null) {

if (requestCode == LOCATION_PERMISSION_REQUEST && mOnLocationPermissionResultListener != null) {
mOnLocationPermissionResultListener.onLocationPermissionResult(result);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ public static ObaRegion getRegionWithPathNoSeparator(Context context) {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -131,7 +133,9 @@ public static ObaRegion getRegionNoSeparator(Context context) {
false,
null,
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -169,7 +173,9 @@ public static ObaRegion getRegionWithPort(Context context) {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -207,7 +213,9 @@ public static ObaRegion getRegionNoScheme(Context context) {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -245,7 +253,9 @@ public static ObaRegion getRegionWithHttps() {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -283,7 +293,9 @@ public static ObaRegion getRegionWithHttpsAndPort() {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -319,7 +331,9 @@ public static ObaRegion getRegionWithoutObaApis(Context context) {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}

/**
Expand Down Expand Up @@ -355,6 +369,8 @@ public static ObaRegion getInactiveRegion(Context context) {
false,
"co.bytemark.hart",
null,
null);
null,
false,
false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
Expand Down Expand Up @@ -71,6 +72,7 @@
import org.onebusaway.android.map.bike.BikeshareMapController;
import org.onebusaway.android.map.googlemapsv2.bike.BikeStationOverlay;
import org.onebusaway.android.region.ObaRegionsTask;
import org.onebusaway.android.ui.HomeActivity;
import org.onebusaway.android.ui.LayersSpeedDialAdapter;
import org.onebusaway.android.util.LocationHelper;
import org.onebusaway.android.util.LocationUtils;
Expand Down Expand Up @@ -411,8 +413,13 @@ public void onRequestPermissionsResult(
} else {
mUserDeniedPermission = true;
}
} else if (HomeActivity.BATTERY_OPTIMIZATIONS_PERMISSION_REQUEST == requestCode) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
UIUtils.openBatteryIgnoreIntent(getActivity());
}
}
if (mOnLocationPermissionResultListener != null) {

if (requestCode == LOCATION_PERMISSION_REQUEST && mOnLocationPermissionResultListener != null) {
mOnLocationPermissionResultListener.onLocationPermissionResult(result);
}
}
Expand Down
15 changes: 15 additions & 0 deletions onebusaway-android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
Expand All @@ -37,6 +38,10 @@
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="${applicationId}.permission.TRIP_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<!--To enable checkBatteryOptimizations feature, also uncomment checkBatteryOptimizations() in
the HomeActivity's onCreate() method-->
<!--<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>-->

<uses-sdk tools:overrideLibrary="net.openid.appauth,
android.support.customtabs,
Expand Down Expand Up @@ -296,6 +301,16 @@
</intent-filter>
</receiver>

<receiver
android:enabled="true" android:name=".travelbehavior.receiver.TransitionBroadcastReceiver">
</receiver>
<receiver
android:enabled="true" android:name=".travelbehavior.receiver.RecognitionBroadcastReceiver">
</receiver>
<receiver
android:enabled="true" android:name=".travelbehavior.receiver.LocationBroadcastReceiver">
</receiver>

<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
Expand All @@ -46,6 +47,7 @@
import org.onebusaway.android.io.elements.ObaRegion;
import org.onebusaway.android.provider.ObaContract;
import org.onebusaway.android.report.ui.util.SocialReportHandler;
import org.onebusaway.android.travelbehavior.TravelBehaviorManager;
import org.onebusaway.android.ui.social.SocialAppProfile;
import org.onebusaway.android.ui.social.SocialNavigationDrawerHandler;
import org.onebusaway.android.util.BuildFlavorUtils;
Expand Down Expand Up @@ -125,6 +127,8 @@ public void onStart(@NonNull LifecycleOwner owner) {
reportAnalytics();

createNotificationChannels();

TravelBehaviorManager.startCollectingData(getApplicationContext());
}

/**
Expand Down Expand Up @@ -623,4 +627,17 @@ private void createNotificationChannels() {
}
}

public static Boolean isIgnoringBatteryOptimizations(Context applicationContext) {
PowerManager pm = (PowerManager) applicationContext.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
pm.isIgnoringBatteryOptimizations(applicationContext.getPackageName())) {
return true;
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return null;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.onebusaway.android.directions.util.TripRequestBuilder;
import org.opentripplanner.api.model.Itinerary;
import org.opentripplanner.api.model.Leg;
import org.opentripplanner.api.model.TripPlan;

import android.app.Activity;
import android.app.AlarmManager;
Expand Down Expand Up @@ -165,16 +166,16 @@ private void checkForItineraryChange(final Class<? extends Activity> source, fin

TripRequest.Callback callback = new TripRequest.Callback() {
@Override
public void onTripRequestComplete(List<Itinerary> itineraries, String url) {
if (itineraries == null || itineraries.isEmpty()) {
public void onTripRequestComplete(TripPlan tripPlan, String url) {
if (tripPlan == null || tripPlan.itineraries == null || tripPlan.itineraries.isEmpty()) {
onTripRequestFailure(-1, null);
return;
}

// Check each itinerary. Notify user if our *current* itinerary doesn't exist
// or has a lower rank.
for (int i = 0; i < itineraries.size(); i++) {
ItineraryDescription other = new ItineraryDescription(itineraries.get(i));
for (int i = 0; i < tripPlan.itineraries.size(); i++) {
ItineraryDescription other = new ItineraryDescription(tripPlan.itineraries.get(i));

if (itineraryDescription.itineraryMatches(other)) {

Expand All @@ -187,7 +188,7 @@ public void onTripRequestComplete(List<Itinerary> itineraries, String url) {
(delay > 0) ? R.string.trip_plan_delay
: R.string.trip_plan_early,
R.string.trip_plan_notification_new_plan_text,
source, builder.getBundle(), itineraries);
source, builder.getBundle(), tripPlan.itineraries);
disableListenForTripUpdates();
return;
}
Expand All @@ -203,7 +204,7 @@ public void onTripRequestComplete(List<Itinerary> itineraries, String url) {
showNotification(itineraryDescription,
R.string.trip_plan_notification_new_plan_title,
R.string.trip_plan_notification_new_plan_text, source,
builder.getBundle(), itineraries);
builder.getBundle(), tripPlan.itineraries);
disableListenForTripUpdates();
}

Expand Down
Loading

0 comments on commit 11e81df

Please sign in to comment.