Sunday, January 6, 2013

Advanced ACRA 3: Auto delete old records

One issue with using Google Spreadsheet for ACRA reports is the size limitation of Google Spreadsheet. Specifically, the maximum size of Google Spreadsheet is 400K cells (which translates to 11K reports as of ACRA 4.2.3). More over, if the Google Spreadsheet become too large it simply won't open (there are multiple post of people saying they just can't open large ACRA Spreadsheets).

To avoid this limitation - automatically delete old ACRA reports:
1. Add the following Google Apps Script to your ACRA Google Spreadsheet ("Tools" -> "Script Editor" -> "Blank Project").
2. Schedule the script to run once a day using Time-Driven trigger (in the Script Editor, "Resources"-> "Current script's triggers").

I've extended the script to:
*. remove old versions entries so I could focus on the latest version only, just adjust the version number parameter.
*. Remove invalid entries (I think that was solved in later version of ACRA).



function deleteObsoleteRows() {  
  // Application specific
  //  // https://developers.google.com/apps-script/class_spreadsheetapp#openById
  var SPREAD_SHEET_KEY = "ENTER YOUR KEY HERE";
  //  // Delete any recoprd below this version 
  var APP_VERSION_CODE_CURRENT = 0;

  // ACRA 4.2.3 version specific - report cell locations
  var APP_VERSION_CODE = 2;

  // Maximum records per spreadsheet - if there are more - delete the oldest records
  // Google Spreadhseet over too many records is not useable
  var MAX_RECORDS = 10000;
    
  // For details see 
  // https://developers.google.com/apps-script/class_spreadsheetapp#openById
  var sheet = SpreadsheetApp.openById(SPREAD_SHEET_KEY);
  //var sheet = SpreadsheetApp.getActiveSheet();
  
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();
  var values = rows.getValues();

  // Delete invalid records
  for (var i = numRows - 1; i >= 1; i--) {
    var row = values[i];
    
    // Logger.log(row);
    
    // Delete empty APP_VERSION_CODE
    if (row[APP_VERSION_CODE] == "") 
      sheet.deleteRow(i+1);
    // Delete old version records
    else if (row[APP_VERSION_CODE] < APP_VERSION_CODE_CURRENT) 
      sheet.deleteRow(i+1);
  }
  
  // Delete the oldest records if there are too many records
  for (var i = numRows - MAX_RECORDS; i > 0; i--) {
    sheet.deleteRow(2);
  }
};

Wednesday, December 26, 2012

Binding bitmap to ImageView with SimpleAdapter

SimpleAdapter does not bind bitmaps to ImageView. That's the bottom line. From viewing the source of SimpleAdapter it seems it only binds text and integers (???) to ImageView.

I didn't like the extension I've found which do that (it overrides the whole binding function instead of just enhancing it). so I wrote my own.

package com.utils;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleAdapter;

public class SimpleAdapterEx extends SimpleAdapter {
 private int mResource;
    private int[] mTo;
    private String[] mFrom;

    private List<? extends Map<String, ?>> mData;
 
 public SimpleAdapterEx(Context context, List<? extends Map<String, ?>> data,
            int resource, String[] from, int[] to) {
  super(context, data, resource, from, to);
  
  mResource = resource;
  mData = data;
  mTo = to;
  mFrom = from;
 }

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
  View v = super.getView(position, convertView, parent);

  v = createViewFromResourceEx(v, position, convertView, parent, mResource);

  return v;
    }
 
 @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
  View v = super.getDropDownView(position, convertView, parent);
  
  v = createViewFromResourceEx(v, position, convertView, parent, mResource);
  
  return v;
 }
 
    private View createViewFromResourceEx(View v, int position, View convertView,      
            ViewGroup parent, int resource) {
     
        bindView(position, v);

     return v;
    }
        
    private void bindView(int position, View view) {
        final Map dataSet = mData.get(position);
        if (dataSet == null) {
            return;
        }

        final ViewBinder binder = getViewBinder();
        final String[] from = mFrom;
        final int[] to = mTo;
        final int count = to.length;

        for (int i = 0; i < count; i++) {
            final View v = view.findViewById(to[i]);
            if (v != null) {
                final Object data = dataSet.get(from[i]);
                String text = data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }

                boolean bound = false;
                if (binder != null) {
                    bound = binder.setViewValue(v, data, text);
                }

                if (!bound) {
                    if (v instanceof ImageView) {
                        if (data instanceof Bitmap) {
                            setViewImage((ImageView) v, (Bitmap)data);                            
                        }                        
                    }
                }
            }
        }     
    }      
    
    private void setViewImage(ImageView imageView, Bitmap bitmap) {
     imageView.setImageBitmap(bitmap);
    }
}

Friday, December 21, 2012

Android Market Optimization: Part II

Earlier this year I wrote about Android Market Optimization blog posts. Now there are few sites that can help you do that:
In general you should follow ASO tag in your favorite tech blog, for example on TechCrunch.

Thursday, November 22, 2012

Eclipse: Unable to find Action Set

Problem: After updating Eclipse my Android plug-in stopped working. Checking a bit more, all my Eclipse plug-ins stopped working (they even didn't appear in the Help->About windows).

In the errors log window (Window->Show View->Error Log) I saw the error "Unable to find Action Set" for all the plug-ins. For example, the Android plug-ins errors:
Unable to find Action Set: adt.actionSet.lint
Unable to find Action Set: adt.actionSet.avdManager
Unable to find Action Set: adt.actionSet.refactorings
Unable to find Action Set: adt.actionSet.wizards

Solution: I checked many options, bottom line, the problem was solved in my case when I've uninstalled (Help->About->Installation Details) a package called: Object Teams Patch for JDT/Core

Tuesday, September 11, 2012

Advanced ACRA 2: Frequent errors detection

In my first ACRA post I wrote about detecting which Android versions generates the errors using Google Docs. This time I'll write on the most basic problem - finding which error happens the most. It is possible to group by full stack trace, however, the stack trace are not the same even on exactly the same errors. Instead, my approach is to compare the exception & the function that actually threw the exception. It might produce incorrect results if there are multiple similar exceptions.

Here's how it's done, open the Google Doc's ACRA spreadsheet:
  1. Rename the first sheet to 'Sheet1'
  2. Add new sheet
  3. In Cell A1 set text: "Short Stack"
  4. In Cell A2 set text: "=LEFT(Sheet1!P2,FIND("(", Sheet1!P2, 1))"
  5. Copy cell A2 to match the rows in Sheet1 (e.g. to cells A3, A4, A5, ...)
  6. Select column A in Sheet2, and create a pivot table ("Data" -> "Pivot table report...")
  7. In the pivot table sheet:
    • "Rows" -> "Add field" : "Short Stack"
    • "Values" -> "Add field" : "Short Stack", summarize by: "COUNTA"
Note: this list is for ACRA v4.2.3. With ACRA 4.3.0+ the 'Stack Trace' column might not be P

Monday, August 13, 2012

Eclipse autocomplete doesn't work

After formatting my computer I had to reinstall everything. When I started to work with my new Eclipse Juno on my Android project the autocomplete didn't work. It took my few searches on Google to find the answer, so I'll improve that page pagerank so others can find it faster. The answer is here.

Wednesday, August 8, 2012

Diagnosing repetitive BSOD

I had repetitive BSOD on my Windows 7 x64 Samsung laptop.

Here is the steps I think I should have taken (stop when the problem found):
1. Download Blue Screen View by Nir Sofer and check which driver cause the BDOS. If it's the same driver all the time - root cause found.

2. Memory check: (don't use the Windows 7 built-in memory check, it missed my problem) Download memtest86+ and check your physical memory. This tool might taken few hours to run.

3. Disk check: Run full disk check - open the disk in Windows Explorer, right click on the driver root, click on "Properties", than "Tools", under "Error Checking", check all check boxes and press on check now. After rebooting you can view the results in the "Events Viewer" under "Windows Logs" -> "Application", sort by "Source" column and search for "Wininit"

If nothing found so far, my best guess is  to backup the computer & re-format it. If the BDOS continues it's an hardware issue, otherwise it was some other software issue.