Trying to use Google Analytics for caught and uncaught exceptions.
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 14 Dec 2014 19:47:11 +0000 (20:47 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 14 Dec 2014 19:47:11 +0000 (20:47 +0100)
app/build.gradle
app/src/main/AndroidManifest.xml
app/src/main/java/name/gumartinm/weather/information/app/WeatherInformationApp.java
app/src/main/res/xml/exceptions_tracker.xml [new file with mode: 0644]
app/src/main/res/xml/global_tracker.xml [new file with mode: 0644]

index 2a5029c..97ca02d 100644 (file)
@@ -2,6 +2,12 @@ apply plugin: 'com.android.application'
 
 android {
     signingConfigs {
+        releaseSigning {
+            keyAlias ''
+            keyPassword ''
+            storeFile file('')
+            storePassword ''
+        }
     }
     compileSdkVersion 18
     buildToolsVersion '21.1.1'
@@ -18,6 +24,7 @@ android {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
             buildConfigField "boolean", "DEBUG_MODE", "false"
+            signingConfig signingConfigs.releaseSigning
         }
         debug {
             buildConfigField "boolean", "DEBUG_MODE", "true"
index 73297f4..4c156e8 100644 (file)
         <meta-data
             android:name="com.google.android.gms.version"
             android:value="@integer/google_play_services_version" />
+        <meta-data
+            android:name="com.google.android.gms.analytics.globalConfigResource"
+            android:resource="@xml/global_tracker" />
 
     </application>
 
index dd4146a..cca8dcf 100644 (file)
 package name.gumartinm.weather.information.app;
 
 import android.app.Application;
+import android.content.Context;
+
+import com.google.android.gms.analytics.GoogleAnalytics;
+import com.google.android.gms.analytics.HitBuilders;
+import com.google.android.gms.analytics.StandardExceptionParser;
+import com.google.android.gms.analytics.Tracker;
+
+import java.util.HashMap;
 
 import name.gumartinm.weather.information.BuildConfig;
+import name.gumartinm.weather.information.R;
 import timber.log.Timber;
 
 public class WeatherInformationApp extends Application {
@@ -28,7 +37,92 @@ public class WeatherInformationApp extends Application {
 
         if (BuildConfig.DEBUG_MODE) {
             Timber.plant(new Timber.DebugTree());
+        } else {
+            Timber.plant(new GoogleAnalyticsReportingTree(
+                    new GoogleAnalyticsTrackers(this.getApplicationContext())));
         }
     }
 
+    private static class GoogleAnalyticsTrackers {
+
+        private enum TrackerName {
+            EXCEPTIONS_TRACKER, // Tracker used when logging caught exceptions in this app.
+        };
+
+        private final HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();
+        private final Context appContext;
+
+        private GoogleAnalyticsTrackers(final Context appContext) {
+            this.appContext = appContext;
+        }
+
+        /**
+         * Get tracker
+         * @param trackerId
+         * @return Tracker
+         */
+        private synchronized Tracker getTracker(final TrackerName trackerId) {
+            if (!mTrackers.containsKey(trackerId)) {
+
+                final GoogleAnalytics analytics = GoogleAnalytics.getInstance(appContext.getApplicationContext());
+
+                final Tracker t = (trackerId == TrackerName.EXCEPTIONS_TRACKER) ?
+                        analytics.newTracker(R.xml.exceptions_tracker) :
+                        analytics.newTracker(R.xml.exceptions_tracker);
+
+                // Do not retrieve user's information. I strongly care about user's privacy.
+                t.enableAdvertisingIdCollection(false);
+
+                mTrackers.put(trackerId, t);
+            }
+            return mTrackers.get(trackerId);
+        }
+
+        /**
+         * Send exception
+         * @param exception
+         * @param trackerName
+         */
+        private void send(final Throwable exception, final TrackerName trackerName) {
+            final Tracker tracker = this.getTracker(trackerName);
+
+            // Build and send exception.
+            tracker.send(new HitBuilders.ExceptionBuilder()
+                    .setDescription(
+                            new StandardExceptionParser(appContext.getApplicationContext(), null)
+                                    .getDescription(Thread.currentThread().getName(), exception))
+                    .setFatal(false)
+                    .build());
+        }
+    }
+
+    private static class GoogleAnalyticsReportingTree extends Timber.HollowTree {
+        private final GoogleAnalyticsTrackers analyticsTrackers;
+
+        private GoogleAnalyticsReportingTree(final GoogleAnalyticsTrackers analyticsTrackers) {
+            this.analyticsTrackers = analyticsTrackers;
+        }
+
+        @Override
+        public void i(final String message, final Object... args) {
+            // Do nothing, just report exceptions.
+        }
+
+        @Override
+        public void i(final Throwable t, final String message, final Object... args) {
+            i(message, args); // Just add to the log.
+        }
+
+        @Override
+        public void e(final String message, final Object... args) {
+            i("ERROR: " + message, args); // Just add to the log.
+        }
+
+        @Override
+        public void e(final Throwable exception, final String message, final Object... args) {
+            e(message, args);
+
+            this.analyticsTrackers.send(exception, GoogleAnalyticsTrackers.TrackerName.EXCEPTIONS_TRACKER);
+        }
+    }
 }
diff --git a/app/src/main/res/xml/exceptions_tracker.xml b/app/src/main/res/xml/exceptions_tracker.xml
new file mode 100644 (file)
index 0000000..8334404
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools"
+           tools:ignore="TypographyDashes">
+    <integer name="ga_sessionTimeout">300</integer>
+    <bool name="ga_autoActivityTracking">false</bool>
+    <bool name="ga_anonymizeIp">true</bool>
+    <bool name="ga_reportUncaughtExceptions">false</bool>
+    <string name="ga_logLevel">verbose</string>
+    <string name="ga_trackingId"></string>
+</resources>
diff --git a/app/src/main/res/xml/global_tracker.xml b/app/src/main/res/xml/global_tracker.xml
new file mode 100644 (file)
index 0000000..6248311
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:tools="http://schemas.android.com/tools"
+           tools:ignore="TypographyDashes">
+    <integer name="ga_sessionTimeout">300</integer>
+    <bool name="ga_autoActivityTracking">false</bool>
+    <bool name="ga_anonymizeIp">true</bool>
+    <bool name="ga_reportUncaughtExceptions">true</bool>
+    <string name="ga_logLevel">verbose</string>
+    <string name="ga_trackingId"></string>
+</resources>