package com.sunlightlabs.android.congress.utils;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.sunlightlabs.android.congress.CongressApp;
import com.sunlightlabs.android.congress.NotificationSettings;
import com.sunlightlabs.android.congress.R;
import com.sunlightlabs.android.congress.Settings;
import java.util.Map;
/**
* Helper class to manage Google Analytics tracking.
* All calls to log an activity visit or event should go through this class,
* as it centralizes the check on whether the user has opted out of tracking altogether.
*/
public class Analytics {
// in onCreate(), ensure trackers are created and configured for that activity
public static void init(Activity activity) {
if (analyticsEnabled(activity))
((CongressApp) activity.getApplication()).appTracker();
}
// in onStart(), start auto-tracking with any previously initialized trackers
public static void start(Activity activity) {
if (analyticsEnabled(activity)) {
// play nice with OkHttp
HttpManager.init();
Log.i(Utils.TAG, "[Analytics] Tracker starting for " + activity.getLocalClassName());
GoogleAnalytics.getInstance(activity).reportActivityStart(activity);
// send an event to insist that custom dimensions get associated with other activity.
// wasteful, but this is done because there is no longer a way to set custom dimensions
// at a tracker level, while using auto-tracking for activities.
ping(activity);
}
}
// in onStop(), stop auto-tracking with any previously initialized trackers
public static void stop(Activity activity) {
// play nice with OkHttp
HttpManager.init();
Log.i(Utils.TAG, "[Analytics] Tracker stopping for " + activity.getLocalClassName());
GoogleAnalytics.getInstance(activity).reportActivityStop(activity);
}
// set the Google opt-out mid-stream
public static void optout(Activity activity, boolean value) {
Log.i(Utils.TAG, "[Analytics] Setting app-wide GA opt-out to: " + value);
GoogleAnalytics.getInstance(activity).setAppOptOut(value);
}
public static void event(Activity activity, String category, String action, String label) {
if (analyticsEnabled(activity)) {
// play nice with OkHttp
HttpManager.init();
if (label == null) label = "";
Log.i(Utils.TAG, "[Analytics] Tracking event - category: " + category + ", action: " + action + ", label: " + label);
Map<String,String> event = attachCustomDimensions(activity, new HitBuilders.EventBuilder()
.setCategory(category)
.setAction(action)
.setLabel(label)
).build();
((CongressApp) activity.getApplication()).appTracker().send(event);
}
}
public static boolean analyticsEnabled(Activity activity) {
boolean debugDisabled = activity.getResources().getString(R.string.debug_disable_analytics).equals("true");
// these should be in sync, but in case they get out of sync, err towards turning off analytics
boolean googleOptout = GoogleAnalytics.getInstance(activity).getAppOptOut();
boolean userEnabled = Utils.getBooleanPreference(activity, Settings.ANALYTICS_ENABLED_KEY, Settings.ANALYTICS_ENABLED_DEFAULT);
return (!debugDisabled && !googleOptout && userEnabled);
}
/*
* Custom dimensions and metrics.
*/
public static final int DIMENSION_MARKET_CHANNEL = 1; // market channel (user)
public static final int DIMENSION_ORIGINAL_CHANNEL = 2; // original distribution channel (user)
public static final String DIMENSION_ORIGINAL_CHANNEL_PREFERENCE = "original_distribution_channel";
public static final int DIMENSION_NOTIFICATIONS_ON = 3; // whether notifications are enabled (session)
public static final int DIMENSION_ENTRY = 4; // how the user entered the app (hit)
public static HitBuilders.EventBuilder attachCustomDimensions(Activity activity, HitBuilders.EventBuilder event) {
Resources res = activity.getResources();
String marketChannel = res.getString(R.string.market_channel);
event = event.setCustomDimension(DIMENSION_MARKET_CHANNEL, marketChannel);
String originalChannel = Utils.getStringPreference(activity, DIMENSION_ORIGINAL_CHANNEL_PREFERENCE);
event = event.setCustomDimension(DIMENSION_ORIGINAL_CHANNEL, originalChannel);
boolean notificationsOn = Utils.getBooleanPreference(activity, NotificationSettings.KEY_NOTIFY_ENABLED, false);
event = event.setCustomDimension(DIMENSION_NOTIFICATIONS_ON, notificationsOn ? "on" : "off");
String entrySource = entrySource(activity);
if (entrySource != null)
event = event.setCustomDimension(DIMENSION_ENTRY, entrySource);
// debug: output custom dimensions
// String msg = "[" + marketChannel + "][" + originalChannel + "][" + (notificationsOn ? "on" : "off") + "][" + (entrySource != null ? entrySource : "nothing") + "]";
// Log.i(Utils.TAG, msg);
return event;
}
/*
* Utility function for discerning an entry source from an activity's Intent.
*/
public static final String EXTRA_ENTRY_FROM = "com.sunlightlabs.android.congress.utils.ENTRY_FROM";
public static String entrySource(Activity activity) {
Intent intent = activity.getIntent();
String action = intent.getAction();
boolean main = action != null && action.equals(Intent.ACTION_MAIN);
if (main) {
String source = ENTRY_MAIN;
Bundle extras = intent.getExtras();
if (extras != null) {
String extra = extras.getString(EXTRA_ENTRY_FROM);
if (extra != null)
source = extra;
}
return source;
} else
return null;
}
public static Intent passEntry(Activity activity, Intent intent) {
String action = activity.getIntent().getAction();
if (action != null && action.equals(Intent.ACTION_MAIN)) {
intent.setAction(Intent.ACTION_MAIN);
intent.putExtra(Analytics.EXTRA_ENTRY_FROM, activity.getIntent().getStringExtra(Analytics.EXTRA_ENTRY_FROM));
}
return intent;
}
/*
* Event definitions
*/
// types of entry into the application
public static final String ENTRY_MAIN = "main";
public static final String ENTRY_SHORTCUT = "shortcut";
public static final String ENTRY_NOTIFICATION = "notification";
// categories of events
public static final String EVENT_FAVORITE = "favorites";
public static final String EVENT_NOTIFICATION = "notifications";
public static final String EVENT_LEGISLATOR = "legislator";
public static final String EVENT_BILL = "bill";
public static final String EVENT_ANALYTICS = "analytics";
public static final String EVENT_ENTRY = "entry";
public static final String EVENT_ABOUT = "about";
public static final String EVENT_CHANGELOG = "changelog";
public static final String EVENT_REVIEW = "review"; // values will be "google" or "amazon"
public static final String EVENT_PING = "ping";
// event values
public static final String FAVORITE_ADD_LEGISLATOR = "add_legislator";
public static final String FAVORITE_REMOVE_LEGISLATOR = "remove_legislator";
public static final String FAVORITE_ADD_BILL = "add_bill";
public static final String FAVORITE_REMOVE_BILL = "remove_bill";
public static final String NOTIFICATION_ADD = "subscribe";
public static final String NOTIFICATION_REMOVE = "unsubscribe";
public static final String LEGISLATOR_CALL = "call";
public static final String LEGISLATOR_WEBSITE = "website";
public static final String LEGISLATOR_TWITTER = "twitter";
public static final String LEGISLATOR_YOUTUBE = "youtube";
public static final String LEGISLATOR_FACEBOOK = "facebook";
public static final String LEGISLATOR_DISTRICT = "district";
public static final String LEGISLATOR_CONTACTS = "contacts";
public static final String BILL_SHARE = "share";
public static final String BILL_TEXT = "text";
public static final String BILL_OPENCONGRESS = "opencongress";
public static final String BILL_GOVTRACK = "govtrack";
public static final String BILL_UPCOMING = "upcoming";
public static final String BILL_UPCOMING_MORE = "upcoming_more";
public static final String ANALYTICS_DISABLE = "disable";
public static final String ABOUT_VALUE = "open";
public static final String CHANGELOG_VALUE = "open";
public static final String PING_VALUE = "ping";
public static void ping(Activity activity) {
event(activity, EVENT_PING, PING_VALUE, null);
}
public static void aboutPage(Activity activity) {
event(activity, EVENT_ABOUT, ABOUT_VALUE, null);
}
public static void changelog(Activity activity) {
event(activity, EVENT_CHANGELOG, CHANGELOG_VALUE, null);
}
public static void reviewClick(Activity activity, String market) {
event(activity, EVENT_REVIEW, market, null);
}
public static void addFavoriteLegislator(Activity activity, String bioguideId) {
event(activity, EVENT_FAVORITE, FAVORITE_ADD_LEGISLATOR, bioguideId);
}
public static void removeFavoriteLegislator(Activity activity, String bioguideId) {
event(activity, EVENT_FAVORITE, FAVORITE_REMOVE_LEGISLATOR, bioguideId);
}
public static void addFavoriteBill(Activity activity, String billId) {
event(activity, EVENT_FAVORITE, FAVORITE_ADD_BILL, billId);
}
public static void removeFavoriteBill(Activity activity, String billId) {
event(activity, EVENT_FAVORITE, FAVORITE_REMOVE_BILL, billId);
}
public static void subscribeNotification(Activity activity, String subscriber) {
event(activity, EVENT_NOTIFICATION, NOTIFICATION_ADD, subscriber);
}
public static void unsubscribeNotification(Activity activity, String subscriber) {
event(activity, EVENT_NOTIFICATION, NOTIFICATION_REMOVE, subscriber);
}
public static void legislatorCall(Activity activity, String bioguideId) {
event(activity, EVENT_LEGISLATOR, LEGISLATOR_CALL, bioguideId);
}
public static void legislatorWebsite(Activity activity, String bioguideId, String network) {
event(activity, EVENT_LEGISLATOR, network, bioguideId);
}
public static void legislatorDistrict(Activity activity, String bioguideId) {
event(activity, EVENT_LEGISLATOR, LEGISLATOR_DISTRICT, bioguideId);
}
public static void legislatorContacts(Activity activity, String bioguideId) {
event(activity, EVENT_LEGISLATOR, LEGISLATOR_CONTACTS, bioguideId);
}
public static void billShare(Activity activity, String billId) {
event(activity, EVENT_BILL, BILL_SHARE, billId);
}
public static void billText(Activity activity, String billId) {
event(activity, EVENT_BILL, BILL_TEXT, billId);
}
public static void billOpenCongress(Activity activity, String billId) {
event(activity, EVENT_BILL, BILL_OPENCONGRESS, billId);
}
public static void billGovTrack(Activity activity, String billId) {
event(activity, EVENT_BILL, BILL_GOVTRACK, billId);
}
public static void billUpcomingMore(Activity activity, String sourceType) {
event(activity, EVENT_BILL, BILL_UPCOMING_MORE, sourceType);
}
public static void billUpcoming(Activity activity, String billId) {
event(activity, EVENT_BILL, BILL_UPCOMING, billId);
}
public static void markEntry(Activity activity, String source) {
event(activity, EVENT_ENTRY, source, source);
}
public static void analyticsDisable(Activity activity) {
event(activity, EVENT_ANALYTICS, ANALYTICS_DISABLE, "");
}
}