Archive for April, 2013

Guide: Android: Crash Reports and Usage Monitoring:

Well you reached a step where you have completed your application and want
to test it or even publish it to the Google Play store. At this point (It’s strongly recommended
to do that even before that) it’s very important to integrated some sort of crash reports
service in your application and could be very useful to integrate some kind of usage
monitoring system as well.

So, today I’m going to talk about those features and more specifically I’m going to talk
about integration of two crash report services:

1. Crittercism
2. ACRA with BugSense back-end.

Both of those services can be used for free, but got paid programs as well.
I’m going to talk about one usage monitoring system as well named:
3. Flurry.
Lets start with the crash reports. So how is it done:

1. Well for Crittercism the deal is very simple, head to their site: www.crittercism.com,
and sign in. You will need to download the jar file from Documentation for Android section.
Once you did that and added the jar file to the /libs folder of your project you are ready to start
configuring it. Open your Apps section and create an application for which you would like to
receive crash reports. Press the:

Untitled

button, and enter the application details. When you finish press the REGISTER APP button at
the bottom of the page. Open your Apps page again and you will see the newly
added application under the Registered Apps section. Click on the app name to enter
it’s configurations and go to the Settings page (red), under “To initiate Crittercism for this
Application:”
you will find a row of code (green) you will have to integrate in your application
in order for the crash reports service to work:

Untitled5

You should integrate this line in the first Activity of your application in the onCreate() method:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Crittercism.init(getApplicationContext(), "516a6c4e46b7c26e6f000002");
    // rest of code here...
}

Add this Activity to the Manifast file:

<activity android:name="com.crittercism.NotificationActivity"/>

Finally you need to add the following three permissions to your Manifest file:

<!--  Internet Permission  -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--  Crittercism Permissions  -->
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>

2. The second crash reporting service is greatly popular among Android developers:
Application Crash Report for Android or ACRA in short. up until not long ago
this service was used with Google Doc back-end to store the crash logs. this use of
Google Doc have became deprecated by Google, and they have asked developers nicely
not to use their service for this purpose.

So I searched for another back-end service that will work with ACRA and found out that
BugSense provide this kind of service. What you need to do as before is to head
to their site and sign up. Next, you will receive a dashboard screen, in it create a new
project that will represent the project you want to receive error reports for. Press the:

add project

button, and enter the application details like: Project Name, Billing Account, Platform (Technology) and another application details. Open your My projects page again and you will
see the newly added application:

new project

You can see that with the new project you receive an ApiKey(red) that you will use next to integrate ACRA in your project. To do that first head to acra.ch and download the
last .jar file from the Quick Setup section. As before add the jar file to the /libs folder of your project.

Now you can start integrate ACRA in your code, all you need to do is to add 2 lines to your application class:

import org.acra.*;
import org.acra.annotation.*;

@ReportsCrashes(formUri = "http://www.bugsense.com/api/acra?api_key=1e76b702", formKey="")
public class MyApplication extends Application 
{
    @Override
    public void onCreate() 
    {
        // The following line triggers the initialization of ACRA
        super.onCreate();
        ACRA.init(this);
        // rest of code here...
    }
}		

So as you can see you need to add the @ReportsCrashes annotation right before the class
definitions, where you would replace the api_key, with the key you were given from BugSense
when you registered your app. Second line would be:

ACRA.init(this);

to initialize ACRA monitoring. As with the first crash service don’t forget to add here the internet permission as well:

<!--  Internet Permission  -->
<uses-permission android:name="android.permission.INTERNET"/>

3. Now for the usage monitoring system: Flurry:
As with the other two services, we need to register so head to www.flurry.com, sign up for
the service, and open the Applications tab in your dashboard screen. click the Add a New Application option from the up-right corner, choose the platform of your project (Android in our case), pick a name for the project and select it’s category. Finally press the Create App button.

Next, you will receive the following screen:
flurry

Here as you can see you receive Your unique application key (1) and you have a button to
download the relevant SDK file for you platform (2). Download the SDK and as before integrate
it into the /libs folder of your application. Now for Flurry integration you need to add in each Activity of your application were you want to monitor user actions, those lines to start and stop monitoring:

@Override
protected void onStart()
{
    super.onStart();
    FlurryAgent.onStartSession(this, "65KYTTCTDCMT7J69S7XT");
}
	 
@Override
protected void onStop()
{
    super.onStop();		
    FlurryAgent.onEndSession(this);
}

To monitor an event you should add this line in the relevant position in your code:

FlurryAgent.onEvent("Event text");

If you want to monitor parameters as well then you need to pass a HashMap of parameters to the FlurryAgent like this:

final HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("String key", "String value");
FlurryAgent.logEvent("Text relevant to parameters", parameters);

As before, don’t forget to add the internet permission to your project:

<!--  Internet Permission  -->
<uses-permission android:name="android.permission.INTERNET"/>

And that it. Now you can and should monitor your application for errors and usage.
Enjoy and stay tuned.

April 23, 2013Emil Adjiev 1 Comment »
FILED UNDER :Guide , Guide - Android Development

Guide: Android: Use Camera Activity for Thumbnail and Full Size Image:

Today I have decided to show you how to use the build in camera Activity to
Take thumbnail and full size images. The reason for that is that this is a common problem
and many people get confused as for why do they get a low resolution image when they are
using the build in camera Activity for taking images in their Android application
(I was one of those people).

But first I would like to stop and explain why do you need thumbnail images in your app.
The problem with mobile devices as we all know is that they are low on resources (CPU,
Memory, Storage, etc.. today clearly this statement becomes less and less true), as for this
reason the Android OS was designed to allow a single application use only a very limited
amount of memory at run time.

That means that you can’t take a full 5 or 8 megapixels image and load it into memory just to
show it inside a small ImageView. Well, you can, but on the second or third image your
application will simply crash with an java.lang.OutOfMemoryError. So clearly you have
to care always to use the image with the most low resolution but yet satisfies with it quality at run time.

Back to where I started, people get confused because there are several ways to perform this
operation and I will show you them today:

Thumbnail Image:

Actually this will be the easiest way to take an image using the camera and to save it in
you application. The problem with this is that this image is very low resolution and is
not fit for displaying on a full mobile screen:

1. First of all define:

public static final int CAPTURE_IMAGE_THUMBNAIL_ACTIVITY_REQUEST_CODE = 1888; 

This will be your code so you could read the result of the camera Activity. You can
define here any number you would like.

2. Next fire an intent that will start an Activity for result.

Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(intent, CAPTURE_IMAGE_THUMBNAIL_ACTIVITY_REQUEST_CODE);

3. Finally receive the result and save it:

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{  
    //Check that request code matches ours:
    if (requestCode == CAPTURE_IMAGE_THUMBNAIL_ACTIVITY_REQUEST_CODE) 
    {
        //Check if your application folder exists in the external storage, if not create it:
        File imageStorageFolder = new File(Environment.getExternalStorageDirectory()+File.separator+"Your application Folder");
        if (!imageStorageFolder.exists())
        {
            imageStorageFolder.mkdirs();
            Log.d(TAG , "Folder created at: "+imageStorageFolder.toString());
        }

        //Check if data in not null and extract the Bitmap:
        if (data != null)
        {
            String filename = "image";
            String fileNameExtension = ".jpg";
            File sdCard = Environment.getExternalStorageDirectory();
            String imageStorageFolder = File.separator+"Your application Folder"+File.separator;
            File destinationFile = new File(sdCard, imageStorageFolder + filename + fileNameExtension);
            Log.d(TAG, "the destination for image file is: " + destinationFile );
            if (data.getExtras() != null)
            {
                Bitmap bitmap = (Bitmap)data.getExtras().get("data");
                try 
                {
                    FileOutputStream out = new FileOutputStream(destinationFile);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                    out.flush();
                    out.close();
                } 
                catch (Exception e) 
                {
                    Log.e(TAG, "ERROR:" + e.toString());
                }
            }
        }
    }
}

You can see that in this case we are getting our image from the Extras of the intent under
the “data” key. We cast it to a Bitmap and save it to a file using an FileOutputStream.
But actually we didn’t had to save it to file and could use the bitmap straight forward.

Full Size Image:

Well the big difference here is if we want to produce a high quality image from the
camera Activity we don’t have a choice but to save it into file and then use:

1. So First of all as before we need to create a static int that will be our requestCode:

public static final int CAPTURE_IMAGE_FULLSIZE_ACTIVITY_REQUEST_CODE = 1777; 

2. Next we fire again the same intent to start Activity for result but this time with a little difference:

Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "image.jpg");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(intent, CAPTURE_IMAGE_FULLSIZE_ACTIVITY_REQUEST_CODE);

and the difference in this case is with this line: intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));

Here we are actually passing an URI as an extra to the intent in order to save the image at this location
when it will be taken.

3. Finally we will receive the result in onActivityResult:

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{  
    //Check that request code matches ours:
    if (requestCode == CAPTURE_IMAGE_FULLSIZE_ACTIVITY_REQUEST_CODE) 
    {
        //Get our saved file into a bitmap object:
       File file = new File(Environment.getExternalStorageDirectory()+File.separator + "image.jpg");
       Bitmap bitmap = decodeSampledBitmapFromFile(file.getAbsolutePath(), 1000, 700);
    }
}

When decodeSampledBitmapFromFile method is:

public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) 
{ // BEST QUALITY MATCH
    
    //First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    // Calculate inSampleSize, Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    int inSampleSize = 1;

    if (height > reqHeight) 
    {
        inSampleSize = Math.round((float)height / (float)reqHeight);
    }
    int expectedWidth = width / inSampleSize;

    if (expectedWidth > reqWidth) 
    {
        //if(Math.round((float)width / (float)reqWidth) > inSampleSize) // If bigger SampSize..
        inSampleSize = Math.round((float)width / (float)reqWidth);
    }

    options.inSampleSize = inSampleSize;

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;

    return BitmapFactory.decodeFile(path, options);
}

For both cases don’t forget to add the relevent camera permissions to the manifest file:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

And that’s it, now you can add the build in camera capabilities to your application and take
images with the quality you want. Enjoy.

April 7, 2013Emil Adjiev 26 Comments »
FILED UNDER :Guide , Guide - Android Development