Download Practical: Android SMS Telephony

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Practical: Android SMS Telephony
Author: David Sutton
Introduction
In this week’s practical we will create a simple application that would allow us
to run a pub quiz in which communication occurs via SMS messaging. The
first thing we will need to do is find out how to simulate telephony in the
emulator.
Exercise 1: Start Two Emulators
Launch Eclipse then start two emulator instances. Make a note of the ports on
which the emulators are running. You can find this out by looking at the title
bar of the emulator. For instance if the title is “5554:MyEmulator” then the
emulator is running on port 5554.
Exercise 2: Simulate Telephony via Telnet
Open Putty, or whatever command line tool is available on your computer,
and establish a telnet connection to the emulator. If you were connecting from
the terminal on a Mac, and your emulator was running on port 5554 the
command to use would be
telnet localhost 5554
Simulate an SMS message using the sms send command. Simulate a call
using gsm call. Experiment with other ways of using the sms and gsm
commands. You can find more details at
http://developer.android.com/tools/devices/emulator.html
Exercise 3: Simulate Telephony Using the DDMS Perspective
Open the Eclipse DDMS perspective by selecting the menu item
Window->Open Perspective->DDMS
You should see perspective resembling Figure 1 below. Use the right hand
pane to select the emulator with which you wish to operate and the left hand
window to simulate reception of SMS and voice calls. To return to the
“normal” perspective select Window->Open Perspective->Java
Page 1 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Figure 1 The DDMS Perspective
Exercise 4: Simulate Telephony by Calling one Emulator from Another
You can send an SMS message from one emulator instance to another by
using the port number of the second instance as a phone number. You an
also initiate voice calls that way, although you cannot actually speak into the
phone. Experiment with this technique.
Exercise 5: Set up the UI for the Pub Quiz App
Create a new Android application project and edit the layout file for its main
Activity to give you something similar to Figure 2. If you decided on a
LinearLayout then you could use something similar to Table 1 (you would
need to define appropriate Strings in the strings.xml file).
Page 2 of 12
Oxford Brookes University
Practical
Figure 2 UI for the Pub Quiz App
Page 3 of 12
U08971 Advanced Mobile Software Development
Android SMS Telephony
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Table 1 Possible Layout File for Pub Quiz App
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<EditText
android:id="@+id/question_edt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/question_str" />
<EditText
android:id="@+id/answer_edt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/answer_str" />
<Button
android:id="@+id/send_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/send_str" />
<TextView
android:id="@+id/quizzers_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="36dp"
android:text="@string/quizzers_str" />
<ListView
android:id="@+id/quizzers_lst"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
Exercise 6: Create a Class to Represent Quizzers
Create a class to represent Quizzers, as described in the lecture slides. If you
are in a hurry, the code set out in Table 2 would do.
Page 4 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Table 2 A Quizzers Class
public class Quizzer {
private String name;
private String origAddress;
private int nbrAnswered;
private int nbrCorrect;
public Quizzer(String name, String origAddress) {
this.name = name;
this.origAddress = origAddress;
}
public String getName() {
return name;
}
public String getOrigAddress() {
return origAddress;
}
public void incNbrAnswered() {
nbrAnswered++;
}
public void incNbrCorrect() {
nbrCorrect++;
}
public String toString() {
return name + "(" + nbrCorrect + "/" + nbrAnswered + ")";
}
}
Exercise 7: Add an ArrayList and ArrayAdapter for the Quizzers
Add private fields to your main Activity that represent a list of Quizzers, a
reference to the ListView declared in the layout file, and an ArrayAdapter so
that the ArrayList contents can be shown in the ListView.
Then add code to the OnCreate method of the main Activity so that we
instantiate these fields and set up the ArrayAdapter correctly. It might be an
idea to add a dummy Quizzer to the ArrayList so that you can check that the
code works (in the next exercise we will arrange that quizzers can subscribe
by SMS message and get added to the ArrayList that way).
After you have completed this exercise the code should resemble that set out
in Table 3.
Page 5 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Table 3 PubQuiz with ArrayList and ArrayAdapter
public class PubQuiz extends Activity {
private ListView quizzersLst;
private ArrayList<Quizzer> quizzers;
private ArrayAdapter<Quizzer> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pub_quiz);
quizzersLst = (ListView) findViewById(R.id.quizzers_lst);
quizzers = new ArrayList<Quizzer>();
//Test code - we'll delete this later.
quizzers.add(new Quizzer("Dummy","0123456789"));
adapter = new ArrayAdapter<Quizzer>(this,
android.R.layout.simple_list_item_1, quizzers);
quizzersLst.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
… the rest of the code is unchanged
Exercise 8: Add an ArrayList and ArrayAdapter for the Quizzers
In this exercise we will modify the application so that quizzers can sign up by
sending an SMS message of the form
subscribe <team name>
Here’s how we do it.
1. Edit the manifest so that the app has permission to receive SMS
messages. To do this you add the permission
“android.permission.RECEIVE_SMS”. While you are doing this, you
might as well add the permission “android.permission.SEND_SMS”.
We won’t need that last one yet, but we will soon.
2. Create a BroadcastReceiver inside your onCreate method, as
illustrated in the lecture slides. Override the onReceive method of your
BroadcastReceiver so that it calls a private method processMessage,
which we will define later.
3. Within the onCreate method, register your BroadcastReceiver to
receive Intents with the action string
“android.provider.Telephony.SMS_RECEIVED”. You do this by calling
Page 6 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
the registerReceiver method with an appropriate IntentFilter, as shown
in the lecture slides.
4. Within the processMessage method, examine the first word in the
message. If it is the word “subscribe” then interpret the rest of the line
as a team name, create a new Quizzer object, add it to the ArrayList of
quizzers and notify the ArrayAdapter that the content of the ArrayList
has changed. Use a ReentrantLock to ensure that the code which
updates the ArrayList is thread safe.
Once you have done all this, your main Activity code should
5. Run the app and simulate some incoming subscriptions. The UI should
look like that shown in.
Table 4 Main Activity Code for Exercise 8
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.locks.ReentrantLock;
import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsMessage;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class PubQuiz extends Activity {
private static final String SUBSCRIBE_STR = "subscribe";
private static final String SMS_RECEIVED =
"android.provider.Telephony.SMS_RECEIVED";
private ListView quizzersLst;
private ArrayList<Quizzer> quizzers;
private ArrayAdapter<Quizzer> adapter;
private ReentrantLock lock = new ReentrantLock();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pub_quiz);
quizzersLst = (ListView) findViewById(R.id.quizzers_lst);
quizzers = new ArrayList<Quizzer>();
adapter = new ArrayAdapter<Quizzer>(this,
Page 7 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
android.R.layout.simple_list_item_1, quizzers);
quizzersLst.setAdapter(adapter);
BroadcastReceiver myReceiver = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[]) bundle.get("pdus");
for (Object pduObj:pdus) {
byte[] pdu = (byte[]) pduObj;
SmsMessage message = SmsMessage.createFromPdu(pdu);
processMessage(message);
}
}
};
IntentFilter filter = new IntentFilter(SMS_RECEIVED);
registerReceiver(myReceiver, filter);
}
private void processMessage(SmsMessage message) {
String messageText = message.getMessageBody();
Scanner scan = new Scanner(messageText);
if(scan.hasNext()) {
if (scan.next().equalsIgnoreCase(SUBSCRIBE_STR)) {
String name = scan.nextLine().trim();
String origAdress = message.getOriginatingAddress();
Quizzer quizzer = new Quizzer(name, origAdress);
lock.lock();
try {
quizzers.add(quizzer);
adapter.notifyDataSetChanged();
}
finally {
lock.unlock();
}
}
}
}
….
Page 8 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Figure 3 UI After Completing Exercise 8
Exercise 9: Sending Questions
We will now modify our app so that it when we press the “Send” button the
question entered in the text box at the top of the screen is sent to all
subscribed quizzers and the answer is stored so that it can be checked
against their subsequent responses. Here is how we can do it
1. Edit the main Activity so as to add private fields that will represent the
Send button and the two text boxes above it. Also add an ArrayList to
store the answers to the questions. The additional fields should look
something like this:
private EditText questionEdt;
private EditText answerEdt;
private Button sendBtn;
private ArrayList<String> answers = new ArrayList<String>();
2. In the onCreate method of the main activity, add code that will assign
values to the first of the three fields set out above. The code should
look something like this.
questionEdt = (EditText) findViewById(R.id.question_edt);
answerEdt = (EditText) findViewById(R.id.answer_edt);
sendBtn = (Button) findViewById(R.id.send_btn);
3. Add an onClickListener to the “Send” button which calls a private
method sendMessages. We will define sendMessages in the next step.
The code should look something like this.
Page 9 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
sendBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sendQuestion();
}
});
4. Write the sendMessage method. It should send a message to all
subscribed quizzers that consists of a question number followed by the
text of the question set out in the edit box at the top of the screen. So
for example if the second question to be defined was “What is the
capital of Norway” then the subscribed quizzers would be sent a
message that reads “2 What is the capital of Norway”. The
sendMessage method should also add the answer to the answers
ArrayList. Code along the following lines would work
private void sendQuestion() {
SmsManager manager = SmsManager.getDefault();
String question = questionEdt.getEditableText().toString();
String answer = answerEdt.getEditableText().toString();
answers.add(answer);
String sentQuestion = "" + answers.size() + " " + question;
for (Quizzer quizzer : quizzers) {
manager.sendTextMessage(quizzer.getOrigAddress(),
null, sentQuestion, null, null);
}
}
5. Test your code. You will need to do this using two or more emulator
instances.
Exercise 10: Processing Answers
Update the processMessage method so that you can process messages that
consist of an integer followed by an answer to a question. The added code
should find out which quizzer the message came from, increment the number
of questions that quizzer has attempted and, if the answer is correct,
increment the number of correct answers that quizzer has submitted.
So that we can find out which quizzer a message comes from, add the
following method to the main Activity.
private Quizzer getQuizzer(String origAddress) {
for (Quizzer q : quizzers) {
if (q.getOrigAddress().equals(origAddress)) {
return q;
}
}
return null;
}
Page 10 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
In order to process answers add the bolded code below to the
processMessage method. You will notice that there is now some duplicated
code in the method, and you may wish to refactor the code to remove that
duplication.
private void processMessage(SmsMessage message) {
String messageText = message.getMessageBody();
Scanner scan = new Scanner(messageText);
if (scan.hasNextInt()) {
int questionNo = scan.nextInt();
String origAddress = message.getOriginatingAddress();
Quizzer quizzer = getQuizzer(origAddress);
if (quizzer != null && questionNo <= answers.size()) {
lock.lock();
try {
quizzer.incNbrAnswered();
String answer = scan.nextLine().trim();
if (answer.equalsIgnoreCase(
answers.get(questionNo - 1).trim())) {
quizzer.incNbrCorrect();
}
adapter.notifyDataSetChanged();
} finally {
lock.unlock();
}
}
}
if (scan.hasNext()) {
if (scan.next().equalsIgnoreCase(SUBSCRIBE_STR)) {
String origAddress = message.getOriginatingAddress();
String name;
if (scan.hasNextLine()) {
name = scan.nextLine().trim();
} else {
name = origAddress;
}
Quizzer quizzer = new Quizzer(name, origAddress);
lock.lock();
try {
quizzers.add(quizzer);
adapter.notifyDataSetChanged();
} finally {
lock.unlock();
}
}
}
}
Page 11 of 12
Oxford Brookes University
Practical
U08971 Advanced Mobile Software Development
Android SMS Telephony
Further Work
The quiz app is fairly basic, and you could extend it in several ways. Here are
a couple of suggestions:


Modify the app so that you can end a quiz and start another one.
Write an app that could be used by the quizzers as an alternative to
just sending their answers by SMS.
Page 12 of 12