Beruflich Dokumente
Kultur Dokumente
conn = null;
}
}
}
Listing 9–9 shows an activity class that adds a file to the MediaStore. If the add is
successful, the added file is displayed to the user via an intent. What happens behind
the scenes is that the file is inspected by the MediaScanner to determine what type of file
it is and other relevant details about it. Of course, we could have given the MediaScanner
the MIME type as the second argument to scanFile(). If MediaScanner can’t determine
what the type of the file is by the extension, it won’t get added. If the file belongs in the
MediaStore, a database entry is made into the media provider database. The file itself
doesn’t move. But now the media provider knows about this file. If you added an image
file, you can now open the Gallery application and see it. If you added a music file, it will
now show up in the Music application.
If you want to see inside the media provider’s database, open a tools window, launch
adb shell then navigate on the device to
/data/data/com.android.providers.media/databases. There you will find databases,
one of which is internal.db. There could be external database files there also,
corresponding to one or more SD cards. Since you can use multiple SD cards with an
Android phone, there could also be multiple external database files there. You can use
the sqlite3 utility to inspect the tables in these databases. There are tables for audio,
images, and video. See Chapter 3 for more information on using sqlite3.
This concludes our discussion of the media APIs. We hope you’ll agree that playing
and recording media content is simple with Android. Now we’ll move on to the
telephony APIs.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Destination Address:" />
<EditText android:id="@+id/addrEditText"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:phoneNumber=”true” android:text="9045551212" />
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Text Message:" />
</LinearLayout>
</LinearLayout>
import android.app.Activity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
setContentView(R.layout.main);
sendBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
EditText addrTxt =
(EditText)TelephonyDemo.this.findViewById(R.id.addrEditText);
EditText msgTxt =
(EditText)TelephonyDemo.this.findViewById(R.id.msgEditText);
try {
sendSmsMessage(
addrTxt.getText().toString(),msgTxt.getText().toString());
Toast.makeText(TelephonyDemo.this, "SMS Sent",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(TelephonyDemo.this, "Failed to send SMS",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
The interesting part of the sample is the sendSmsMessage() method. The method uses
the SmsManager class’s sendTextMessage() method to send the SMS message. Here’s
the signature of SmsManager.sendTextMessage():
sendTextMessage(String destinationAddress, String smscAddress, String textMsg,
PendingIntent sentIntent, PendingIntent deliveryIntent);
In this example, you populate only the destination address and the text-message
parameters. You can, however, customize the method so it doesn’t use the default SMS
center (the address of the server on the cellular network that will dispatch the SMS
message). You can also implement a customization in which pending intents are called
when the message is sent and a delivery notification has been received.
All in all, sending an SMS message is about as simple as it gets with Android. Realize
that, with the emulator, your SMS messages are not actually sent to their destinations.
You can, however, assume success if the sendTextMessage() method returns without an
exception. As shown in Listing 9–10, you use the Toast class to display a message in
the UI to indicate whether the SMS message was sent successfully.
Sending SMS messages is only half the story. Now we’ll show you how to monitor
incoming SMS messages.
Figure 9–8. Using the Emulator Control UI to send SMS messages to the emulator
The onReceive() method will have the broadcast intent, which will contain the
SmsMessage in the bundle property. You can extract the SmsMessage by calling
intent.getExtras().get("pdus"). This call returns an array of objects defined in
Protocol Description Unit (PDU) mode—an industry-standard way of representing an
SMS message. You can then convert the PDUs to Android SmsMessage objects, as
shown in Listing 9–11. As you can see, you get the PDUs as an object array from the
intent. You then construct an array of SmsMessage objects, equal to the size of the PDU
array. Finally, you iterate over the PDU array, and create SmsMessage objects from the
PDUs by calling SmsMessage.createFromPdu(). What you do after reading the incoming
message must be quick. A broadcast receiver gets high priority in the system, but must
CHAPTER 9: Using the Media Framework and Telephony APIs 359
be done quickly and does not get put into the foreground for the user to see. Therefore,
your options are limited. You should not do any direct UI work. Issuing a Notification is
fine, as is starting a service to continue work there. Once the onReceive() method
completes, the hosting process of the onReceive() method could get killed at any time.
Starting a service is okay but binding to one is not, since that would mean your process
needs to exist for a while, which might not happen.
Now let’s continue our discussion about SMS by looking at how you can work with
various SMS folders.
</LinearLayout>
import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Cursor c = getContentResolver()
.query(SMS_INBOX, null, null, null, null);
startManagingCursor(c);
360 CHAPTER 9: Using the Media Framework and Telephony APIs
setListAdapter(adapter);
}
}
Listing 9–12 opens the SMS inbox and creates a list in which each item contains the
body portion of an SMS message. The layout portion of Listing 9–12 contains a simple
TextView that will hold the body of each message in a list item. To get the list of SMS
messages, you create a URI pointing to the SMS inbox (content://sms/inbox) and then
execute a simple query. You then filter on the body of the SMS message and set the list
adapter of the ListActivity. After executing the code from Listing 9–12, you’ll see a list
of SMS messages in the inbox. Make sure you generate a few SMS messages using the
Emulator Control before running the code on the emulator.
Because you can access the SMS inbox, you would expect to be able to access other
SMS-related folders such as the sent folder or the draft folder. The only difference
between accessing the inbox and accessing the other folders is the URI you specify. For
example, you can access the sent folder by executing a query against
content://sms/sent. Following is the complete list of SMS folders and the URI for each
folder:
All: content://sms/all
Inbox: content://sms/inbox
Sent: content://sms/sent
Draft: content://sms/draft
Outbox: content://sms/outbox
Failed: content://sms/failed
Queued: content://sms/queued
Undelivered: content://sms/undelivered
Conversations: content://sms/conversations
Android combines MMS and SMS and allows you to access content providers for both
at the same time, using an AUTHORITY of mms-sms. Therefore, you can access a URI
such as this:
content://mms-sms/conversations
Sending E-mail
Now that you’ve seen how to send SMS messages in Android, you might assume that
you can access similar APIs to send e-mail. Unfortunately, Android does not provide
APIs for you to send e-mail. The general consensus is that users don’t want an
CHAPTER 9: Using the Media Framework and Telephony APIs 361
application to start sending e-mail on their behalf. Instead, to send e-mail, you have to
go through the registered e-mail application. For example, you could use ACTION_SEND to
launch the e-mail application:
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
emailIntent.setType("message/rfc822");
startActivity(emailIntent);
This code launches the default e-mail application and allows the user to decide whether
to send the e-mail or not. Other “extras” that you can add to an email intent include
EXTRA_CC and EXTRA_BCC.
Now let’s talk about the telephony manager.
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state)
{
case TelephonyManager.CALL_STATE_IDLE:
Log.d(TAG, "call state idle...incoming number is["+
incomingNumber+"]");break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d(TAG, "call state ringing...incoming number is["+
incomingNumber+"]");break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d(TAG, "call state Offhook...incoming number is["+
incomingNumber+"]");break;
default:
Log.d(TAG, "call state ["+state+"]incoming number is["+
incomingNumber+"]");break;
}
}
}
}
When working with the telephony manager, be sure to add the <uses-permission
android:name="android.permission.READ_PHONE_STATE" /> permission to your manifest
file so you can access phone-state information. As shown in Listing 9–13, you get
notified about phone-state changes by implementing a PhoneStateListener and calling
the listen() method of the TelephonyManager. When a phone call arrives, or the phone
state changes, the system will call your PhoneStateListener’s onCallStateChanged()
method with the new state and the incoming phone number. In the case of an incoming
call, you look for the CALL_STATE_RINGING state. You write a debug message to the log
file in this example, but your application could implement custom business logic in its
place. To emulate incoming phone calls, you can use Eclipse’s Emulator Control UI, as
you did with SMS messages (see Figure 9–8).
When dealing with phone-state changes, you might also need to get the subscriber’s
(user’s) phone number. TelephonyManager.getLine1Number() will return that for you.
Summary
In this chapter, we talked about the Android media framework and the telephony APIs.
With respect to media, we showed you how to play audio and video. We also showed
you how to record audio and video, both directly and via intents.
In the second part of the chapter, we talked about telephony services in Android.
Specifically, we showed you how to send text messages and how to monitor incoming
text messages. We also showed you how to access the various SMS folders on the
device. We concluded with a discussion of the TelephonyManager class.
In the next chapter, we are going to turn our attention to 3D graphics by discussing how
to use OpenGL with your Android applications.