Android
Problems Using Google Analytic in Android in the application class
For a while now you have been able to use Google Analytics to track user Analytics in Android applications. Its pretty simple to use, but I found one bug that other people may run in to. The application I’m working on has its static application data stored in a custom instance that implements the Android application class. When I first started working with Analytics I placed the tracker in the application class, and had the tracker start during the constructor of the application. This didn’t work at all, as the tracker.startNewSession would throw null pointer exceptions try to create a database.
Lucky for me, all my activities extend a custom activity, so I could add the tracker there. At first I wasn’t too happy to have an instance of the tracker per activity, but it turns out that getInstance() function is actually getting an instance of a static class, so in reality there is only one instance of the tracker in memory.
Hope this helps someone getting started with Google Analytics in Android.
-James
How to Add bitmaps from Camera Activity Dynamically to Gallery
So I spent a few hours this morrning looking for a demo on how to add bitmaps that I got from the Camera Activity Dynamicly to a Gallery View. Here is the code I came up with. Let me know if there is a better way.
import java.util.Stack;
import java.util.Vector;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.Gallery;
import android.widget.ImageView;
public class Pictures extends Activity implements OnClickListener {
private static final int PICTURE_RESULT = 1;
Context ctx = null;
Button next = null;
Button addPhoto = null;
Gallery gal = null;
ImageAdapter images =null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pictures);
ctx = this.getBaseContext();
next = (Button) this.findViewById(R.id.widget30);
next.setOnClickListener(this);
addPhoto = (Button) this.findViewById(R.id.widget35);
addPhoto.setOnClickListener(this);
images = new ImageAdapter(this);
gal = (Gallery) this.findViewById(R.id.widget36);
gal.setAdapter(images);
}
@Override
public void onClick(View v) {
if (v == next) {
return;
} else if (v == addPhoto) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
this.startActivityForResult(intent, PICTURE_RESULT);
}
}
@Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if (reqCode == PICTURE_RESULT) {
if (resultCode == Activity.RESULT_OK) {
Bundle b = data.getExtras();
Bitmap pic = (Bitmap) b.get("data");
if (pic != null) {
images.AddImage(pic);
gal.setAdapter(images); //forces the gallery to add the new images.
}
}
}
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private Vector<Bitmap> images = new Vector<Bitmap>();
public ImageAdapter(Context c) {
mContext = c;
}
public void AddImage(Bitmap b)
{
images.add(b);
}
@Override
public int getCount() {
return images.size();
}
@Override
public Object getItem(int arg0) {
return images.get(arg0);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView img;
if(convertView ==null)
{
img = new ImageView(mContext);
}
else
{
img = (ImageView)convertView;
}
img.setImageBitmap(images.get(position));
return img;
}
}
}
And the xml layout:
<LinearLayout
android:id="@+id/widget34"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
>
<Button
android:id="@+id/widget35"
android:layout_width="209px"
android:layout_height="wrap_content"
android:text="Add Photo"
>
</Button>
<Gallery
android:id="@+id/widget36"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</Gallery>
<Button
android:id="@+id/widget30"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next"
>
</Button>
</LinearLayout>
Android 1.x users now make up only about 10% of the market.
I was looking at the platform versions that were using Android Market for the first two weeks of February. Android 1.x users now make up 10.1% of the users using Android market. I haven’t been able to figure out how many users use the market in a given month, so I’m unsure how many users 10% is.
For many applications the API changes in 1.x to 2.x isn’t that important. In fact of all my applications, Only Private Browser could make good use of the 2.x API. (Photo of the Day uses live wallpapers, so it has to use 2.x, so it doesn’t count.) I would recommend supporting the lowest API version that fits your applications design, because why cut your market by 10% if you don’t have too. Also, there might be less competition in the 1.x market, because all the new applications will probably target 2.x just because its newer.
There are a lot of great API improvements in 2.x. Opengl support is better, the webkit object actually exports the plugin interface, and the you can catch ssl certificate errors, and redirections. There are a ton of other great changes that are documented in the API differences pages.
So what do you guys think, Should I drop support for 1.x in Private Browser? Are you going to drop support for 1.x in the near future? Take the poll and leave a comment and let me know what you think. Frankly I’m on the fence right now.
-James
Physic Libraries In Android
I came a cross a cool HTML5 pinball demo that was using the Box2d library. Turns out there is a java port called JBox2D. Might make for some cool Android games… I even found a quick Android intro!
-James
Android Stereo Right and Left PCM Raw Audio
I have been playing with raw audio generation (PCM) in Android using AudioTrack. It’s pretty easy to do, but I had trouble finding information about stereo byte formatting when streaming, in other words how to mix between the left and right stream. After playing with the code for a while, i figured it out and boy is it simple, the even bytes are the left channel and the odd is the right channel.
In other words:
I hope this saves you some time!
-James
Huge Android Canceled Sales Numbers
I have noticed lately that I have been getting more and more sales that canceled after a few minutes. I believe that users are starting to learn that they can try out a paid application for 24 hours (soon to be changed to 15 minutes) and get a refund if they uninstall it. There are a few other reasons this might happen:
- A user doesn’t like the application, or it doesn’t provide value for the whole return window
- A user wants to review the application, but not buy it.
- A user can strip the DRM and get a refund (i.e. piracy)
- A website could download the application to learn about it, (i.e. the unofficial android application websites)
- People might hate Google and are trying to raise the charge backs.
Regarding the last point, When you buy an app on the market, Google charges the card and waits for authorization. You can verify this by looking at the declines, I get about one decline a week. If a user uninstalls in 24 hours, then Google will have to do a charge back, which credit card companies hate to do. Maybe its a way for Google’s competitors to cost Google some extra cash. (If you can’t tell this last point is tongue in cheek).
-James
Another Great Android Monetization Blog
I found another great Android Monetization Blog called Independent Web Developer’s Blog. The developer is doing very well, he has quit his day job and is quite open with how he is making his money and how much. The site has a lot of great posts, so check it out!
-James
Importance of inital ranking in Android Market
I have read online that its best to publish your app as soon as possible and do updates as much as possible. Think the mantra “deploy early and often”. Initial I subscribed to this idea, because its super easy to push out updates via Android Market, but I have found its not a good idea, and here is why.
The majority of my sales happen on days I do updates, the reason is Google tends to promote them. I have noticed that apps that have a good ranking (4+ stars) tend to get promoted longer and get much more play. Which makes you a lot more money.
The market doesn’t facilitate feedback to developers very well, so to file a bug report, users leave feed back and a ranking. If you have a bad bug, you might get a bunch of one start ratings, and even if you fix the bug in minutes, the users aren’t going to download your app again, and aren’t going to change their ranking. These poor rankings really hurt long term, especially for new applications that don’t have a lot of marketing behind them.
Lesson learned, TEST TEST TEST, your reputation on Android market counts!
-James



So a bunch of people have been leaving Google/Admob to start a new company called