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

Wednesday 5 October 2011

Kindle Fire: Five reasons why we should get one

Amazon is really impressive.
Apparently Kindle Fire pre-orders are in the thousands per day already. I knew they would be successful but really? Thousands ? (I think the number yesterday was 50k/day).

Well, regardless I think it will not be an iPad-killer (gut feeling only) BUT I'm sure (gut sure) Kindle Fire will be a strong competitor to all tablets and pads alike.
Unless Samsung decides to cut violently the prices of their tablets, here's why I would buy a Kindle Fire:

1) Replace my old Kindle
Have a Kindle or any other e-Ink based e-reader but not a tablet? Buy a Kindle Fire. Even with the heroic efforts of makers of e-readers to add additional functionality like web browsing to their devices, we all know it sucks. Sure it can be used to reply that urgent e-mail if you don't have another option. Lots of patience required though. If only I had an Android device..

2) Amazon is behind it
New hardware is often expensive and whether you're a first adopter or not, the thought "what happens if anything goes wrong?" always crosses our mind.
And it's when things break that we all want quality customer service, something most people will agree Amazon is very competent at.

3) Small and light
I want a portable device not a tennis racket. Sure there are plenty of portable-sized tablets but are they really worth? Which takes us to the next reason

4) Very, very very affordable
Almost half its competitors price.
Sure the specs are not mind blowing but I don't think a tablet's camera will make much difference in my life (Fire doesn't have camera if you don't know). If I want descent pictures I'll use a proper digital camera. If not, I'll probably use my phone.

5) It's a Kindle on steroids
OK, not much of a reason my friends say, but if enjoy your kindle, you know what I'm talking about.

Now, have fun with your knew toy and remember: don't pay attention to what I just wrote. Follow your pragmatic inner voice.

Sunday 2 October 2011

Android: Implementing logging in your app


How much logging does one need?
How frequently should I log?
(How to use java.util.logging?)

Programming logging in your Android application
Eternal questions about logging and often they don't have a simple answer. Logs are important, even vital sometimes. I don't write anything that does not have some level of logging.
And when we're talking about logging for mobile apps, things can get more complicated.
Why? Well, logs are resources and resources in a mobile device are scarce (that's how I like to think anyway).

By telling the app to log something we are consuming CPU and generating I/O. So if we are iterating a large list something and logging every single iteration, we're probably using a lot of resources.

Which, again could be fine if the user is not being affected by that (if anything we're consuming power). It's all about how the user perceives the app whilst running.
So how to safely implement logging in your Android app?
Here's a few suggestions:

1) Use only 1 log file (do not rollover)
2) Limit it to a size you think is sufficient to capture enough information throughout the app's life cycle
3) collect error logs (by let's say, sending it to your app's remote server) but ONLY with user's agreement
4) log only what you need but with as much information as you can. You'll have to find the right balance for your app.
5) use the logging facilities existing in the SDK.

OK, less talk more code.
First let's learn how to create a logging mechanism using the java.util.logging package (that's right, not Android specific).

The java logging is very flexibly but basically we need 3 things
- a Logger object;
- a log handler;
- a log formatter;

the most simple combination of this 3 is used in the code snippet below

Logger myAppLog=Logger.getLogger("myAppLog"); FileHandler logHandler=new FileHandler("path_to_log.file",false); SimpleFormatter formatter=new SimpleFormatter(); logHandler.setFormatter(formatter); myAppLog.addHandler(logHandler);

The code uses a file as the output for the log messages and a simple text formatter.  By default the log file is in XML. You can write your own formatters just by extending one of the formatting classes.

We are done with the basic stuff, just call myAppLog.log(...), myAppLog.severe(...) or myAppLog.warning(...) however you think necessary. More information about these methods can be found here.

There are however a few details we must observe. All in this line of code

FileHandler logHandler=new FileHandler("path_to_log.file",false);

First the path to the log file. I recommend using the internal memory. I know, less space but has a faster access time. You can use methods like Context.getDir() to properly set a location for your log file.

The second parameter (boolean true) tells the log handler that we don't want to append, i.e, a new file is created every time.

Another thing is the size and number of log files. Remember that I suggested not rolling logs over and limiting the size? Well, we can't do that with the construction above.
For that we need to change that line to

FileHandler logHandler=new FileHandler("path_to_log.file", 100*1024, 1, false);

here we're telling the handler to limit the file to 100kb (100*1024) and to keep only 1 log file, always creating a new one.

Simple isn't it?
Let people know if you like this ;)


---
Programming tricks and tips for android developers

Sometimes I think Nokia is bipolar or something

And they are my favorite company ever, best hardware in the world.
But, man, they how like to change directions!
Check this out.
Nokia Aims Software At Low-End Phones

Android: Localizing your Android app - Part 2

Part two or our little localization tutorial. For a quick recap, we learned first here how to use string resources to leverage translation in localized applications.
The image below can help refresh your memory.

This solves the problem of translating the content of strings we put in your layout xml files. But what if we need to access those strings programmatically? Thanks to the fantastic Android framework, it couldn't be easier.
Using the Resources class you can access and resource embedded in your app, including strings.
Call Resources.getString(int resourceID) to get the desired string. Resource strings are defined under R.string.*.

For instance, consider the following resource string

<resources>
    <string name="app_title">Test app</string>
</resources> 



calling getString(R.string.app_title) returns "Test app".
You can call getResources() from the the app context to get ta resource object. More information here.

Now, what if I need different images and icons for different countries? Like the exit signs in English and French.
No problem, just name the drawable directory the same way we learned to name the values directory.
For instance, drawable-fr contains icons/images for the French locale, drawable-es for Spanish and you got the idea.
But we all learned that we should use different drawables for different screen densities, that's why we have by default the directories drawable-ldpi, drawable-mdpi and drawable-hdpi. In order to have localizable icon/images taking density under consideration, combine both qualifiers in the name of the directory. Like: drawable-fr-mdpi, which contains drawable resources for French and high density devices. More details about how to combine different qualifiers can be found here.

Ok, enough with translation, let's go talk about something more interesting now.
No, wait! Just a few more things about translating your app:
  1. Keep in mind that translated text will most likely have a different length than the original one. People say sentences in English are shorter than in French. I can't vouch for that :) but design the layout of your app considering text of variable size;
  2. it's a good idea to use resource strings for any text that will be displayed, even if that text does not need translation
  3. translating is not just about "replacing words". Be careful with the cultural significance of sentences and words.

To the other good stuff now: localizing: making your app support other cultural attributes like currency, date/time and number format.
1) The Locale class
All starts with the Locale class, which let's you get information about the current locale and all other available locales installed. To get an instance of the default Locale call the static method Locale.getDefault().
To get an instance of another available locale use one of the public fields in Locale, like Locale.GERMAN (default locale for Germany).
We'll talk more about it in the next sessions but you can find all you need to know about Locale here.

2) Date and Time
If you just want to access date or time formatted for the current locale, the easiest way is to use Calendar. (Actually I recommend calendar for and Date/Time reference. Never instantiate a Date object directly).
To get a Calendar object for a specific locale call the factory method Calendar.getInstance(Locale)
For instance
Calendar.getInstance(Locale.getDefault()) returns the calendar for the default locale
Calendar.getInstance(Locale.FRENCH) returns the calendar for the default French locale. Note that the locale in this case is more about country/culture than language.

Remember when dealing with dates you have to consider the time zone (no, just setting the locale isn't enough). To get a Calendar for a specific locale and time zone call Locale.getInstance(Timezone, Locale).
More information here.

More formatting
Formatting date and time is a very common task and to do it properly - taking the Locale under consideration - it's better to use SimpleDateFormat.This class provides facilities to format date and time anyway you need.
To instantiate a SimpleDateFormat object with a pattern and locale use SimpleDateFormat(String template, Locale locale). Don't forget to set the time zone calling SimpleDateFormat.setTimeZone(). More information here.

3) Currency and number
Formatting currency and numbers in general kind of go together. But not quite :)

First, to get general information about number formatting (like decimal separator, infinity representation, etc), use DecimalFormalSymbols. To get the decimal symbols for a particular locale use the constructor DecimalFormatSymbols(Locale).

The CurrencyClass helps us to get currency symbols for several locales (although you can get the almost the same things from DecimalFormatSymbol). Use CurrencyClass.getInstance(Locale) to get an instance representing currency for the target locale.

Formatting currency and numbers in general is a more elaborate task. The class used to format numbers in general is DecimalFormat.
DecimalFormat will take in consideration the current locale so the code prints

DecimalFormat formatter=new DecimalFormat("##.#");
System.out.println(formatter.format(123.4);

123.4 for a US (English) locale and
123,4 for a French locale.

Consult the documentation to learn more about formatting patterns but on you want to keep in mind is "$", used to format currency.

The problem with DecimalFormat is that it's not possible to get a localized instance of a DecimalFormat object through the class itself (to the moment, AFAIK).To get a localized object we need to use NumberFormat.
A call to NumberFormat.getInstance(Locale) will return an localized version of an object that has NumberFormat as base class. The documentation says it's possible that this object will not be a DecimalFormat object but so far the Android SDK always returns DecimalFormat (since it's the only numeric subclass of NumericFormat).

Calling NumberFormat.getInstance(Locale) will return a NumberFormat object that can be used to format numbers in general. If you don't care about a pattern, just call format(...) and you're done. If you need to specify a custom pattern for formatting, call applyLocalizedPattern if the pattern is already localized or applyPattern if the pattern is not localized (not using localized numeric symbols).

And this concludes our localization chat.
Have fun!


---
Programming tricks and tips for android developers