Easy Swipe to Refresh in Android

Swipe to Refresh Android

Recently, Google released a new version of the Support Library, which has an interesting component. It’s called SwipeRefreshLayout. With that, it’s become a child’s play to implement a quick Swipe-to-Refresh control for your apps.

A few things first

  1. Available only with android-support-v13. Which means that only apps target SDK level 13 and above can use this.
  2. It can only contain one scrollable direct child such as a ListView or a ScrollView.
That’s all you need to know. Well.. A few things more, basically some xml and java code.
For this example, we use a ListView with some demo data. Once the list view is scrolled, we do some task, wait for sometime, and update the list view’s adapter. Finally, ask the SwipeRefreshLayout to stop the progress indicator, since we are done with refreshing.
The layout file

<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    xmlns:tools=”http://schemas.android.com/tools”
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    tools:context=”${packageName}.${activityClass}” >
    <android.support.v4.widget.SwipeRefreshLayout
        android:id=”@+id/swipeLayout”
        android:layout_width=”match_parent”
        android:layout_height=”match_parent” >
        <ListView
            android:id=”@+id/listView”
            android:layout_width=”match_parent”
            android:layout_height=”match_parent” >
        </ListView>
    </android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>

The UI initialization

private void initializeViews() {
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeLayout);
refreshLayout.setOnRefreshListener(this);
                // The default colors for the progress bar are not so nice.
setColorSchemeForProgressBar();
ListView listView = (ListView) findViewById(R.id.listView);
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1);
adapter.addAll(getDemoData(5));
listView.setAdapter(adapter);
  }

The Refresh Task

       @Override
public void onRefresh() {
Log.i(TAG, “Refresh Requested”);
doRefresh();
}
// Fetch data and update listview’s adapter
private void doRefresh() {
RefreshTask task = new RefreshTask();
task.execute((Void) null);

The Completion Work

private void postRefreshComplete() {
// Stop the refresh animation
refreshLayout.setRefreshing(false);
// Update adapter with new data
adapter.clear();
adapter.addAll(getDemoData(new Random().nextInt(20)));
adapter.notifyDataSetChanged();
   }

And there you go, a simple swipe to refresh usage for your Android apps. You can find the whole source code here

Step Detector and Step Counter Sensors on Android

Android KitKat has added a few more hardware sensors to it’s API list. Step Sensors are one of them, which looks very promising. Although, not a lot of phones yet have these Step Sensors, in the future, this would gradually become a standard I think. Currently, Nexus 5 has them.

Let’s see how we can interact with these sensors. Basically, there are 2 sensors.

  1. Step Counter: This keeps a count of the number of steps that you have taken. The counter is only reset when you re-boot the device, else, for every step you take (or the phone thinks you took, you counts up).
  2. Step Detector: This sensor just detects when you take a step. That’s it. 
The example project shows you how to initialize and setup the SensorManager and respond to events from the Sensors.

// Step Counter
sManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float steps = event.values[0];
textViewStepCounter.setText((int) steps + “”);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}, sManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER),
SensorManager.SENSOR_DELAY_UI);

// Step Detector
sManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
// Time is in nanoseconds, convert to millis
timestamp = event.timestamp / 1000000;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}, sManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR),
SensorManager.SENSOR_DELAY_UI); 

No special permissions are required.

Head over to Github to get the full source code.

Easy Image Chooser Library for Android

In almost all the Android apps that I have worked on, there has been a requirement for choosing an image or taking a snap and using the device’s camera.

Taking a snap, is rather straightforward to implement, but choosing an image from your gallery is sometimes a hard nut to crack. And to implement this correctly, you would always end up writing a lot of code. Assuming that you want to target all OSes, devices, folders etc.

For example, choosing a picture from the Camera folder of your phone is nice and easy. But, if you want to have the user chose an image from one of his picasa web albums, which he has synced on his phone, you will find a dead-end. Well, almost.

For myself, I must have at-least rewritten the same code, multiple number of times. Of course, the platform should help us in achieving this seemingly straightforward feature with as less code as possible. But, right now, it’s not possible.

So, I thought of creating a library which anyone could integrate within one’s own app, without really worrying about the nitty-gritties and the bugs, to implement or add this feature into his app. And there’s more. Most of the time, you would need a scaled down version of the chosen image to show a preview or use it in a listview. This library would give you 3 sizes, as of now.

  1. Original Size
  2. Thumbnail Size
  3. Thumbnail Smaller Size
The sizes are dynamically calculated, based on the original size of the image. It’s pretty rough here, but I am looking forward to improve that part.
This version of the library is pretty basic. But, I would be working on improving this library to add more functionality in the future.
You can find more information about this library here.
By using this library in the current state, you could handle all these cases/special cases with just a few lines of code. An example of this is shown below.
Usage:
1. For choosing an image from gallery

imageChooserManager = new ImageChooserManager(this, ChooserType.REQUEST_PICK_PICTURE);
imageChooserManager.setImageChooserListener(this);
imageChooserManager.choose();

2. For capturing a picture using your camera

imageChooserManager = new ImageChooserManager(this, ChooserType.REQUEST_CAPTURE_PICTURE);
imageChooserManager.setImageChooserListener(this);
imageChooserManager.choose();

3. On Activity result, do this:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK &&
(requestCode == ChooserType.
REQUEST_PICK_PICTURE||
requestCode == ChooserType.
REQUEST_CAPTURE_PICTURE)) {
imageChooserManager.submit(requestCode, data);
}
}

4. Implement the ImageChooserListener interface and override these methods:

@Override
public void onImageChosen(final ChosenImage image) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (image != null) {
// Use the image
// image.getFilePathOriginal();
// image.getFileThumbnail();
// image.getFileThumbnailSmall();
}
}
});
}
@Override
public void onError(final String reason) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// Show error message
}
});
}

That’s all you need to code. And the library takes care of handling all kinds of images, and also generates 2 thumbnails which you could directly use. Let me know if you need to add any new features or if you find a bug. I will try to address those as soon as humanly possible. If you would like to contribute to this project, drop me a mail.

Easier Bug Reporting on 4.2

With the recent release of an updated Jelly Bean version, i.e, 4.2, there have been quite some new things to awe you.

These are two things that could probably make a developers life easier.

  • Take bug report — immediately takes a screen shot and dumps device state information to local file storage, then attaches them to a new outgoing email message.
  • Power menu bug reports — Adds a new option to the device power menu and quick settings to take a bug report (see above).
Remember, while you were testing your app on a bus, or you were away from your desktop/laptop and got a dreaded crash!! You, so eagerly want to have a look at the logcat, or even save the logcat output for later investigation. And most of the times, I don’t have SendLog, which I could fire up, and send me the logs.
With 4.2, it’s already built-in to your phone. Here are a few screenshots, that give you an idea.
Enable this option from the Settings Page.

Hold the power button, to see the option to capture a “Bug Report”
Happy Coding…

Check orientation of images/captures

A lot of times, you would need your app to either pick an image from the gallery or use the device’s camera for capturing a picture that your app could use. I have seen a lot of apps, do it plain wrong. Especially, the orientation of the images.

The default gallery app, reads the orientation properly, and displays the images/thumbnails properly. So, our apps can also handle images in various orientations properly. And the good news is, it’s very easy to handle.

There’s a class called ExifInterface. Most of the times, when you have a similar situation, you would almost never want a full-scaled image to be shown in your app. Most often, we use a thumbnail view for the purpose. The following code would get you a re-sized bitmap, from your original file.

Say for example, we have this path to the actual image file. imagePath


1. Create a Bitmap from the file

Bitmap b = BitmapFactory.decodeFile(imagePath);

2. Resize the Bitmap by scaling it to appropriate level

int width = b.getWidth();
int height = b.getHeight();
int newWidth = 150;
int newHeight = 150;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// Bitmap resizedBitmap = Bitmap.createBitmap(b, 0, 0, width, height, matrix, true);
// resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, out);

3. Handle orientation of the image

ExifInterface exif = new ExifInterface(imagePath);
String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
if (orientation.equals(ExifInterface.ORIENTATION_NORMAL)) {
        // Do nothing. The original image is fine.
} else if (orientation.equals(ExifInterface.ORIENTATION_ROTATE_90+””)) {
        matrix.postRotate(90);
} else if (orientation.equals(ExifInterface.ORIENTATION_ROTATE_180+””)) {
        matrix.postRotate(180);
} else if (orientation.equals(ExifInterface.ORIENTATION_ROTATE_270+””)) {
        matrix.postRotate(270);
}

4. Save the new bitmap 

out = new FileOutputStream(new File(“some output file path”));
Bitmap resizedBitmap = Bitmap.createBitmap(b, 0, 0, width, height, matrix, true);
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, out);

Now your output file would be an image that is resized and handled properly for orientation of the images. You could directly use the “resized” bitmap, but I prefere files.