Thursday, August 22, 2013

Detecting If An Android App Is In The Background

Was trying to understand when does my app go to the background. The Activity lifecycle methods does not help, as they can be called when switching between activities inside my app.
After a bit of googling, I found this: http://www.apptentive.com/blog/detecting-android-app-starts-and-stops/

Very good, and works like a charm, but please replace the calls to commit() with calls to apply() - see my previous post here: http://srooltheknife.blogspot.com/2013/08/stackoverflow-programming.html


Tuesday, August 20, 2013

StackOverflow Programming

Programming is my profession. I am doing this for a long time (damn, its over 30 years by now).

In the early stages of my career, the way to learn the trade, was by one of three ways:
- get subscription to some early stage hobbyist magazine (I fondly remember Byte magazine)
- get some books
- get a mentor

I was lucky enough to have a great mentor that introduced me to the field - my uncle Dani who was a programmer in the 70s doing really cool stuff (real-time, complex systems that were ahead of their time). He introduced me to object-oriented programming before it was IN, using languages as Forth, and Modula. He helped me get my first Mac (the cost of which was like a used car here).

Anyway, at that time you had to read a lot. From paper.

Fast forward 15 years, and the internet was taking the stage.

Now, knowledge quickly started to spread, be shared, and be available to everyone.

Fast forward 15 more years, and now our brains are re-wired. We don't remember anything we learn. We don't have to... (see the book "The Shallows" for more on this subject - link below).

Its the age of StackOverflow programming.

Sometimes, it is great. Sometimes its a dangerous, or problematic way... Here's a little anecdote.

Doing Android programming, I stored some long term values in the SharedPreferences object. Turns out that some examples on the internet tell you to use editor.commit() after you store or modify your values.
Well, if you don't need the result of this, you would be better off if you use editor.apply().

As the Android documentation say:

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit()will block until all async commits are completed as well as the commit itself.
As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.
You don't need to worry about Android component lifecycles and their interaction with apply() writing to disk. The framework makes sure in-flight disk writes from apply() complete before switching states
References: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

Maybe the lesson here is really "Read the Documentation" and don't just code by copy and paste - at this age of Stack Overflow programming, spend the time reading. At least from time to time...


Edit: some people raised a concern that with apply() you need to worry about "race conditions" or other issues. Again, READ THE DOCS (as quoted above):

As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.



Monday, August 5, 2013

Keerbot Drawing Program

My friend Gilad is building a wall drawing robot.

A very cool one.

You can see some of his work here: http://www.keerbot.com/

Gilad asked me to write a little utility that will allow him to better debug the robot. This little tool allows you to draw on the PC, and then save the resulting drawing to a text file with G-Codes the robot can understand. It's a C# Visual Studio 2010 express project, but you can easily adopt it to any .Net environment.

I think it's a good tutorial for anyone who wants to create a simple Windows drawing program.

Hope you like that, and go check the Keerbot site and stay tuned for more cool stuff from Gilad.

So, here is the code, and you can get the whole VisualStudio project here: https://dl.dropboxusercontent.com/u/3647610/KeerbotProject.zip

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// Keerbot Drawing Creator Program
//
// Written by: Israel Roth
//
// This code is provided with no warranties, but its free to use for any purpose.
//
// (c) 2013. Israel Roth
//

namespace Keerbot1
{
    public partial class Form1 : Form
    {
        private bool isMouseDown = false;
        private List points;
        private List> shapes;

        // scalePoint translate a point from the screen coordinates to the Keerbot coordinate space

        private Point scalePoint(Point inPoint)
        {
            int xx = (inPoint.X - 175) * 2;
            int yy = (250 - inPoint.Y) * 2;
            return new Point(xx, yy);
        }

        public Form1()
        {
            InitializeComponent();
            points = new List(100);
            shapes = new List>(10);
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            isMouseDown = true;
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            isMouseDown = false;
            if (points.Count > 2)
            {
                shapes.Add(points);
            }
            points = new List(100);
        }
                                                                                                                                                                            
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            Point scaled = scalePoint(e.Location);
            toolStripStatusLabel1.Text = scaled.X + "," + scaled.Y;
            if (isMouseDown)
            {
                points.Add(new Point(e.X, e.Y));
                panel1.Invalidate();
            }

        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (shapes.Count > 0)
            {
                foreach (List s in shapes)
                {
                    DrawPoints(s, e);
                }
            }
            DrawPoints(points, e);
       }

        private void DrawPoints(List points, PaintEventArgs e)
        {
            if (points.Count > 2)
            {
                Pen pen = new Pen(Color.Black, 1);
                Point[] pArray = points.ToArray();
                e.Graphics.DrawLines(pen, pArray);
            }
         }

        private void button1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }

        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            string name = saveFileDialog1.FileName;
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(name))
            {
                foreach (List s in shapes)
                {
                    bool isFirst = true;
                    foreach (Point q in s)
                    {
                        Point p = scalePoint(q);
                        if (isFirst)
                        {
                            file.WriteLine(startLineText.Text + " X" + p.X + " Y" + p.Y + " Z" + zUpText.Text);
                            isFirst = false;
                        }
                        else
                        {
                            file.WriteLine(startLineText.Text + " X" + p.X + " Y" + p.Y + " Z" +
                                                                                    zDownText.Text);
                        }
                    }
                }
            }

        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            shapes.Clear();
            points.Clear();
            panel1.Invalidate();
        }

    }
}


Thursday, July 25, 2013

Automating Android Testing

So, I am dealing now with improving the performance of an Android app I am working on.
The app is an education app where users can view their books, collaborate and do many more things. There are many things happening in this app, and some of them negatively impact the user experience in terms of performance and responsiveness.
As I am approaching the task, I decided that I must have some ways to measure the current performance of the app, and its various parts.
I basically want to perform a user operation, and measure the time it takes the app to respond.
Assuming the way this works is:
User Input -> Various lengthy operations -> Display updated
If I can improve the lengthy operations performance, I will get a better user experience.
To establish a method for measuring the performance and any progress I make, and not just basing this on subjective feeling, I wanted to make some automated framework, whereby a script can activate user actions, and report back the time it took the app operations until the desired feedback is presented to the user.
There are various methods described elsewhere, some rely on accessibility and automating various widget actions based on that. In my case, I do not have widgets, and I wanted a simpler way.
So my simple solution consists of a small footprint web server (or http daemon) embedded in my app. I based this on Nano HTTPD: https://github.com/NanoHttpd/nanohttpd which is a very simple http daemon you use by subclassing the NanoHTTPD class.
When you subclass NanoHTTPD, you are expected to override the serve method to respond to http requests.

I wrote mine to look for parameters in the query string this way:



public Response serve(String uri, Method method, Map headers,
   Map parms, Map files) {
 for (Map.Entry kv : parms.entrySet()) {
  String key = kv.getKey();
  String strValue = kv.getValue();
  if (key.compareTo("cmd") == 0) {
   _callbackHandler.TA_PerformCommand(strValue);
   break;
  }
  else {
   Log.d("httpd", "Invalid param: " + key);
  }
  final String html = "Command Received";
  return new NanoHTTPD.Response(Response.Status.OK, MIME_HTML, html);
 }

The callback handler is an object passed to the constructor of my NanoHTTPD sub-class.

Since some of the operations I try to measure take time, and I want to measure that time, I added logic to my serve method to wait and sleep (since it is anyway being run on a separate thread) until the operation is done, and to report back the timing of this operation. This is the basic code:



public Response serve(String uri, Method method, Map headers,
   Map parms, Map files) {
 for (Map.Entry kv : parms.entrySet()) {
  String key = kv.getKey();
  String strValue = kv.getValue();
  if (key.compareTo("cmd") == 0) {
   startMeasurements();
   _callbackHandler.TA_PerformCommand(strValue);
   while (_inMeasurement) {
    try {
     Thread.sleep(1L, 0);
     long delta = System.currentTimeMillis() -
        _startTime;
     if (delta > 6000L) { // timeout after 6 sec
      addMeasurement("timeout");
      endMeasurements();
     }
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   String htmlResult = measurementsToHTML();
   return new NanoHTTPD.Response(Response.Status.OK,
       MIME_HTML, htmlResult);
  }
  else {
   Log.d("httpd", "Invalid param: " + key);
  }
  final String html = "Command Received";
  return new NanoHTTPD.Response(Response.Status.OK, MIME_HTML, html);
 }


The callback handler's TA_PerformCommand calls my server class endMeasurements once the operation is done setting the _inMeasurement flag to false.
If the action takes more than 6 seconds (a safe upper limit in my case), the loop times out and we end the measurement.

Once I have this little server set in my app, it is quite easy to write a testing script using JMeter, or a nice little app I found for my Mac: http://fakeapp.com/

It is now quite easy for me to repeat a sequence of tests, capture the times, tweak some of the code and test again.



Sunday, May 26, 2013

Analyzing SQLite on Android

Working on an Android project with quite a sophisticated SQLite DB, I am now trying to optimize the program access to the DB, and wanted to get access to the DB file. I don't like to root my devices (maybe I am over-sensitive about that), so I used this answer by RRTW from Stack Overflow (http://stackoverflow.com/questions/4452538/android-location-of-sqlite-database-on-the-device):


File f=new File("/data/data/your.app.package/databases/your_db.db3");
FileInputStream fis=null;
FileOutputStream fos=null;

try
{
  fis=new FileInputStream(f);
  fos=new FileOutputStream("/mnt/sdcard/db_dump.db");
  while(true)
  {
    int i=fis.read();
    if(i!=-1)
    {fos.write(i);}
    else
    {break;}
  }
  fos.flush();
  Toast.makeText(this, "DB dump OK", Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
  e.printStackTrace();
  Toast.makeText(this, "DB dump ERROR", Toast.LENGTH_LONG).show();
}
finally
{
  try
  {
    fos.close();
    fis.close();
  }
  catch(IOException ioe)
  {}
}


So I can now grab the file with DDMS and examine it on my Mac.