mirror of
https://github.com/scratchfoundation/scratchjr.git
synced 2024-11-24 16:17:55 -05:00
Switch to firebase analytics
* Remove ScratchJrApplication class - it was only being used to initialize the old Google Analytics. * Change AppUsage (home, school, other, noanswer) from being a prefix on `label` to being a Firebase user property. * Set the user property when loading the index page - it shouldn’t change for the rest of the session.
This commit is contained in:
parent
1be3feb791
commit
b965440709
9 changed files with 61 additions and 60 deletions
|
@ -30,9 +30,10 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.google.firebase:firebase-core:17.2.0'
|
||||
implementation 'com.google.firebase:firebase-analytics:17.2.0'
|
||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.gms:play-services-analytics:17.0.0'
|
||||
}
|
||||
|
||||
def appModuleRootFolder = '.'
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:name="ScratchJrApplication"
|
||||
android:hardwareAccelerated="true">
|
||||
<provider android:name="ShareContentProvider"
|
||||
android:grantUriPermissions="true"
|
||||
|
|
|
@ -30,9 +30,6 @@ import android.webkit.JavascriptInterface;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.google.android.gms.analytics.HitBuilders;
|
||||
import com.google.android.gms.analytics.Tracker;
|
||||
|
||||
/**
|
||||
* The methods in this inner class are exposed directly to JavaScript in the HTML5 pages
|
||||
* as AndroidInterface.
|
||||
|
@ -44,7 +41,6 @@ public class JavaScriptDirectInterface {
|
|||
|
||||
/** Activity hosting the webview running the JavaScript */
|
||||
private final ScratchJrActivity _activity;
|
||||
private final ScratchJrApplication _application;
|
||||
|
||||
/** Current camera view, if active */
|
||||
private CameraView _cameraView;
|
||||
|
@ -55,9 +51,8 @@ public class JavaScriptDirectInterface {
|
|||
/**
|
||||
* @param scratchJrActivity
|
||||
*/
|
||||
JavaScriptDirectInterface(ScratchJrActivity scratchJrActivity, ScratchJrApplication application) {
|
||||
JavaScriptDirectInterface(ScratchJrActivity scratchJrActivity) {
|
||||
_activity = scratchJrActivity;
|
||||
_application = application;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
@ -623,7 +618,13 @@ public class JavaScriptDirectInterface {
|
|||
// Analytics
|
||||
@JavascriptInterface
|
||||
public void analyticsEvent(String category, String action, String label, long value) {
|
||||
_application.getDefaultTracker().send(new HitBuilders.EventBuilder()
|
||||
.setCategory(category).setAction(action).setLabel(label).setValue(value).build());
|
||||
_activity.logAnalyticsEvent(category, action, label);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void setAnalyticsUser(String place) {
|
||||
if (place != null) {
|
||||
_activity.setAnalyticsUser(place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,7 @@ import android.webkit.WebView;
|
|||
import android.webkit.WebViewClient;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.google.android.gms.analytics.HitBuilders;
|
||||
import com.google.android.gms.analytics.Tracker;
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -55,10 +54,10 @@ public class ScratchJrActivity
|
|||
{
|
||||
/** Milliseconds to pan when showing the soft keyboard */
|
||||
private static final int SOFT_KEYBOARD_PAN_MS = 250;
|
||||
|
||||
|
||||
/** Log tag for Scratch Jr. app */
|
||||
private static final String LOG_TAG = "ScratchJr";
|
||||
|
||||
|
||||
/** Bundle key in which the current url is stored */
|
||||
private static final String BUNDLE_KEY_URL = "url";
|
||||
|
||||
|
@ -91,7 +90,7 @@ public class ScratchJrActivity
|
|||
|
||||
/** Set to true when the splash screen is done loading. This is used for unit testing. */
|
||||
private boolean _splashDone = false;
|
||||
|
||||
|
||||
/** Y starting and ending coordinate for soft keyboard scroll position */
|
||||
private int _softKeyboardScrollPosY0;
|
||||
private int _softKeyboardScrollPosY1;
|
||||
|
@ -104,8 +103,8 @@ public class ScratchJrActivity
|
|||
public int cameraPermissionResult = PackageManager.PERMISSION_DENIED;
|
||||
public int micPermissionResult = PackageManager.PERMISSION_DENIED;
|
||||
|
||||
/** Analytics tracker */
|
||||
private Tracker _tracker;
|
||||
/* Firebase analytics tracking */
|
||||
private FirebaseAnalytics _FirebaseAnalytics;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -153,8 +152,7 @@ public class ScratchJrActivity
|
|||
receiveProject(it.getData());
|
||||
}
|
||||
|
||||
ScratchJrApplication application = (ScratchJrApplication) getApplication();
|
||||
_tracker = application.getDefaultTracker();
|
||||
_FirebaseAnalytics = FirebaseAnalytics.getInstance(this);
|
||||
|
||||
// When System UI bar is displayed, wait one second and then re-assert immersive mode.
|
||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
|
||||
|
@ -283,7 +281,7 @@ public class ScratchJrActivity
|
|||
_soundManager.close();
|
||||
_soundRecorderManager.close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
@ -368,7 +366,7 @@ public class ScratchJrActivity
|
|||
webSettings.setLoadWithOverviewMode(false);
|
||||
webSettings.setUseWideViewPort(false);
|
||||
// Uncomment to enable remote Chrome debugging on a physical Android device
|
||||
//WebView.setWebContentsDebuggingEnabled(true);
|
||||
// WebView.setWebContentsDebuggingEnabled(true);
|
||||
|
||||
// Enable cookie persistence
|
||||
CookieManager.setAcceptFileSchemeCookies(true);
|
||||
|
@ -381,7 +379,7 @@ public class ScratchJrActivity
|
|||
CookieSyncManager.createInstance(this);
|
||||
|
||||
/* Object exposed to the JavaScript that makes it easy to bridge JavaScript and Java */
|
||||
JavaScriptDirectInterface javaScriptDirectInterface = new JavaScriptDirectInterface(this, (ScratchJrApplication) getApplication());
|
||||
JavaScriptDirectInterface javaScriptDirectInterface = new JavaScriptDirectInterface(this);
|
||||
_webView.addJavascriptInterface(javaScriptDirectInterface, "AndroidInterface");
|
||||
_webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
|
@ -406,8 +404,8 @@ public class ScratchJrActivity
|
|||
|
||||
// Track page load
|
||||
String[] parts = url.split("/");
|
||||
_tracker.setScreenName(parts[parts.length - 1]);
|
||||
_tracker.send(new HitBuilders.ScreenViewBuilder().build());
|
||||
String page = parts[parts.length - 1].split("\\?")[0];
|
||||
_FirebaseAnalytics.setCurrentScreen((Activity) view.getContext(), page, null);
|
||||
}
|
||||
});
|
||||
_webView.requestFocus(View.FOCUS_DOWN);
|
||||
|
@ -478,6 +476,28 @@ public class ScratchJrActivity
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* log a Firebase analytics event for the app
|
||||
* @param category
|
||||
* @param action
|
||||
* @param label
|
||||
*/
|
||||
public void logAnalyticsEvent(String category, String action, String label) {
|
||||
Bundle params = new Bundle();
|
||||
params.putString(FirebaseAnalytics.Param.ITEM_ID, action);
|
||||
params.putString(FirebaseAnalytics.Param.ITEM_CATEGORY, category);
|
||||
params.putString(FirebaseAnalytics.Param.ITEM_NAME, label);
|
||||
_FirebaseAnalytics.logEvent(FirebaseAnalytics.Event.VIEW_ITEM, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the preferred place for the user: home, school, other, noanswer
|
||||
* @param place
|
||||
*/
|
||||
public void setAnalyticsUser(String place) {
|
||||
_FirebaseAnalytics.setUserProperty("place_preference", place);
|
||||
}
|
||||
|
||||
public void translateAndScaleRectToContainerCoords(RectF rect, float devicePixelRatio) {
|
||||
float wx = _webView.getX();
|
||||
float wy = _webView.getY();
|
||||
|
@ -489,7 +509,7 @@ public class ScratchJrActivity
|
|||
_softKeyboardScrollPosY0 = topYPx;
|
||||
_softKeyboardScrollPosY1 = bottomYPx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Height of the status bar at the top of the screen
|
||||
*/
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package org.scratchjr.android;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.google.android.gms.analytics.GoogleAnalytics;
|
||||
import com.google.android.gms.analytics.Logger;
|
||||
import com.google.android.gms.analytics.Tracker;
|
||||
|
||||
public class ScratchJrApplication extends Application {
|
||||
private Tracker mTracker;
|
||||
|
||||
/**
|
||||
* Gets the default {@link Tracker} for this {@link Application}.
|
||||
* @return tracker
|
||||
*/
|
||||
synchronized public Tracker getDefaultTracker() {
|
||||
if (mTracker == null) {
|
||||
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
|
||||
// To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
|
||||
mTracker = analytics.newTracker(R.xml.global_tracker);
|
||||
}
|
||||
return mTracker;
|
||||
}
|
||||
}
|
|
@ -23,5 +23,6 @@ allprojects {
|
|||
url "https://maven.google.com"
|
||||
}
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ function indexLoadStart (afterUsage) {
|
|||
gn('blueguy').className = 'blue hide';
|
||||
gn('redguy').className = 'red hide';
|
||||
gn('gear').className = 'gear show';
|
||||
|
||||
|
||||
if (afterUsage) {
|
||||
gn('catface').className = 'catface show';
|
||||
gn('jrlogo').className = 'jrlogo show';
|
||||
|
@ -94,6 +94,7 @@ function indexLoadStart (afterUsage) {
|
|||
gn('usageOther').className = 'usageOther hide';
|
||||
gn('usageNoanswer').className = 'usageNoanswer hide';
|
||||
}
|
||||
iOS.setAnalyticsUser(AppUsage.currentUsage);
|
||||
}
|
||||
gn('gettings').className = 'gettings show';
|
||||
gn('startcode').className = 'startcode show';
|
||||
|
@ -113,13 +114,13 @@ function indexLoadUsage () {
|
|||
gn('redguy').className = 'red hide';
|
||||
gn('catface').className = 'catface hide';
|
||||
gn('jrlogo').className = 'jrlogo hide';
|
||||
|
||||
|
||||
gn('usageQuestion').textContent = Localization.localize('USAGE_QUESTION');
|
||||
gn('useSchoolText').textContent = Localization.localize('USAGE_SCHOOL');
|
||||
gn('useHomeText').textContent = Localization.localize('USAGE_HOME');
|
||||
gn('useOtherText').textContent = Localization.localize('USAGE_OTHER');
|
||||
gn('usageNoanswerText').textContent = Localization.localize('USAGE_NONE');
|
||||
|
||||
|
||||
gn('usageQuestion').className = 'usageQuestion show';
|
||||
gn('usageSchool').className = 'usageSchool show';
|
||||
gn('usageHome').className = 'usageHome show';
|
||||
|
|
|
@ -3,7 +3,6 @@ import IO from './IO';
|
|||
import Lobby from '../lobby/Lobby';
|
||||
import Alert from '../editor/ui/Alert';
|
||||
import ScratchAudio from '../utils/ScratchAudio';
|
||||
import AppUsage from '../utils/AppUsage';
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Tablet interface functions
|
||||
|
@ -356,8 +355,11 @@ export default class iOS {
|
|||
if (!value) {
|
||||
value = 1;
|
||||
}
|
||||
let usageLabel = label ? AppUsage.currentUsage + label : AppUsage.currentUsage;
|
||||
tabletInterface.analyticsEvent(category, action, usageLabel, value);
|
||||
tabletInterface.analyticsEvent(category, action, label, value);
|
||||
}
|
||||
|
||||
static setAnalyticsUser (preferredPlace) {
|
||||
tabletInterface.setAnalyticsUser(preferredPlace);
|
||||
}
|
||||
|
||||
// Web Wiew delegate call backs
|
||||
|
|
|
@ -6,7 +6,7 @@ export default class AppUsage {
|
|||
static get currentUsage () {
|
||||
return currentUsage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize currentUsage for attaching to Analytics events from
|
||||
* the usage cookie if it is set. currentUsage is blank if the cookie is
|
||||
|
@ -14,9 +14,9 @@ export default class AppUsage {
|
|||
*/
|
||||
static initUsage () {
|
||||
const usageCookie = Cookie.get('usage');
|
||||
currentUsage = (usageCookie) ? usageCookie + '::' : '';
|
||||
currentUsage = (usageCookie) ? usageCookie : '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the App should ask for the usage data (first time launched)
|
||||
* @return {boolean} True if the usage cookie has never been set
|
||||
|
@ -25,7 +25,7 @@ export default class AppUsage {
|
|||
var usageCookie = Cookie.get('usage');
|
||||
return usageCookie === null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the usage cookie for tracking Analytics Events
|
||||
* @param {string} kind answer from user to the usage survey (home, school, other, noanswer)
|
||||
|
@ -36,6 +36,6 @@ export default class AppUsage {
|
|||
} else {
|
||||
Cookie.set('usage', kind);
|
||||
}
|
||||
currentUsage = (kind === '') ? 'noanswer::' : kind + '::';
|
||||
currentUsage = (kind === '') ? 'noanswer' : kind;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue