Wednesday, October 19, 2011

Simple ViewPager for Android

You would have seen many applications recently, which make use of the new and awesome ViewPager that allows views to be horizontally scrollable. The new Android Market app also implements a flavor of the ViewPager, although it's a little more complex that what we will see here. This class is not available directly for you to use. Check this blog for some insight. It would required you to download a compatibility library from Google, add it to your project wherever you would like to use it, and go about paging views.

And yes, it's very simple to implement. I have coded up a little sample where it shows you how to use a ViewPager with a simple PagerAdapter. More or less, it works like the ListViews. Although there is not much documentation for this, it's quite easy to set up everything.

Firstly, you would need to add the ViewPager into your layout file.

Listing of main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:text="Page 1" android:id="@+id/textViewHeader"
        android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:gravity="center" android:padding="10dip" android:textStyle="bold"></TextView>
    <android.support.v4.view.ViewPager
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:id="@+id/viewPager" />
</LinearLayout>
In this sample, we are using an extra TextView which would show the current page you are on.

Setting up the ViewPager
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
MyPagerAdapter adapter = new MyPagerAdapter(this);
viewPager.setAdapter(adapter);
This code is almost identical to what we would do for a ListView or Gallery. The only difference is that the adapter here, extends a PagerAdapter instead.

The PagerAdapter

The PagerAdapter has a few methods that you would implement. For this example, I have four different views, one for each page. 2 are ListViews, a TextView and a Button, not in that order. Here are the methods that you would need to implement. Look at the MyPageAdapter class for more.

@Override
public void destroyItem(View view, int arg1, Object object) {
         ((ViewPager) view).removeView((View)object);
}
@Override
public int getCount() {
          return views.size();
}
@Override
public Object instantiateItem(View view, int position) {
           View view = views.get(position);
           ((ViewPager) view).addView(view);
           return view;
}
@Override
public boolean isViewFromObject(View view, Object object) {
           return view == object;
}
 And you are done!!! Sweet.... You can find the whole source code here.

Sunday, September 25, 2011

Automating Builds on Android - Part 2

In the previous post, Automating Builds on Android - Part 1, we saw how to setup our projects to automate the build process. In this post, we will automate the process further to make Ant automatically use the passwords for our keystore and alias, label our builds to whatever name we like and put it in a specific location on your system (from where others can access it).

1. To make Ant use the passwords for our keystore automatically, we will create a separate properties file in our project folder where. Let's name it "passwords.properties". This file would contain two properties as listed below.
key.store.password=sample
key.alias.password=sample
2. We will need to make a small change in our build.xml file to tell Ant to load this property file while building. To do this, we simply add this one line in the build.xml file.
<property file="passwords.properties" />
If you try to run "ant release" command in your terminal, you will notice that Ant doesn't ask you to enter your passwords anymore. It has picked up the passwords from your passwords.properties file.

3. Adding a name and a time-stamp to your builds while making a release build needs a little more effort. We will now create another properties file called "extras.properties". This file would contain two more properties as listed below.
file_name_format=test_build_hello_world
build_location=C:/Builds/HelloWorld
The file_name_format would be used to name your output builds. Sometimes, you would want to name your builds differently based on whether it is a "daily_build" or "weekly_build" or a "release_build". Instead of renaming the output file manually, you could just change this property accordingly just before your type in "ant release", and your builds would automatically be named as you like. The other property, build_location is again a configurable value here, where Ant would put all your builds in the specified location. This could be a shared folder on your system from where anyone else can access it easily.

4. Now comes the lengthy part. To accommodate these changes in our build process, our original build.xml is not enough. We will have to tweak the actual underlying build.xml to make our build process more streamlined. Let's see how to do it. Pick up the build.xml from the sample project and replace the previous build.xml with this one. It will have a whole lot of Ant scripts. You don't have to worry about most of it, except for these lines.

    <!-- Date/Time format for naming the file-->
    <tstamp>
        <format property="time" pattern="dd_MMM" />
    </tstamp>
    <property file="local.properties" />
    <property file="passwords.properties" />
    <property file="extras.properties" />

Notice, that, we are using a time-stamp property which we would be using in our build.xml to version our builds based on the specific format. Our builds will be names as "test_build_hello_world_22_SEP.apk".

The last thing you need to change is this piece of code. You will find it somewhere in the new build.xml.

    <property name="out.release.file.name" value="${file_name_format}_${time}.apk" />
    <property name="out.release.file" location="${build_location}/${out.release.file.name}" />

5. Here, you can see that we have changed the property "out.release.file.name" to a value that we want the output file to be named as. And also, we changed the "out.release.file" to use our configured directory from the extras.properties file.

The final step is to run "ant release" for the last time, and you will see your final release build placed at your desired location.

You can find the sample project here.

Automating Builds on Android - Part 1

Do you find it hard to get a release build of an Android app? Well, you could say that it's not at all difficult. It just takes about 1 minute to get a build, sign it with your release keys and you are done. For a typical moderately big Android app, you could have a QA process where you send out builds for testing or verification to someone else. And you could be sending out the builds multiple times a day. In such situations, it becomes a tad tedious getting release builds out of your eclipse. In this post, we will try to automate this process of preparing the release builds.

Our tool of choice is Ant. Most of you perhaps already know how to do set it up. We will, however, also see how to version or auto-label your builds in next post. In this post, we will go through the basics.

1. To start off with, create a "HelloWorldAnt" Android project.

2. The next step is to prepare our project to use Ant scripts. To do this, fire up your terminal, go to the directory where your project rests and type out this command.
android update project -p .
3. A few files would be added to your project. Among these, the build.xml is the file that Ant would read and package your apk.
Updated local.properties
Added file ./build.xml
Updated file ./proguard.cfg
4. Now try running this command in the terminal. After we setup everything, this is the one single command that we would run every time we need to create a release build.
ant release
5. You will see a long log of what Ant is doing. Look towards the end of the logs and you will notice these lines:
-release-nosign:
     [echo] No key.store and key.alias properties found in build.properties.
     [echo] Please sign /workspace/HelloWorldAnt/bin/HelloWorldAntActivity-unsigned.apk manually
     [echo] and run zipalign from the Android SDK tools.

6. So, till this point, the Ant tool has prepared an unsigned apk which it has kept in the bin folder of your project and it asks you to manually sign this apk with your release keys. Next step is to automate this process.

7. Put your keystore inside your project folder. For this project, sample_keystore is the keystore that we would be using to sign this application. Now, we need to tell Ant to use this keystore to sign our builds with. Here, we will add a few files to our project.

Filename: build.properties

File Listing:
key.store=sample_keystore
key.alias=samplekeystore
 8. At this point, if you try running "ant release" command, it will ask you to enter the password for the keystore and the alias name, and finally, it would put the release and signed builds in your bin folder. 

The next post will talk about customizing the build process to the next level.

Automating Builds on Android - Part 2

You can find the sample project here.

Friday, July 15, 2011

Flip animation in Android

I love animations. Let's see the video first. If you are excited, go peek at the code.



In this example, the main layout contains two ImageView widgets with two different images that are to be animated. The image views actually overlapp each other, at first, but as the animation starts, only one of them is visible at a time, while the other is invisible.

For the animation, we are using a FlipAnimator class, which extends the Animation class. Here is how we need to initialize and setup the animation.
FlipAnimator animator = new FlipAnimator(imageViewOriginal, imageViewFlip,
                        imageViewFlip.getWidth() / 2, imageViewFlip.getHeight() / 2);
 if (imageViewOriginal.getVisibility() == View.GONE) {
                animator.reverse();
 }
 layout.startAnimation(animator);
 There is a small check to tell the animator where to reverse the animation. This is not the perfect way, but you will get an idea. To initialize the animator, you will need to pass the original view and the flipped view and the x and y position of the axes about which it will be flipped.

The animator, internally uses a AccelerateDecelerateInterpolator.
"An interpolator where the rate of change starts and ends slowly but accelerates through the middle."

The main logic of the animation is written inside this method:
protected void applyTransformation(float interpolatedTime, Transformation t)

You can find the whole source code here

References:
http://www.inter-fuser.com/2009/08/android-animations-3d-flip.html 

Monday, July 11, 2011

Understanding Intents and Intent-Filters in Android

Intents or Intent messaging is the Android’s way to pass messages/information to various components of Android. An Intent object contains information that the target component can act upon. Through Intents, your apps can trigger Activities, Services and Broadcast Receivers. The most common use of intents in any application is to directly launch an Activity or Service to perform action on the data being passed with the Intent object.

A sample use of Intent is shown in the following example.
1. To launch an Activity
Intent intent = new Intent(context, TagetActivity.class);
startActivity(intent);
2. To launch a Service
Intent intent = new Intent(context, TargetService.class);
startService(intent);
To pass some data within your intents you need pass them within the Intent object like this.
intent.put(key, value);
This way you can pass basic data-types that are supported by the Intent class. In these examples, we are specifying the component names explicitly, i.e, TagetActivity activity and TargetService service. These intents are examples of Explicit Intents wherein you specify the target component that you want to handle your data.

There would be situations where you would want the user to choose the target component, or to put in another way, the target component is determined dynamically at run-time depending on various factors. For an example, you would like to write a E-Mail app. The basic requirement would be that whenever a user clicks on an e-mail address, your app should be triggered, and it should be designed to capture the e-mail address that was clicked. This is where, Implicit Intents come into picture. Since, the e-mail address link that the user clicks on might not necessarily be a part of your application, you do not have the privilege of launching your Compose Activity on the click event of the link. What would you do in such a case?

What happens when the e-mail link is clicked?
When an email link is clicked, the app would create an Implicit Intent setting it up with the proper data and broadcast it. Something like this:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.put(Intent.EXTRA_EMAIL, {email addresses}];
startActivity(intent);
In the above code snippet, we can see that the Intent here doesn’t specify the component name. However, it specifies an action and the list of email addresses. For this example, we just need to pass a string array with just one email address that the user has clicked on.

How would Android know which activity should be launched (or service for example). In such cases, Android tries to find the best match, i.e, the component that can handle such a payload. In case it finds multiple components, it gives the user a choice to make. For instance, if you have multiple email clients installed and all of them can handle such type of Intents, the user gets a list of all these apps (see image). He can then select one which would launch that particular component (Activity for this example). If it fails to find any components to handle this Intent, an exception will be thrown (ActivityNotFoundException in this case). Here we have two email applications that can handle this intent. The user is given a choice to select one of them when an e-mail link is clicked. Depending on the user’s choice, the corresponding activity will be launched.

How do we write an Activity that can handle such Intents?

We have to specify or rather design one of our activity, the compose screen of our email client that can handle such intents. For that, we need to specify Intent-Filters for this specific activity in the AndroidManifest.xml file.
<activity android:name=".ComposeActivity"
    android:label="@string/app_name">
    <intent-filter android:label="@string/app_name">
         <action android:name="android.intent.action.SEND" />
         <data android:scheme="mailto" />
         <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
The above code itself is self-explanatory. Your activity now can handle intents that are launched with this signature. The action is “android.intent.action.ACTION_SEND” and the data scheme is “mailto”, i.e, any email address. So, in your ComposeActivity, you can retrieve the email address list by querying the intent for the key, EXTRA_EMAIL and you will get the list of email addresses (one in this case). Typically, you will need to populate the Send To address field of your ComposeActivity now.

The intent resolution process tries to find a best match for the intent. Once it finds an Intent and launches the Activity with or without user interruption(in case multiple matches are found), the responsibility of handling the intent now lies with the target component. To finish off the article, here is the way to extract the email address that had been clicked.
Bundle data = getIntent().getExtras();
String[] emailAddresses = data.get(Intent.EXTRA_EMAIL);
The developer docs on Intent, Intent Filters and Intent Resolution mechanism is a nice read to understand the Intent mechanism of Android. You can find other examples of the types of data and schemes that you can design your apps for.