6 min read

(For more resources related to this topic, see here.)

Android Beam

Devices that have NFC hardware can share data by tapping them together. This could be done with the help of the Android Beam feature. It is similar to Bluetooth, as we get seamless discovery and pairing as in a Bluetooth connection. Devices connect when they are close to each other (not more than a few centimeters). Users can share pictures, videos, contacts, and so on, using the Android Beam feature.

Beaming NdefMessages

In this section, we are going to implement a simple Android Beam application. This application will send an image to another device when two devices are tapped together. There are three methods that are introduced with Android Ice Cream Sandwich that are used in sending NdefMessages. These methods are as follows:

  • setNdefPushMessage() : This method takes an NdefMessage as a parameter and sends it to another device automatically when devices are tapped together. This is commonly used when the message is static and doesn’t change.

  • setNdefPushMessageCallback() : This method is used for creating dynamic NdefMessages. When two devices are tapped together, the createNdefMessage() method is called.

  • setOnNdefPushCompleteCallback() : This method sets a callback which is called when the Android Beam is successful.

We are going to use the second method in our sample application.

Our sample application’s user interface will contain a TextView component for displaying text messages and an ImageView component for displaying the received images sent from another device. The layout XML code will be as follows:

<RelativeLayout android_layout_width="match_parent" android_layout_height="match_parent" > <TextView android_id="@+id/textView" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_centerHorizontal="true" android_layout_centerVertical="true" android_text="" /> <ImageView android_id="@+id/imageView" android_layout_width="wrap_content" android_layout_height="wrap_content" android_layout_below="@+id/textView" android_layout_centerHorizontal="true" android_layout_marginTop="14dp" /> </RelativeLayout>

Now, we are going to implement, step-by-step, the Activity class of the sample application. The code of the Activity class with the onCreate() method is as follows:

public class Chapter9Activity extends Activity implements
CreateNdefMessageCallback
{
NfcAdapter mNfcAdapter;
TextView mInfoText;
ImageView imageView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView = (ImageView) findViewById(R.id.imageView);
mInfoText = (TextView) findViewById(R.id.textView);
// Check for available NFC Adapter
mNfcAdapter =
NfcAdapter.getDefaultAdapter(getApplicationContext());

if (mNfcAdapter == null)
{
mInfoText = (TextView) findViewById(R.id.textView);
mInfoText.setText("NFC is not available on this device.");
finish();
return;
}
// Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(this, this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

As you can see in this code, we can check whether the device provides an NfcAdapter. If it does, we get an instance of NfcAdapter. Then, we call the setNdefPushMessageCallback() method to set the callback using the NfcAdapter instance. We send the Activity class as a callback parameter because the Activity class implements CreateNdefMessageCallback.In order to implement CreateNdefMessageCallback, we should override the createNdefMessage()method as shown in the following code block:

@Override
public NdefMessage createNdefMessage(NfcEvent arg0) {
Bitmap icon =
BitmapFactory.decodeResource(this.getResources(),
R.drawable.ic_launcher);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
icon.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
NdefMessage msg = new NdefMessage(new NdefRecord[] {
createMimeRecord("application/com.chapter9", byteArray)
, NdefRecord.createApplicationRecord("com.chapter9")
});
return msg;
}
public NdefRecord createMimeRecord(String mimeType, byte[]
payload) {
byte[] mimeBytes = mimeType.getBytes(Charset.forName("USASCII"));
NdefRecord mimeRecord = new
NdefRecord(NdefRecord.TNF_MIME_MEDIA,
mimeBytes, new byte[0], payload);
return mimeRecord;
}

As you can see in this code, we get a drawable, convert it to bitmap, and then to a byte array. Then we create an NdefMessage with two NdefRecords. The first record contains the mime type and the byte array. The first record is created by the createMimeRecord() method. The second record contains the Android Application Record ( AAR). The Android Application Record was introduced with Android Ice Cream Sandwich. This record contains the package name of the application and increases the certainty that your application will start when an NFC Tag is scanned. That is, the system firstly tries to match the intent filter and AAR together to start the activity. If they don’t match, the activity that matches the AAR is started.

When the activity is started by an Android Beam event, we need to handle the message that is sent by the Android Beam. We handle this message in the onResume() method of the Activity class as shown in the following code block:

@Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android
Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.
equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
@Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
void processIntent(Intent intent) {
Parcelable[] rawMsgs = intent
.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR

byte[] bytes = msg.getRecords()[0].getPayload();
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0,
bytes.length);
imageView.setImageBitmap(bmp);
}

As you can see in this code, we firstly check whether the intent is ACTION_NDEF_DISCOVERED. This means the Activity class is started due to an Android Beam. If it is started due to an Android Beam, we process the intent with the processIntent() method. We firstly get NdefMessage from the intent. Then we get the first record and convert the byte array in the first record to bitmap using BitmapFactory . Remember that the second record is AAR, we do nothing with it. Finally, we set the bitmap of the ImageView component.

The AndroidManifest.xml file of the application should be as follows:

<manifest
package="com.chapter9"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android_name="android.permission.NFC"/>
<uses-feature android_name="android.hardware.nfc"
android:required="false" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Chapter9Activity"
android:label="@string/title_activity_chapter9" >
<intent-filter>
<action android_name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action
android:name="android.nfc.action.NDEF_DISCOVERED" />
<category
android:name="android.intent.category.DEFAULT" />
<data android_mimeType="application/com.chapter9" />
</intent-filter>

</activity>
</application>
</manifest>

As you can see in this code, we need to set the minimum SDK to API Level 14 or more in the AndroidManifest.xml file because these APIs are available in API Level 14 or more. Furthermore, we need to set the permissions to use NFC. We also set the uses feature in AndroidManifest.xml. The feature is set as not required. This means that our application would be available for devices that don’t have NFC support. Finally, we create an intent filter for android.nfc.action.NDEF_DISCOVERED with mimeType of application/com.chapter9.

When a device sends an image using our sample application, the screen will be as follows:

Summary

In this article, we firstly learned the Android Beam feature of Android. With this feature, devices can send data using the NFC hardware. We implemented a sample Android Beam application and learned how to use Android Beam APIs.

Resources for Article :


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here