chApter 8 meSSaGinG and networKinGsuch messages. Android comes with a built-in SMS application that enables you to send and receiveSMS messages. However, in some cases you might want to integrate SMS capabilities into your ownAndroid application. For example, you might want to write an application that automatically sendsa SMS message at regular time intervals. For example, this would be useful if you wanted to trackthe location of your kids — simply give them an Android device that sends out an SMS message con-taining its geographical location every 30 minutes. Now you know if they really went to the libraryafter school! (Of course, that would also mean you would have to pay the fees incurred in sendingall those SMS messages…)This section describes how you can programmatically send and receive SMS messages in your Androidapplications. The good news for Android developers is that you don’t need a real device to test SMSmessaging: The free Android Emulator provides that capability.Sending SmS messages programmaticallyYou will first learn how to send SMS messages programmatically from within your application. Usingthis approach, your application can automatically send an SMS message to a recipient without userintervention. The following Try It Out shows you how.Sending SMS Messagestry it outcodefile SMS.zip available for download at Wrox.com

1 .Using Eclipse, create a new Android project and name it as shown in Figure 8-1.Figure 8-1SMS Messaging

❘

265

2 .Add the following statements in bold to themain.xmlfile:<?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”><Button​​​​android:id=”@+id/btnSendSMS”​​​​android:layout_width=”fill_parent”​​​​android:layout_height=”wrap_content”​​​​android:text=”Send SMS” /></LinearLayout>

3 .In theAndroidManifest.xmlfile, add the following statements in bold:<?xml​version=”1.0”​encoding=”utf-8”?><manifest​xmlns:android=”http://schemas.android.com/apk/res/android”​​​​​​package=”net.learn2develop.SMS”​​​​​​android:versionCode=”1”​​​​​​android:versionName=”1.0”>​​​​<application​android:icon=”@drawable/icon”​android:label=”@string/app_name”>​​​​​​​​<activity​android:name=”.MainActivity”​​​​​​​​​​​​​​​​​​android:label=”@string/app_name”>​​​​​​​​​​​​<intent-filter>​​​​​​​​​​​​​​​​<action​android:name=”android.intent.action.MAIN”​/>​​​​​​​​​​​​​​​​<category​android:name=”android.intent.category.LAUNCHER”​/>​​​​​​​​​​​​</intent-filter>​​​​​​​​</activity>​​​​</application>​​​​<uses-sdk​android:minSdkVersion=”8”​/>​​​​<uses-permission android:name=”android.permission.SEND_SMS”></uses-permission></manifest>

5 .Press F11 to debug the application on the Android Emulator. Using the Android SDK and AVDManager, launch another AVD.

6 .On the first Android Emulator, click the Send SMS button to send an SMS message to the secondemulator. The left side of Figure 8-2 shows the SMS message received by the second emulator (notethe notification bar at the top of the second emulator).Figure 8-2SMS Messaging

❘

267How It WorksAndroid uses a permissions-based policy whereby all the permissions needed by an application must bespecified in theAndroidManifest.xmlfile. This ensures that when the application is installed, the userknows exactly which access permissions it requires.Because sending SMS messages incurs additional costs on the user’s end, indicating the SMS permissionsin theAndroidManifest.xmlfile enables users to decide whether to allow the application to install or not.To send an SMS message programmatically, you use theSmsManagerclass. Unlike other classes, you donot directly instantiate this class; instead, you call thegetDefault()static method to obtain aSmsManager

object. You then send the SMS message using thesendTextMessage()method:​​​​private​void​sendSMS(String​phoneNumber,​String​message)​​​​{​​​​​​​​SmsManager​sms​=​SmsManager.getDefault();​​​​​​​​sms.sendTextMessage(phoneNumber,​null,​message,​null,​null);​​​​}Following are the five arguments to thesendTextMessage()method:destinationAddress➤➤— Phone number of the recipientscAddress➤➤— Service center address; use null for default SMSCtext➤➤— Content of the SMS messagesentIntent➤➤— Pending intent to invoke when the message is sent (discussed in more detail in thenext section)deliveryIntent➤➤— Pending intent to invoke when the message has been delivered (discussed inmore detail in the next section)getting Feedback after Sending the messageIn the previous section, you learned how to programmatically send SMS messages using theSmsManagerclass; but how do you know that the message has been sent correctly? To do so, you cancreate twoPendingIntentobjects to monitor the status of the SMS message-sending process. ThesetwoPendingIntentobjects are passed to the last two arguments of thesendTextMessage()method.The following code snippets show how you can monitor the status of the SMS message being sent:​​​​//---sends​an​SMS​message​to​another​device---​​​​private​void​sendSMS(String​phoneNumber,​String​message)​​​​{​​​​​​​​String SENT = “SMS_SENT”;​​​​​​​​String DELIVERED = “SMS_DELIVERED”;​​​​​​​​PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,​​​​​​​​​​​​new Intent(SENT), 0);​​​​​​​​PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,268

269Here, you created twoPendingIntentobjects. You then registered for twoBroadcastReceivers.These twoBroadcastReceiverslisten for intents that match “SMS_SENT” and “SMS_DELIVERED”(which are fired by the OS when the message has been sent and delivered, respectively). WithineachBroadcastReceiveryou override theonReceive()method and get the current result code.The twoPendingIntentobjects are passed into the last two arguments of thesendTextMessage()

method:​​​​​​​​sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);In this case, whether a message has been sent correctly or failed to be delivered, you will be notifiedof its status via the twoPendingIntentobjects.Sending SmS messages using intentUsing theSmsManagerclass, you can send SMS messages from within your application without the needto involve the built-in Messaging application. However, sometimes it would be easier if you couldsimply invoke the built-in Messaging application and let it do all the work of sending the message.To activate the built-in Messaging application from within your application, you can use an Intentobject together with the MIME type“vnd.android-dir/mms-sms”as shown by the following codesnippet:​​​​/**​Called​when​the​activity​is​first​created.​*/​​​​@Override​​​​public​void​onCreate(Bundle​savedInstanceState)​{​​​​​​​​super.onCreate(savedInstanceState);​​​​​​​​setContentView(R.layout.main);​​​​​​​​btnSendSMS​=​(Button)​findViewById(R.id.btnSendSMS);​​​​​​​​btnSendSMS.setOnClickListener(new​View.OnClickListener()​​​​​​​​{​​​​​​​​​​​​public​void​onClick(View​v)​​​​​​​​​​​​{​​​​​​​​​​​​​​​​//sendSMS(“5556”, “Hello my friends!”);​​​​​​​​​​​​​​​​Intent i = new​​​​​​​​​​​​​​​​​​​​Intent(android.content.Intent.ACTION_VIEW);​​​​​​​​​​​​​​​​i.putExtra(“address”, “5556; 5558; 5560”);​​​​​​​​​​​​​​​​i.putExtra(“sms_body”, “Hello my friends!”);​​​​​​​​​​​​​​​​i.setType(“vnd.android-dir/mms-sms”);​​​​​​​​​​​​​​​​startActivity(i);​​​​​​​​​​​​}​​​​​​​​});​​​​}This will invoke the Messaging application, as shown in Figure 8-3. Note that you can send your SMSto multiple recipients by simply separating each phone number with a semicolon (in theputExtra()

method).270

❘

chApter 8 meSSaGinG and networKinGFigure 8-3NOTE If you use this method to invoke the Messaging application, there is noneed to ask for theSMS_SENDpermission inAndroidManifest.xmlbecause yourapplication is ultimately not the one sending the message.receiving SmS messagesBesides sending SMS messages from your Android applications, you can also receive incoming SMSmessages from within your application by using aBroadcastReceiverobject. This is useful when youwant your application to perform an action when a certain SMS message is received. For example,you might want to track the location of your phone in case it is lost or stolen. In this case, you canwrite an application that automatically listens for SMS messages containing some secret code. Oncethat message is received, you can then send an SMS message containing the location’s coordinatesback to the sender.The following Try It Out shows how to programmatically listen for incoming SMS messages.Receiving SMS Messagestry it out1 .Using the same project created in the previous section, add the following statements in bold to theAndroidManifest.xmlfi le:<?xml​version=”1.0”​encoding=”utf-8”?><manifest​xmlns:android=”http://schemas.android.com/apk/res/android”SMS Messaging

5 .Using the DDMS, send a message to the emulator. Your application should be able to receive themessage and display it using theToastclass (see Figure 8-5).Figure 8-5How It WorksTo listen for incoming SMS messages, you create aBroadcastReceiverclass. TheBroadcastReceiver

class enables your application to receive intents sent by other applications using thesendBroadcast()

method. Essentially, it enables your application to handle events raised by other applications. When anintent is received, theonReceive()method is called; hence, you need to override this.When an incoming SMS message is received, theonReceive()method is fired. The SMS message iscontained in theIntentobject (intent; the second parameter in theonReceive()method) via aBundle

object. The messages are stored in anObjectarray in the PDU format. To extract each message, youuse the staticcreateFromPdu()method from theSmsMessageclass. The SMS message is then displayedusing theToastclass. The phone number of the sender is obtained via thegetOriginatingAddress()

SMS Messaging

❘

273method, so if you need to send an autoreply to the sender, this is the method to obtain the sender’s phonenumber.One interesting characteristic of theBroadcastReceiveris that you can continue to listen for incomingSMS messages even if the application is not running; as long as the application is installed on the device,any incoming SMS messages will be received by the application.Updating an Activity from a BroadcastReceiverThe previous section described how you can use aBroadcastReceiverclass to listen for incomingSMS messages and then use theToastclass to display the received SMS message. Often, you’ll wantto send the SMS message back to the main activity of your application. For example, you might wishto display the message in aTextView. The following Try It Out demonstrates how you can do this.Creating a View-Based Application Projecttry it out

1 .Using the same project created in the previous section, add the following lines in bold to themain.xmlfile:<?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”><Button​​​​​android:id=”@+id/btnSendSMS”​​​​android:layout_width=”fill_parent”​​​​android:layout_height=”wrap_content”​​​​android:text=”Send​SMS”​/><TextView​​​​android:id=”@+id/textView1”​​​​android:layout_width=”wrap_content”​​​​android:layout_height=”wrap_content” /></LinearLayout>

2 .Add the following statements in bold to theSMSReceiver.javafile:package​net.learn2develop.SMS;import​android.content.BroadcastReceiver;import​android.content.Context;import​android.content.Intent;import​android.os.Bundle;import​android.telephony.SmsMessage;import​android.widget.Toast;public​class​SMSReceiver​extends​BroadcastReceiver274

❘

chApter 8 meSSaGinG and networKinG{​​​​@Override​​​​public​void​onReceive(Context​context,​Intent​intent)​​​​{​​​​​​​​//---get​the​SMS​message​passed​in---​​​​​​​​Bundle​bundle​=​intent.getExtras();​​​​​​​​SmsMessage[]​msgs​=​null;​​​​​​​​String​str​=​“”;​​​​​​​​if​(bundle​!=​null)​​​​​​​​{​​​​​​​​​​​​//---retrieve​the​SMS​message​received---​​​​​​​​​​​​Object[]​pdus​=​(Object[])​bundle.get(“pdus”);​​​​​​​​​​​​msgs​=​new​SmsMessage[pdus.length];​​​​​​​​​​​​for​(int​i=0;​i<msgs.length;​i++){​​​​​​​​​​​​​​​​msgs[i]​=​SmsMessage.createFromPdu((byte[])pdus[i]);​​​​​​​​​​​​​​​​str​+=​“SMS​from​“​+​msgs[i].getOriginatingAddress();​​​​​​​​​​​​​​​​str​+=​“​:”;​​​​​​​​​​​​​​​​str​+=​msgs[i].getMessageBody().toString();​​​​​​​​​​​​​​​​str​+=​“\n”;​​​​​​​​​​​​}​​​​​​​​​​​​//---display​the​new​SMS​message---​​​​​​​​​​​​Toast.makeText(context,​str,​Toast.LENGTH_SHORT).show();​​​​​​​​​​​​//---send a broadcast intent to update the SMS received in the activity---​​​​​​​​​​​​Intent broadcastIntent = new Intent();​​​​​​​​​​​​broadcastIntent.setAction(“SMS_RECEIVED_ACTION”);​​​​​​​​​​​​broadcastIntent.putExtra(“sms”, str);​​​​​​​​​​​​context.sendBroadcast(broadcastIntent);​​​​​​​​}​​​​}}

4 .Press F11 to debug the application on the Android Emulator. Using the DDMS, send an SMS messageto the emulator. Figure 8-6 shows theToastclass displaying the message received, and theTextView

showing the message received.Figure 8-6How It WorksYou first added aTextViewto your activity so that it can be used to display the received SMS message.Next, you modified theSMSReceiverclass so that when it receives an SMS message, it will broadcast anotherIntentobject so that any applications listening for this intent can be notified (which we will implement inthe activity next). The SMS received is also sent out via this intent:​​​​​​​​​​​​//---send​a​broadcast​intent​to​update​the​SMS​received​in​the​activity---​​​​​​​​​​​​Intent​broadcastIntent​=​new​Intent();​​​​​​​​​​​​broadcastIntent.setAction(“SMS_RECEIVED_ACTION”);​​​​​​​​​​​​broadcastIntent.putExtra(“sms”,​str);​​​​​​​​​​​​context.sendBroadcast(broadcastIntent);Next, in your activity you created aBroadcastReceiverobject to listen for broadcast intents:​​​​private​BroadcastReceiver​intentReceiver​=​new​BroadcastReceiver()​{​​​​​​​​@Override​​​​​​​​public​void​onReceive(Context​context,​Intent​intent)​{​​​​​​​​​​​​//---display​the​SMS​received​in​the​TextView---​​​​​​​​​​​​TextView​SMSes​=​(TextView)​findViewById(R.id.textView1);​​​​​​​​​​​​​SMSes.setText(intent.getExtras().getString(“sms”));​​​​​​​​}​​​​};SMS Messaging

❘

277When a broadcast intent is received, you update the SMS message in theTextView.You need to create anIntentFilterobject so that you can listen for a particular intent. In this case, theintent is“SMS_RECEIVED_ACTION”:​​​​@Override​​​​public​void​onCreate(Bundle​savedInstanceState)​{​​​​​​​​super.onCreate(savedInstanceState);​​​​​​​​setContentView(R.layout.main);​​​​​​​​//---intent to filter for SMS messages received---​​​​​​​​intentFilter = new IntentFilter();​​​​​​​​intentFilter.addAction(“SMS_RECEIVED_ACTION”);​​​​​​​​//...​​​​}Finally, you register theBroadcastReceiverin the activity’sonResume()event and unregister it in theonPause()event:​​​​@Override​​​​protected​void​onResume()​{​​​​​​​​//---register​the​receiver---​​​​​​​​registerReceiver(intentReceiver,​intentFilter);​​​​​​​​super.onResume();​​​​}​​​​@Override​​​​protected​void​onPause()​{​​​​​​​​//---unregister​the​receiver---​​​​​​​​unregisterReceiver(intentReceiver);​​​​​​​​super.onPause();​​​​}This means that theTextViewwill display the SMS message only when the message is received while theactivity is visible on the screen. If the SMS message is received when the activity is not in the foreground,theTextViewwill not be updated.invoking an Activity from a BroadcastReceiverThe previous example shows how you can pass the SMS message received to be displayed in the activ-ity. However, in many situations your activity may be in the background when the SMS message isreceived. In this case, it would be useful to be able to bring the activity to the foreground when a mes-sage is received. The following Try It Out shows you how.invoking an Activitytry it out

1 .Using the same project created in the previous section, add the following lines in bold to theMainActivity.javafile:​​​​/**​Called​when​the​activity​is​first​created.​*/​​​​@Override278

4 .Press F11 to debug the application on the Android Emulator. When theMainActivityis shown,click the Home button to send the activity to the background.

5 .Use the DDMS to send an SMS message to the emulator again. This time, note that the activity willbe brought to the foreground, displaying the SMS message received.How It WorksIn theMainActivityclass, you first register theBroadcastReceiverin the activity’sonCreate()event,instead of theonResume()event; and instead of unregistering it in theonPause()event, you now unregister280

❘

chApter 8 meSSaGinG and networKinGit in theonDestroy()event. This ensures that even if the activity is in the background, it will still be able tolisten for the broadcast intent.Next, you modify theonReceive()event in theSMSReceiverclass by using an intent to bring the activ-ity to the foreground before broadcasting another intent:​​​​​​​​​​​​//---launch the MainActivity---​​​​​​​​​​​​Intent mainActivityIntent = new Intent(context, MainActivity.class);​​​​​​​​​​​​mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);​​​​​​​​​​​​context.startActivity(mainActivityIntent);​​​​​​​​​​​​//---send​a​broadcast​to​update​the​SMS​received​in​the​activity---​​​​​​​​​​​​Intent​broadcastIntent​=​new​Intent();​​​​​​​​​​​​broadcastIntent.setAction(“SMS_RECEIVED_ACTION”);​​​​​​​​​​​​broadcastIntent.putExtra(“sms”,​str);​​​​​​​​​​​​context.sendBroadcast(broadcastIntent);ThestartActivity()method launches the activity and brings it to the foreground. Note that you needto set theIntent.FLAG_ACTIVITY_NEW_TASKflag because callingstartActivity()from outside of anactivity context requires theFLAG_ACTIVITY_NEW_TASKflag.You also need to set thelaunchModeattribute of the<activity>element in theAndroidManifest.xmlfiletosingleTask:​​​​​​​​<activity​android:name=”.MainActivity”​​​​​​​​​​​​​​​​​​android:label=”@string/app_name”​​​​​​​​​​​​​​​​ android:launchMode=”singleTask” >If you don’t set this, multiple instances of the activity will be launched as your application receives SMSmessages.Note that in this example, when the activity is in the background (such as when you click the Homebutton to show the home screen), the activity is brought to the foreground and itsTextViewis updatedwith the SMS received. However, if the activity was killed (such as when you click the Back button todestroy it), the activity is launched again but theTextViewis not updated.caveats and WarningsWhile the ability to send and receive SMS messages makes Android a very compelling platformfor developing sophisticated applications, this flexibility comes with a price. A seemingly innocentapplication may send SMS messages behind the scene without the user knowing, as demonstrated bya recent case of an SMS-based Trojan Android application (http://forum.vodafone.co.nz/topic/​5719-android-sms-trojan-warning/). Claiming to be a media player, once installed, the applicationsends SMS messages to a premium number, resulting in huge phone bills for the user.While the user needs to explicitly give permission to your application, the request for permission isonly shown at installation time. Figure 8-7 shows the request for permission that appears when youSending e-Mail

❘

281try to install the application (as an APK file; Chapter 11 discusses packaging your Android applica-tions in more detail) on the emulator (same as on a real device). If the user clicks the Install button,he or she is considered to have given permission to allow the application to send and receive SMSmessages. This is dangerous, as after the application is installed it can send and receive SMS mes-sages without ever prompting the user again.Figure 8-7In addition to this, the application can also “sniff” for incoming SMS messages. For example, basedon the techniques you learned from the previous section, you can easily write an application thatchecks for certain keywords in the SMS message. When an SMS message contains the keyword youare looking for, you can then use the Location Manager (discussed in Chapter 9) to obtain your geo-graphical location and then send the coordinates back to the sender of the SMS message. The sendercould then easily track your location. All these tasks can be done easily without the user knowing it!That said, users should try to avoid installing Android applications that come from dubious sources,such as from unknown websites, strangers, etc.Sending e-mAilLike SMS messaging, Android also supports e-mail. The Gmail/Email application on Android enablesyou to configure an e-mail account using POP3 or IMAP. Besides sending and receiving e-mails usingthe Gmail/Email application, you can also send e-mail messages programmatically from within yourAndroid application. The following Try It Out shows you how.282

❘

chApter 8 meSSaGinG and networKinG

Sending e-mail Programmaticallytry it outcodefile Emails.zip available for download at Wrox.com

1 .Using Eclipse, create a new Android project and name itEmails.

2 .Add the following statements in bold to themain.xmlfile:<?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”​​​​><Button​​​​android:id=”@+id/btnSendEmail”​​​​android:layout_width=”fill_parent”​​​​android:layout_height=”wrap_content”​​​​android:text=”Send Email” /></LinearLayout>

4 .Press F11 to test the application on a real Android device. Click the Send Email button and youshould see the Email application launched in your device, as shown in Figure 8-8.Figure 8-8How It WorksIn this example, you are launching the built-in Email application to send an e-mail message. To do so,you use anIntentobject and set the various parameters using thesetData(),putExtra(), andsetType()

chApter 8 meSSaGinG and networKinGnetWorkingThe previous sections covered how to get connected to the outside world using SMS and e-mail. Anotherway to achieve that is to use the HTTP protocol. Using the HTTP protocol, you can perform a wide vari-ety of tasks, such as downloading web pages from a web server, downloading binary data, and so on.The following Try It Out creates an Android project so that you can use the HTTP protocol to con-nect to the Web to download all sorts of data.Creating the Projecttry it outcodefile Networking.zip available for download at Wrox.com

1 .Using Eclipse, create a new Android project and name itNetworking.

2 .Add the following statement in bold to theAndroidManifest.xmlfile:<?xml​version=”1.0”​encoding=”utf-8”?><manifest​xmlns:android=”http://schemas.android.com/apk/res/android”​​​​​​package=”net.learn2develop.Networking”​​​​​​android:versionCode=”1”​​​​​​android:versionName=”1.0”>​​​​<application​android:icon=”@drawable/icon”​android:label=”@string/app_name”>​​​​​​​​<activity​android:name=”.MainActivity”​​​​​​​​​​​​​​​​​​android:label=”@string/app_name”>​​​​​​​​​​​​<intent-filter>​​​​​​​​​​​​​​​​<action​android:name=”android.intent.action.MAIN”​/>​​​​​​​​​​​​​​​​<category​android:name=”android.intent.category.LAUNCHER”​/>​​​​​​​​​​​​</intent-filter>​​​​​​​​</activity>​​​​</application>​​​​<uses-sdk​android:minSdkVersion=”8”​/>​​​​<uses-permission android:name=”android.permission.INTERNET”></uses-permission></manifest>

chApter 8 meSSaGinG and networKinGHow It WorksBecause you are using the HTTP protocol to connect to the Web, your application needs theINTERNET

permission; hence, the first thing you do is add the permission in theAndroidManifest.xmlfile.You then define theOpenHttpConnection()method, which takes a URL string and returns anInputStream

object. Using anInputStreamobject, you can download the data by reading bytes from the stream object.In this method, you made use of theHttpURLConnectionobject to open an HTTP connection with a remoteURL. You set all the various properties of the connection, such as the request method, and so on:​​​​​​​​​​​​HttpURLConnection​httpConn​=​(HttpURLConnection)​conn;​​​​​​​​​​​​httpConn.setAllowUserInteraction(false);​​​​​​​​​​​​httpConn.setInstanceFollowRedirects(true);​​​​​​​​​​​​httpConn.setRequestMethod(“GET”);After you try to establish a connection with the server, you get the HTTP response code from it. If theconnection is established (via the response codeHTTP_OK), then you proceed to get anInputStreamobjectfrom the connection:​​​​​​​​​​​​httpConn.connect();​​​​​​​​​​​​response​=​httpConn.getResponseCode();​​​​​​​​​​​​if​(response​==​HttpURLConnection.HTTP_OK)​{​​​​​​​​​​​​​​​​in​=​httpConn.getInputStream();​​​​​​​​​​​​}Using theInputStreamobject, you can then start to download the data from the server.downloading Binary dataOne of the common tasks you need to perform is downloading binary data from the Web. For example,you may want to download an image from a server so that you can display it in your application. Thefollowing Try It Out shows how this is done.Creating the Projecttry it out

1 .Using the same project created earlier, add the following statements in bold to themain.xmlfile:<?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”​​​​><ImageView​​​​android:id=”@+id/img”​​​​android:layout_width=”wrap_content”​​​​android:layout_height=”wrap_content”​​​​android:layout_gravity=”center” /></LinearLayout>networking

3 .Press F11 to debug the application on the Android Emulator. Figure 8-9 shows the image down-loaded from the Web and then displayed in theImageView.How It WorksTheDownloadImage()method takes the URL of the image to download and then opens the connection tothe server using theOpenHttpConnection()method that you have defined earlier. Using theInputStream

object returned by the connection, thedecodeStream()method from theBitmapFactoryclass is usedto download and decode the data into aBitmapobject. TheDownloadImage()method returns aBitmap

object.288

❘

chApter 8 meSSaGinG and networKinGFigure 8-9The image is then displayed using anImageViewview.reFerring to locAlhoSt From your emulAtorWhen working with the Android Emulator, you may frequently need to access datahosted on the local web server usinglocalhost. For example, your own Web servicesis likely to be hosted on your local computer during development time and you wantto test it on the same development machine you use to write your Android applica-tions. In such cases, you should use the special IP address of 10.0.2.2 (not 127.0.0.1)to refer to the host computer’s loopback interface. From the Android Emulator’s per-spective,localhost(127.0.0.1) refers to its own loopback interface.downloading text FilesBesides downloading binary data, you can also download plain-text fi les. For example, you mightbe writing an RSS Reader application and hence need to download RSS XML feeds for processing.The following Try It Out shows how you can download a plain-text fi le in your application.networking

2 .Press F11 to debug the application on the Android Emulator. Figure 8-10 shows the RSS feeddownloaded and displayed using theToastclass.Figure 8-10networking

❘

291How It WorksTheDownloadText()method takes an URL of the text file to download and then returns the stringof the text file downloaded. It basically opens an HTTP connection to the server and then uses anInputStreamReaderobject to read each character from the stream and save it in aStringobject.Accessing Web ServicesSo far you have seen how to download images and text from the Web. The previous section showedhow to download an RSS feed from a server. Very often, you need to download XML files and parsethe contents (a good example of this is consuming Web services). Therefore, in this section you learnhow to connect to a Web service using the HTTPGETmethod. Once the Web service returns a resultin XML, you will extract the relevant parts and display its content using theToastclass.For this example, the web method you will be using is fromhttp://services.aonaware.com/DictService/DictService.asmx?op=Define. This web method is from a Dictionary Web servicethat returns the definitions of a given word.The web method takes a request in the following format:GET​/DictService/DictService.asmx/Define?word=string​HTTP/1.1Host:​services.aonaware.comHTTP/1.1​200​OKContent-Type:​text/xml;​charset=utf-8Content-Length:​lengthIt returns a response in the following format:<?xml​version=”1.0”​encoding=”utf-8”?><WordDefinition​xmlns=”http://services.aonaware.com/webservices/”>​​<Word>string</Word>​​<Definitions>​​​​<Definition>​​​​​​<Word>string</Word>​​​​​​<Dictionary>​​​​​​​​<Id>string</Id>​​​​​​​​<Name>string</Name>​​​​​​</Dictionary>​​​​​​<WordDefinition>string</WordDefinition>​​​​</Definition>​​​​<Definition>​​​​​​<Word>string</Word>​​​​​​<Dictionary>​​​​​​​​<Id>string</Id>​​​​​​​​<Name>string</Name>​​​​​​</Dictionary>​​​​​​<WordDefinition>string</WordDefinition>​​​​</Definition>​​</Definitions></WordDefinition>292

❘

chApter 8 meSSaGinG and networKinGHence, to obtain the definition of a word, you need to establish an HTTP connection to the webmethod and then parse the XML result that is returned. The following Try It Out shows you how.Consuming Web Servicestry it out

chApter 8 meSSaGinG and networKinG​​​​​​​​​​​​“http://www.appleinsider.com/appleinsider.rss”);​​​​​​​​Toast.makeText(getBaseContext(),​str,​​​​​​​​​​​​​​​​​​​​​​​Toast.LENGTH_SHORT).show();​​​​​​​​//---access a Web service using GET---​​​​​​​​WordDefinition(“Apple”);​​​​}}

2 .Press F11 to debug the application on the Android Emulator. Figure 8-11 shows the result of theWeb service call being parsed and then displayed using theToastclass.Figure 8-11How It WorksTheWordDefinition()method first opens an HTTP connection to the Web service, passing in the wordthat you are interested in:​​​​​​​​​​​​in​=​OpenHttpConnection(“http://services.aonaware.com/DictService/DictService.asmx/Define?word=”​+​word);It then uses theDocumentBuilderFactoryandDocumentBuilderobjects to obtain aDocument(DOM)object from an XML file (which is the XML result returned by the Web service):​​​​​​​​​​​​Document​doc​=​null;​​​​​​​​​​​​DocumentBuilderFactory​dbf​=​​​​​​​​​​​​​​​​​DocumentBuilderFactory.newInstance();​​​​​​​​​​​​DocumentBuilder​db;​​​​​​​​​​​​try​{networking

❘

295​​​​​​​​​​​​​​​​db​=​dbf.newDocumentBuilder();​​​​​​​​​​​​​​​​doc​=​db.parse(in);​​​​​​​​​​​​}​catch​(ParserConfigurationException​e)​{​​​​​​​​​​​​​​​​//​TODO​Auto-generated​catch​block​​​​​​​​​​​​​​​​e.printStackTrace();​​​​​​​​​​​​}​catch​(Exception​e)​{​​​​​​​​​​​​​​​​//​TODO​Auto-generated​catch​block​​​​​​​​​​​​​​​​e.printStackTrace();​​​​​​​​​​​​}​​​​​​​​​​​​doc.getDocumentElement().normalize();Once theDocumentobject is obtained, you will find all the elements with the<Definition>tag:​​​​​​​​​​​​//---retrieve​all​the​<Definition>​nodes---​​​​​​​​​​​​NodeList​itemNodes​=​​​​​​​​​​​​​​​​doc.getElementsByTagName(“Definition”);Figure 8-12 shows the structure of the XML document returned by the Web service.Figure 8-12As the definition of a word is contained within the<WordDefinition>element, you then proceed toextract all the definitions:​​​​​​​​​​​​String​strDefinition​=​“”;​​​​​​​​​​​​for​(int​i​=​0;​i​<​definitionElements.getLength();​i++)​{​​​​​​​​​​​​​​​​Node​itemNode​=​definitionElements.item(i);​​​​​​​​​​​​​​​​if​(itemNode.getNodeType()​==​Node.ELEMENT_NODE)​​​​​​​​​​​​​​​​​{​​​​​​​​​​​​​​​​​​​​//---convert​the​Node​into​an​Element---​​​​​​​​​​​​​​​​​​​​Element​definitionElement​=​(Element)​itemNode;​​​​​​​​​​​​​​​​​​​​//---get​all​the​<WordDefinition>​elements​under​​​​​​​​​​​​​​​​​​​​//​the​<Definition>​element---​​​​​​​​​​​​​​​​​​​​NodeList​wordDefinitionElements​=​​​​​​​​​​​​​​​​​​​​​​​​(definitionElement).getElementsByTagName(​​​​​​​​​​​​​​​​​​​​​​​​“WordDefinition”);​​​​​​​​​​​​​​​​​​​​strDefinition​=​“”;​​​​​​​​​​​​​​​​​​​​for​(int​j​=​0;​j​<​wordDefinitionElements.getLength();​j++)​{​​​​​​​​​​​​​​​​​​​​​​​​//---convert​a​<WordDefinition>​Node​into​an​Element---296

❘

chApter 8 meSSaGinG and networKinG​​​​​​​​​​​​​​​​​​​​​​​​Element​wordDefinitionElement​=​​​​​​​​​​​​​​​​​​​​​​​​​​​​(Element)​wordDefinitionElements.item(j);​​​​​​​​​​​​​​​​​​​​​​​​//---get​all​the​child​nodes​under​the​​​​​​​​​​​​​​​​​​​​​​​​​//​<WordDefinition>​element---​​​​​​​​​​​​​​​​​​​​​​​​NodeList​textNodes​=​​​​​​​​​​​​​​​​​​​​​​​​​​​​((Node)​wordDefinitionElement).getChildNodes();​​​​​​​​​​​​​​​​​​​​​​​​//---get​the​first​node,​which​contains​the​text---​​​​​​​​​​​​​​​​​​​​​​​​strDefinition​+=​​​​​​​​​​​​​​​​​​​​​​​​​​​​((Node)​textNodes.item(0)).getNodeValue()​+​“.​“;​​​​​​​​​​​​​​​​​​​​}​​​​​​​​​​​​​​​​​​​​//---display​the​title---​​​​​​​​​​​​​​​​​​​​Toast.makeText(getBaseContext(),strDefinition,​​​​​​​​​​​​​​​​​​​​​​​​Toast.LENGTH_SHORT).show();​​​​​​​​​​​​​​​​}​​​​​​​​​​​​}​​​​​​​​}​catch​(IOException​e1)​{​​​​​​​​​​​​Toast.makeText(this, e1.getLocalizedMessage(),​​​​​​​​​​​​​​​​Toast.LENGTH_LONG).show();​​​​​​​​​​​​e1.printStackTrace();​​​​​​​​}The above loops through all the<Definition>elements and then for each<Definition>element it looksfor a child element named<WordDefinition>. The text content of the<WordDefinition>element containsthe definition of a word. The Toast class displays each word definition that is retrieved.performing Asynchronous callsSo far, all the connections made in the previous few sections are all synchronous – that is, the con-nection to a server will not return until the data is received. In real life, this presents some problemsdue to network connections being inherently slow. When you connect to a server to download somedata, the user interface of your application remains frozen until a response is obtained. In most cases,this is not acceptable. Hence, you need to ensure that the connection to the server is made in an asyn-chronous fashion.The easiest way to connect to the server asynchronously is to use theAsyncTaskclass available in theAndroid SDK. UsingAsyncTaskenables you to perform background tasks in a separate thread andthen return the result in a UI thread. Using this class enables you to perform background operationswithout needing to handle complex threading issues.Using the previous example of downloading an image from the server and then displaying the imagein anImageView, you could wrap the code in an instance of theAsyncTaskclass, as shown below:public​class​MainActivity​extends​Activity​{​​​​ImageView​img;private class BackgroundTask extends AsyncTask​​​​<String, Void, Bitmap> {​​​​​​​​protected Bitmap doInBackground(String... url) {Summary

❘

297​​​​​​​​​​​​ //---download an image---​​​​​​​​​​​​Bitmap bitmap = DownloadImage(url[0]);​​​​​​​​​​​​return bitmap;​​​​​​​​}​​​​​​​​protected void onPostExecute(Bitmap bitmap) {​​​​​​​​​​​​ImageView img = (ImageView) findViewById(R.id.img);​​​​​​​​​​​​img.setImageBitmap(bitmap);​​​​​​​​}​​​​}​​​​private​InputStream​OpenHttpConnection(String​urlString)​​​​throws​IOException​​​​{​​​​​​​​...​​​​}Basically, you defi ned a class that extends theAsyncTaskclass. In this case, there are two methodswithin theBackgroundTaskclass —doInBackground()andonPostExecute(). You put all the codethat needs to be run asynchronously in thedoInBackground()method. When the task is completed,the result is passed back via theonPostExecute()method. TheonPostExecute()method is executedon the UI thread, hence it is thread safe to update theImageViewwith the bitmap downloaded fromthe server.NOTE You will learn more about theAsyncTaskclass in Chapter 10 which coversdeveloping services in Android.To perform the asynchronous tasks, simply create an instance of theBackgroundTaskclass and callitsexecute()method:​​​​@Override​​​​public​void​onCreate(Bundle​savedInstanceState)​{​​​​​​​​super.onCreate(savedInstanceState);​​​​​​​​setContentView(R.layout.main);​​​​​​​​​​​​new BackgroundTask().execute(​​​​​​​​​​​​​​​​“http://www.streetcar.org/mim/cable/images/cable-01.jpg”);}SummAryThis chapter described the various ways to communicate with the outside world. You fi rst learnedhow to send and receive SMS messages. You then learned how to send e-mail messages from withinyour Android application. Besides SMS and e-mail, another way to communicate with the outsideworld is through the use of the HTTP protocol. Using the HTTP protocol, you can download datafrom a web server. One good application of this is to talk to Web services, whereby you need toparse XML fi les.298

❘

chApter 8 meSSaGinG and networKinGexerciSeS

1 .Name the two ways in which you can send SMS messages in your Android application .

2 .Name the permissions you need to declare in yourAndroidManifest.xmlfile for sending andreceiving SMS messages .

3 .How do you notify an activity from aBroadcastReceiver?

4 .Name the permissions you need to declare in yourAndroidManifest.xmlfile for an HTTPconnection .Answers to Exercises can be found in Appendix C.Summary