Sunday, January 11, 2015

Calculating Google Analytics event value variance & standard deviation

Here's I calculated the var & stddev of an event value (X) tracked by Google Analytics:
  1. Add a second event with the value X^2
  2. Calculate the variance using this formula: Var = E(X^2) - [E(X)]^2  (note that Google Analytics already calculates E(X^2) & E(X), which are, in this case the event's average).

Friday, November 28, 2014

Can Google Play Services introduce bugs to my apps without code update?

Here's a short list of FC bugs I think Google Play Services introduced remotely to my apps:

Wednesday, September 3, 2014

Removing app from Amazon App Store

Few years ago I had few apps published on Amazon App Store. Since the performance on that market wasn't impressive I didn't update them over time. Few weeks ago I decided to unpublish those apps.

Problem: No way to unpublish apps from the Amazon App Store.
Solution 1: Contact Amazon support and ask them to remove the app. They might want reasons and such.
Solution 2: Limit app distribution to the smallest market you can find on their list.

Monday, April 7, 2014

Upgrading Google Analytics for Android v2 to v4

I couldn't find a single place where all this information can be found, so here are the steps to upgrade Google Analytics for Android v2 to v4 (Google Play Services). This does not include the steps needed to integrate Google Play Services (some Manifest.xml & library includes):

  1. Move the analytics.xml from /res/values to /res/xml
  2. Add the following line to the Manifest.xml:
    <meta-data android:name="com.google.android.gms.analytics.globalConfigResource" android:resource="@xml/analytics" />
    
  3. Replace the campaign tracker in the Manifest.xml if need:
    <service android:name="com.google.android.gms.analytics.CampaignTrackingService" />
    <receiver android:name="com.google.android.gms.analytics.CampaignTrackingReceiver"
              android:exported="true">
       <intent-filter>
      <action android:name="com.android.vending.INSTALL_REFERRER" />
      </intent-filter>
    </receiver>
    
  4. Add the following code to the Application class:
  5. private Tracker mTracker = null;
    
    synchronized public Tracker getTracker() {
      if (mTracker == null) {
        GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
        mTracker = analytics.newTracker(R.xml.analytics);
      }
      
      return mTracker;
    }
    
  6. Activity tracking - replace:
    @Override
    public void onStart() {
      super.onStart();
      
      EasyTracker.getInstance().activityStart(this);
      mTracker = EasyTracker.getTracker();
    }
    
    @Override
    public void onStop() {
      super.onStop();
      
      EasyTracker.getInstance().activityStop(this);
    }
    
    
    with:
    @Override
    public void onStart() {
      super.onStart();
      
      mTracker = ((MyApplication)getApplication()).getTracker();
      GoogleAnalytics.getInstance(this).reportActivityStart(this);
    }
     
    @Override
    public void onStop() {
      super.onStop();
      
      GoogleAnalytics.getInstance(this).reportActivityStop(this);
    }
    
  7. Update events tracking to the new format:
  8. mTracker.send(new HitBuilders.EventBuilder()
      .setCategory(category)
      .setAction(action)
      .setLabel(label)
      .setValue(val)
      .build());
    

Sunday, December 29, 2013

java.lang.IllegalArgumentException: Can't pass bindargs for this sql :insert into....

I've optimized one of my Android apps to use compiled statement (SQLiteStatement) instead of direct SQL to improve performance.

After doing so, I started to get some unhandled exception reports, which had the following in common: Android 4.0.3, Turkish locale and the following stack trace:
java.lang.IllegalArgumentException: Can't pass bindargs for this sql :insert into android.database.sqlite.SQLiteProgram.compileAndbindAllArgs(SQLiteProgram.java)
android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java)
android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java)
android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java)
 
Solution: When using SQLiteStatement write SQL in uppercase letters.

Reason: After searching for some time I found this issue. The SQLiteStatement checks the type of the SQL inside. The checking process is simple string compare of the SQL prefix (INSERT/UPDATE/SELECT/etc..). The string compare in Android 4.0.3 seem to be culture dependent, and in Turkish locale uppercase 'insert' translate to 'İNSERT' (note the dot above the Turkish I') which gives an error in SQL.

Wednesday, December 4, 2013

Notes on using Google Play Game Services

Here are few tips & tricks that helped me [on going post]:

Google Drive: This spreadsheet contains too much content and can no longer be edited

I got this error ("This spreadsheet contains too much content and can no longer be edited") while using ACRA reporting to Google Drive (legacy). In general you should prevent your spreadsheet from reaching the maximum limits (see this for ACRA example). Once you get this error - you can't clean the spreadsheet anymore.

Solution: It's a bypass, not a real solution - click on "File" => "See revision history". Select a revision that should work and click "Restore this revision". You'll lose your latest information, but the spreadsheet will be writable. From now on make sure you're not getting anything close to the limits.