Wednesday 9 November 2011

Android: Programmatically sending (text) SMS messages

Quick and easy one:

...
  android.telephony.SmsManager shortMessageManager;
  shortMessageManager=SmsManager.getDefault();
  
  String phoneNumber="1110001100";
  String message="test text message";

  shortMessageManager.sendTextMessage(phoneNumber, null, message, null, null);
...

Very simple, the second NULL parameter to sendTextMessage is the address of the service center. Set it to NULL to use the phone's default setting (recommended).

If you want to know if the message was sent successfully or failed, create a pending intent and pass it as the forth argument to sendTextMessage. If you want to be notified when the message is delivered, create another pending intent and pass it as the last argument to the same method.

Good luck!

Thursday 27 October 2011

Android: Getting battery status, health, level

How to get the battery level of your android device?

Let's say you want to create a battery indicator that shows that level and health. The easiest way to do it is installing a broadcast listener for the intent ACTION_BATTERY_CHANGED.

In this example code

public class BatteryChangeBroadcastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
      int batteryLevel=intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
      int maxLevel=intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);  
      int batteryHealth=intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 
                         BatteryManager.BATTERY_HEALTH_UNKNOWN);                
      float batteryPercentage=((float)batteryLevel/(float)maxLevel) * 100;

      //Do something with batteryPercentage and batteryHealth. 
      //batteryPercentage here ranges 0-100
 }
}

onReceive runs every time the battery level changes. More details about what batteryHealth means can be found here.

The caveat here is that this broadcast  receiver can start activities, i.e, it won't work if defined in the manifest file.
You need to manually register and unregister in your app code. This means your app must be running to receive the battery status.
Here's how it would look like using the broadcast listener above.

@Override
public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      mBatteryLevelReceiver=new BatteryChangeBroadcastReceiver();
      registerReceiver(mBatteryLevelReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}


@Override
public void onDestroy(){
       super.onDestroy();
       unregisterReceiver(mBatteryLevelReceiver);
}


Unregistering the receiver after the app finishes is very important. You may even want to register/unregister during pause/resume.

And remember, the app must be running for this to work. I'm sure you can find a neat way of doing that ;)

Have fun

Monday 24 October 2011

Android: Programmatically loading large image/bitmap files

Hello!

The use of imagery in our Apps is practically mandatory. After all, the Man said "make it look great".
Embedding icons and images as resources in an App is trivial and the Resources class makes loading them even easier.

But have you tried lately loading a large image file, let's say like an 8Mp picture? Well if you haven't, try it and you'll see that there's not enough memory for that. And don't ever embed a picture that large as a resource in your app.

So how can we load something that we can't load because there's not enough memory? Very carefully and in steps.

1) Loading bitmaps
The Android Bitmap class possesses several factory methods to create bitmaps but unfortunately it does not solve our problems - and I understand is also not recommended. What is left to us is the super awesome BitmapFactory class.
To create a bitmap object using BitmapFactory just call one of its several decode* factory methods, for instance:

...
Bitmap testBitmap=BitmapFactoryClass.decodeResource(resources, R.drawable.myimage);
// do stuff with testBitmap
// recycle testBitmap
...

this creates a Bitmap from the resource  myimage and stores in testBitmap. We can also load from a file on, let's say, the SD card

...
Bitmap testBitmap=BitmapFactoryClass.decodeFile("/mnt/sdcard/picture.jpg";
// do stuff with testBitmap
// recycle testBitmap
...


if we do that to load a 3000x4000 pixels large picture, it will blowup in our faces. It will probably run out of memory loading an image half this size.

To get around this problem, we need to sample the image during the decoding phase.

2) Sampling a large bitmap
the code snippet below does all the hard work of sampling an image and returning it as a Bitmap object.
A few notes before you use it:

BitmapFactoriy.Options is the secret weapon, more specifically the field inJustDecodeBounds. Setting it to true will tell the framework to not try loading the image, instead just return its size (returned in options.outHeight and options.outWidth). Once we have the dimensions of the image, we can read it scaled down by a factor defined in the field inSampleSize.

The SDK recomends using inSampleSize in powers of 2 so the line

int sampleSize=(int) Math.pow(2, Math.floor(Math.sqrt(factor)));
 
tries to find the best power of 2 close to the sample rate you requested. It's simplistic but works  fine for almost all cases. My suggestion is you find what's best for your app. I recommend sampling the image to a bigger size than what you really want and then use Bitmap.createScaledBitmap to set the image to the size you want.
  
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(fileName, options);
     
long totalImagePixes=options.outHeight*options.outWidth;
totalScreenPixels=__some_maximum_number_of_pixels_supported;
   
if(totalImagePixes>totalScreenPixels){    
 double factor=(float)totalImagePixes/(float)(totalScreenPixels);
 int sampleSize=(int) Math.pow(2, Math.floor(Math.sqrt(factor)));
 options.inJustDecodeBounds=false;
 options.inSampleSize=sampleSize;
 return BitmapFactory.decodeFile(fileName, options);
}
      
return BitmapFactory.decodeFile(fileName); 
 
Also, not this the variable sets the maximum number of pixels (i.e, total bytes used) that we want the sampled image to have.
You can use an approach like that or just find a sample size based on your needs. Again, it's simplistic but works majority of cases.

To recap, all  you need is to set inJustDecodeBounds to true, call decodeFile, set inSampleSize to the desired value (power of 2 preferably) and call decodeFile again.

Have fun!

Tuesday 18 October 2011

Android 4.0 Ice Cream Sandwich is here!

Exciting new SDK!

Some of the amazing new features for developers:

  • Unified UI framework for phones, tablets
  • Social API
  • Calendar API
  • Visual voicemail API
  • Android Beam
  • Low-level streaming multimedia
  • Media effects for transforming images and video
  • New media codecs and containers (support for Matroska!!)
  • Wi-Fi Direct
  • OpenGL ES texture views
  • Hardware-accelerated 2D drawing
  • VPN client API

And a lot more! Checkout the full change log here
Developers, don't forget to read the hightlights and the differences report.

oh, and watch the cool promo video

Tuesday 11 October 2011

Android: Getting the version of your App

(AKA how to get the version of the app from the manifest file)

I wrote previously here how to add logging to your app and one of the things you most certainly want to put in your log is the version of your software.
In fact I got a ton of messages asking how to do that, reason why I'm writing this quick and short post :)

There are two version fields that we should get: version name and version code.
Version name is however you want to call the version of your app and version code is an integer number that basically says "this version is new that the other one".
Both fields are attributes if the same name in the manifest file. You need to set it manually so look for android:versionCode and android:versionName.
Programmatically reading versionName and versionCode.

The attributes we set manually in the manifest file re available in the PackageInfo class.
To get an instance of PackageInfo with the fields for your app we will have to utilize the PackageManager class.
Example:

PackageManager pm=new PackageManager();
PackageInfo info=pm.getPackageInfo(getPackageName(),0);
Log.d("TestApp", "version name "+info.versionName);
Log.d("TestApp","version code "+info.versionCode);


Note that getPackageInfo takes 2 arguments. The first is the name of the package from which we want to get the version.
The method Context.getPackageName() gives us the name of the package for the current app (actually the app in the calling context).
The second are flags indicating what king of extra information we want. In our case 0 is sufficient but if you want to know more, check the documentation.

That's it, see you next time!

---
Programming tricks and tips for android developers