Android Developer Phone Sms Course
Android Developer Phone Sms Course
of Contents
Table of Contents
Introduction 1.1
Lesson 1. Phone Calls 1.2
Concepts 1.2.1
1: Phone Calls 1.2.1.1
Practicals 1.2.2
1.1: Making Phone Calls - Part 1 1.2.2.1
1.2: Making Phone Calls - Part 2 1.2.2.2
Lesson 2. SMS Messages 1.3
Concepts 1.3.1
2: SMS Messages 1.3.1.1
Practicals 1.3.2
2.1: Sending and Receiving SMS Messages - Part 1 1.3.2.1
2.2: Sending and Receiving SMS Messages - Part 2 1.3.2.2
2
Introduction
Prerequisites
Completion of the entire Android Developer Fundamentals course, or equivalent
knowledge
Java programming experience
Knowledge of Android programming fundamentals
Course materials
The course materials include the conceptual lessons and practical exercises in this GitBook.
Slide decks are also available for optional use by instructors.
In Android SMS Messages, students learn how to use the SMS features in Android. In the
practical, they create an app that launches an SMS messaging app with a message, and
another app that checks for needed permissions, sends an SMS message, and receives
SMS messages.
3
Introduction
4
1: Phone Calls
1: Phone Calls
Contents:
Android mobile devices with telephone/cellular service are supplied with a Phone app for
making calls, which includes a dialer for dialing a phone number. This chapter describes the
Android telephony features you can use from within your app by launching the Phone app
with an implicit intent. You can add code to your app to:
Dial: Launch the Phone app's dialer with a phone number to dial a call. This is the
preferred technique for apps that don't need to monitor the phone's state.
Call: Request the user's permission if necessary, and make a phone call from within the
app, with the ability to monitor the phone's state. This technique keeps the user within
your app, without having to navigate back to the app. It also enables phone calls if the
Phone app has been disabled in Settings.
Android's Phone app automatically receives incoming phone calls. You can use the
PhoneStateListener class to monitor the phone's ringing state and show the incoming phone
number.
Tip: You can also use a broadcast receiver in your app to detect an incoming call or SMS
message. Broadcast receivers are described in Broadcast Receivers in the Android
Developer Fundamentals Course.
Use an implicit Intent and ACTION_DIAL to launch the Phone app and display the phone
number in the dialer.
This is the simplest way, with no need to request permission from the user (the
Phone app asks for user permission if needed).
5
1: Phone Calls
The user can change the phone number before dialing the call.
The user navigates back to your app using the Back button after the call is
completed.
Use an implicit Intent and ACTION_CALL to make the phone call directly from within your
app.
This action keeps the user within your app, without having to navigate back from
the Phone app.
Your code must ask the user for permission before making the call if the user hasn't
already granted permission. Just as your app needs the user's permission to
access the contacts or use the built-in camera, it needs the user's permission to
directly use the phone.
Your app can monitor the state of the phone call.
The PhoneNumberUtils class provides utility methods for normalizing and formatting phone
number strings. For example, to remove extraneous characters such as dashes and
parentheses, use the normalizeNumber() method, which removes characters other than
digits from a phone number string. For example, the statement below normalizes a phone
number entered into an EditText view named editText :
String normalizedPhoneNumber =
PhoneNumberUtils.normalizeNumber(editText.getText().toString());
6
1: Phone Calls
7
1: Phone Calls
8
1: Phone Calls
The Phone app opens with the number to be dialed. The user can change the number and
initiate the call. The Phone app then makes the call.
<ImageButton
android:id="@+id/phone_icon"
...
android:onClick="dialNumber"/>
In the dialNumber() method, use an implicit intent with the intent action ACTION_DIAL to
pass the phone number to the Phone app as a URI.
Gets the text of the phone number from textView with getText() and uses it with
String.format to include the tel: prefix (for example tel:14155551212 ):
...
String phoneNumber = String.format("tel: %s",
textView.getText().toString());
...
Creates an implicit intent with the intent action ACTION_DIAL , and sets the phone
number as the data for the intent using setData():
…
Intent intent = new Intent(Intent.ACTION_DIAL);
// Set the data for the intent as the phone number.
intent.setData(Uri.parse(phoneNumber));
...
9
1: Phone Calls
Checks if the implicit intent resolves to an app that is installed on the device.
1. If it does, the code sends the intent with startActivity() , and the system
launches the Phone app, as shown in the figure below.
10
1: Phone Calls
11
1: Phone Calls
If there are no apps on the device that can receive the implicit intent, your app will crash
when it calls startActivity() . To first verify that an app exists to receive the intent, call
resolveActivity() on your Intent object with getPackageManager() to get a
PackageManager instance for finding package information. The resolveActivity()
method determines the best action to perform for a given intent. If the result is non-null,
there is at least one app that can handle the intent and it's safe to call startActivity() .
…
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Log.e(TAG, "Can't resolve app for ACTION_DIAL Intent.");
}
...
This example uses a hard-coded phone number, which is a useful technique for providing a
support hotline number, or the selected phone number for a contact. In the next example,
users can enter their own numbers to make calls.
1. Add permissions that enable making a call and reading the phone activity.
2. Check to see if telephony is enabled; if not, disable the phone feature.
3. Check to see if the user continues to grant permission, or request permission if needed.
4. Extend PhoneStateListener, and register the listener using the TelephonyManager
class.
5. Use an implicit intent with ACTION_CALL to make the phone call.
Add the following to your app's AndroidManifest.xml file after the first line (with the package
definition) and before the <application> section:
12
1: Phone Calls
...
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Create a telephony manager.
mTelephonyManager = (TelephonyManager)
getSystemService(TELEPHONY_SERVICE);
...
}
2. Create a method to ensure that mTelephonyManager is not null, and that the SIM state is
ready:
The getSimState() method returns a constant indicating the state of the SIM card.
The above return statement first checks if telephonyManager is not null , and if it is
not, it returns true if the state of the SIM is "ready".
3. Call the above method in the onCreate() method of your activity. If telephony is not
enabled, your code should disable the feature. The example below displays a toast
message, logs a debug message, and disables the call button, effectively disabling the
phone feature:
13
1: Phone Calls
...
if (isTelephonyEnabled()) {
Log.d(TAG, getString(R.string.telephony_enabled));
// Todo: Register the PhoneStateListener.
...
// Todo: Check for permission here.
...
} else {
Toast.makeText(this,
R.string.telephony_not_enabled,
Toast.LENGTH_LONG).show();
Log.d(TAG, getString(R.string.telephony_not_enabled));
// Disable the call button.
disableCallButton();
}
...
Tip: For a complete description of the request permission process, see Requesting
Permissions at Run Time.
Follow these steps to check for and request user permission to make phone calls:
1. At the top of the activity that makes a phone call, and below the activity's class
definition, define a constant variable to hold the request code, and set it to 1 :
Why the integer 1? Each permission request needs three parameters: the context , a
string array of permissions, and an integer requestCode . The requestCode is an integer
attached to the request, and it can be any integer that suits your use case. When a
result returns in the activity, it contains this code and uses it to differentiate multiple
permission results from each other.
14
1: Phone Calls
3. In the activity's onCreate() method, call the method to perform the telephony check:
...
if (isTelephonyEnabled()) {
// Check for phone permission.
checkForPhonePermission();
// Todo: Register the PhoneStateListener.
} else {
...
The code uses checkSelfPermission() to determine whether your app has been
granted a particular permission by the user.
If permission has not been granted, the code uses the requestPermissions() method to
display a standard dialog for the user to grant permission.
The requestPermissions() method needs three parameters: the context, a string array
of permissions, and the predefined integer requestCode .
When your app calls requestPermissions() , the system shows a standard permission
dialog to the user, as shown in the figure below. Your app can't configure or alter the
dialog.
Tip: If you want to provide any information or explanation to the user, you must do that
before you call requestPermissions() , as described in Explain why the app needs
permissions.
15
1: Phone Calls
When the user responds to the request permission dialog, the system invokes your app's
onRequestPermissionsResult() method, passing it the user response. Override that method
to find out whether the permission was granted:
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
if (permissions[0].equalsIgnoreCase
(Manifest.permission.CALL_PHONE)
&& grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
} else {
// Permission denied. Stop the app.
Log.d(TAG, getString(R.string.failure_permission));
Toast.makeText(this,
getString(R.string.failure_permission),
Toast.LENGTH_SHORT).show();
// Disable the call button
disableCallButton();
}
}
}
}
The above code snippet shows a switch statement based on the value of requestCode ,
with one case to check if the permission is the one you defined as
MY_PERMISSIONS_REQUEST_CALL_PHONE .
Tip: It helps to use a switch statement so that you can add more requests to the app.
The user's response to the request dialog is returned in the permissions array (index 0 if
only one permission is requested in the dialog). Compare this to the corresponding grant
result, which is either PERMISSION_GRANTED or PERMISSION_DENIED .
If the user denies a permission request, your app should take appropriate action. For
example, your app might disable the functionality that depends on this permission (such as
the call button) and show a dialog explaining why it could not perform it.
16
1: Phone Calls
onCallStateChanged() method.
In the onCallStateChanged() method, provide actions based on the phone state.
Register the listener using the TelephonyManager class, which provides access to
information about the telephony services on the device.
Implementing a listener
Create a private class in your activity that extends PhoneStateListener:
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// Incoming call is ringing.
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Phone call is active -- off the hook.
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone is idle before and after phone call.
...
break;
default:
// Must be an error. Raise an exception or just log it.
break;
}
}
17
1: Phone Calls
The phone is in the CALL_STATE_IDLE state until a call is started. The phone state changes to
CALL_STATE_OFFHOOK in order to make the connection and stays in the state for the duration
of the call. The phone state returns to the CALL_STATE_IDLE state after the call finishes or if
the call is denied or not completed.
Your app resumes when the state changes back to the CALL_STATE_IDLE state.
Tip: An app running on Android versions prior to KitKat (version 19) doesn't resume when
the phone state returns to CALL_STATE_IDLE from CALL_STATE_OFFHOOK at the end of a call.
The code below sets the flag returningFromOffHook to true when the state is
CALL_STATE_OFFHOOK , so that when the state is back to CALL_STATE_IDLE , you can use the
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// Define a string for the message to use in a toast.
String message = getString(R.string.phone_status);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// Incoming call is ringing
message = message +
getString(R.string.ringing) + incomingNumber;
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Phone call is active -- off the hook
message = message + getString(R.string.offhook);
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
returningFromOffHook = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone is idle before and after phone call.
// If running on version older than 19 (KitKat),
// restart activity when phone call ends.
message = message + getString(R.string.idle);
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
if (returningFromOffHook) {
// No need to do anything if >= version K
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
Log.i(TAG, getString(R.string.restarting_app));
// Restart the app.
18
1: Phone Calls
A good place to do this is in the activity's onCreate() method right after checking for phone
permission, which is after ensuring that telephony is enabled. Follow these steps:
2. In the onCreate() method, add the following code after checking for telephony and
permission:
...
if (isTelephonyEnabled()) {
...
checkForPhonePermission();
// Register the PhoneStateListener to monitor phone activity.
mListener = new MyPhoneCallListener();
telephonyManager.listen(mListener,
PhoneStateListener.LISTEN_CALL_STATE);
} else { ...
3. You must also unregister the listener in the activity's onDestroy() method. This method
is usually implemented to free resources like threads that are associated with an
19
1: Phone Calls
activity, so that a destroyed activity does not leave such things around while the rest of
its application is still running. Override the onDestroy() method by adding the following
code:
@Override
protected void onDestroy() {
super.onDestroy();
if (isTelephonyEnabled()) {
telephonyManager.listen(mListener,
PhoneStateListener.LISTEN_NONE);
}
}
Set the phone number as the data for the intent with setData() .
As in the previous example for passing a number for dialing, you use a string for the phone
number with the tel: prefix.
20
1: Phone Calls
If the implicit intent resolves to an installed app, use the checkForPhonePermission() method
you created previously to check to see if the app still has permission to make the call. You
must check for that permission every time you perform an operation that requires it, because
the user is always free to revoke the permission. Even if the app used the phone a minute
ago, it can't assume it still has that permission a minute later.
1. Launch an emulator directly from the AVD Manager by choosing Tools > Android >
AVD Manager.
2. Double-click a predefined device. Note the number that appears in the emulator's
window title on the far right, as shown in the figure below as #1 (5556). This is the port
number of the emulator instance.
21
1: Phone Calls
is already running.
5. In the phone-calling app, instead of a real phone number, enter the port number (as in
5556), and click the call button. The emulator shows the phone call starting up, as
shown in the figure below.
22
1: Phone Calls
23
1: Phone Calls
The other emulator instance should now be receiving the call, as shown in the figure
below:
24
1: Phone Calls
25
1: Phone Calls
6. Click Answer or Dismiss on the emulator receiving the call,. After you click Answer,
also click the red Hang-up button to end the call.
26
1: Phone Calls
27
1: Phone Calls
Related practical
Making Phone Calls - Part 1
Making Phone Calls - Part 2
Learn more
Android Developer Reference:
Common Intents
TelephonyManager
PhoneStateListener
Requesting Permissions at Run Time
checkSelfPermission
Run Apps on the Android Emulator
Intents and Intent Filters
Intent
Stack Overflow:
How to format a phone number using PhoneNumberUtils?
How to make phone call using intent in android?
Ringing myself using android emulator
Fake Incoming Call Android
Simulating incoming call or sms in Android Studio
Other
User (beginner) tutorial: How to Make Phone Calls with Android
Developer Video: How to Make a Phone Call
28
1.1: Making Phone Calls - Part 1
Android mobile devices with telephone/cellular service are pre-installed with a Phone app for
making calls, which includes a dialer for dialing any phone number. You use an implicit Intent
to launch the Phone app from your app. You have two choices:
Use ACTION_DIAL to launch the Phone app independently from your app with the phone
number displayed in the dialer. The user then makes the call in the Phone app. This is
the preferred action for apps that don't have to monitor the phone's state.
Use ACTION_CALL to launch the Phone app in the context of your app, making the call
directly from your app, and monitoring the phone state. This action keeps the user
within your app, without having to navigate back to the app. Your app must request
permission from the user before making the call if the user hasn't already granted
permission.
29
1.1: Making Phone Calls - Part 1
Create an app that uses an implicit intent to launch the Phone app.
Create another app that makes phone calls from within the app.
Test to see if telephony services are enabled before enabling the app.
Check for calling permission, which can change at any time.
Request permission from the user, if necessary, to make the call.
App overview
You will create two apps:
PhoneCallDial: A basic app that uses an implicit intent to launch the Phone app with a
hard-coded phone number for dialing. The Phone app makes the call. You could use
this technique to provide a one-button dialer to custom support. In this lesson you will
build a layout, shown in the figure below. It includes a TextView with a hard-coded
phone number, and an ImageButton with an icon to launch the Phone app with that
phone number in its dialer.
30
1.1: Making Phone Calls - Part 1
31
1.1: Making Phone Calls - Part 1
Phone Calling Sample: An app that secures permission, uses an implicit intent to
make a phone call from the app, and uses the TelephonyManager class to monitor the
phone's state. You would use this technique if you want to keep the user within your
app, without having to navigate back to the app. In this lesson, you modify the above
layout to use an EditText so that users can enter the phone number. The layout looks
like the figure below:
32
1.1: Making Phone Calls - Part 1
33
1.1: Making Phone Calls - Part 1
i. Select the drawable/ folder in the Project: Android view and choose File > New >
Vector Asset.
ii. Click the Android icon next to "Icon:" to choose an icon. To find a handset icon,
choose Communication in the left column.
iii. Select the icon, click OK, click Next, and then click Finish.
<TextView
android:id="@+id/contact_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:textSize="24sp"
android:text="Jane Doe" />
34
1.1: Making Phone Calls - Part 1
<TextView
android:id="@+id/number_to_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:layout_below="@id/contact_name"
android:text="14155551212" />
You will use the android:id number_to_call to retrieve the phone number.
6. After adding a hard-coded phone number string, extract it into the resource
phone_number .
<ImageButton
android:id="@+id/phone_icon"
android:contentDescription="Make a call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/contact"
android:layout_toRightOf="@id/number_to_call"
android:layout_toEndOf="@id/number_to_call"
android:src="@drawable/ic_call_black_24dp"
android:onClick="dialNumber"/>
Use the vector asset you added previously (for example ic_call_black_24dp for a
phone handset icon) for the android:src attribute. You will use the android:id
@phone_icon to refer to the button for dialing the phone.
8. After adding a hard-coded content description, extract it into the string resource
make_a_call .
9. Click dialNumber in the android:onClick attribute, click the red light bulb that appears,
and then select Create dialNumber(View) in 'MainActivity'. Android Studio
automatically creates the dialNumber() method in MainActivity as public , returning
void , with a View parameter. This method is called when the user taps the
ImageButton.
35
1.1: Making Phone Calls - Part 1
36
1.1: Making Phone Calls - Part 1
37
1.1: Making Phone Calls - Part 1
The following is the complete code for the XML layout in activity_main.xml, including
comments:
<RelativeLayout …
<!-- TextView for a dummy contact name from a contacts database -->
<TextView
android:id="@+id/contact_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:textSize="@dimen/contact_text_size"
android:text="@string/contact" />
2. Inside the dialNumber() method created in the previous section, create a reference to
the number_to_call TextView:
38
1.1: Making Phone Calls - Part 1
3. To create the phone number URI string phoneNumber , get the phone number from
textView and use it with String.format to include the tel: prefix:
...
// Use format with "tel:" and phone number to create mPhoneNum.
String phoneNumber = String.format("tel: %s",
textView.getText().toString());
...
4. Define an implicit intent ( dialIntent ) with the intent action ACTION_DIAL , and set the
phoneNumber as data for the intent:
...
// Create the intent.
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
// Set the data for the intent as the phone number.
dialIntent.setData(Uri.parse(phoneNumber));
...
5. To verify that an app exists to receive the intent, call resolveActivity() on your Intent
object with getPackageManager() to get a PackageManager instance for finding
package information. The resolveActivity() method determines the best action to
perform for a given intent. If the result is non-null, there is at least one app that can
handle the intent and it's safe to call startActivity() .
...
// If package resolves to an app, send intent.
if (dialIntent.resolveActivity(getPackageManager()) != null) {
startActivity(dialIntent);
} else {
Log.e(TAG, "Can't resolve app for ACTION_DIAL Intent.");
}
...
39
1.1: Making Phone Calls - Part 1
1. Click or tap the phone icon. The dialer should appear with the phone number ready to
use, as shown in the figure below:
40
1.1: Making Phone Calls - Part 1
41
1.1: Making Phone Calls - Part 1
2. The phone_number string holds a fixed number (1-415-555-1212). You can change the
number in the Phone app's dialer before calling.
3. Use the Back button to return to the app. You may need to tap or click it two or three
times to navigate backwards from the Phone app's dialer and Favorites list.
Solution code
Android Studio project: PhoneCallDial
In the first step you will add the code to make the call, but the app will work only if telephony
is enabled, and if the app's permission for Phone is set manually in Settings on the device or
emulator.
In subsequent steps you will do away with setting this permission manually by requesting
phone permission from the user if it is not already granted. You will also add a telephony
check to display a message if telephony is not enabled and code to monitor the phone state.
Your app can't make a phone call without the CALL_PHONE permission line in
AndroidManifest.xml. This permission line enables a setting for the app in the Settings
app that gives the user the choice of allowing or disallowing use of the phone. (In the
next task you will add a way for the user to grant that permission from within the app.)
42
1.1: Making Phone Calls - Part 1
<EditText
android:id="@+id/editText_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:inputType="phone"
android:hint="Enter a phone number" />
3. After adding a hard-coded string for the android:hint attribute, extract it into the string
resource enter_phone , and note the following:
You will use the android:id for the EditText view in your code to retrieve the
phone number.
The EditText view uses the android:inputType attribute set to "phone" for a
phone-style numeric keypad.
4. Change the ImageButton as follows:
ii. Add the android:visibility attribute set to visible . You will control the visibility
of this ImageButton from your code.
iii. Change the android:onClick method to callNumber . This will remain highlighted
until you add that method to MainActivity.
<ImageButton
android:id="@+id/phone_icon"
android:contentDescription="@string/make_a_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"
android:layout_toRightOf="@id/editText_main"
android:layout_toEndOf="@id/editText_main"
android:src="@drawable/ic_call_black_24dp"
android:visibility="visible"
android:onClick="callNumber"/>
5. Add the following Button at the end of the layout, before the ending </RelativeLayout>
tag:
43
1.1: Making Phone Calls - Part 1
<Button
android:id="@+id/button_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Retry"
android:layout_below="@id/editText_main"
android:text="Retry"
android:visibility="invisible"/>
</RelativeLayout>
Your app's layout should look like the following figure (the button_retry Button is invisible):
44
1.1: Making Phone Calls - Part 1
45
1.1: Making Phone Calls - Part 1
3. Change the next statement to get the phone number from the EditText view ( editText )
to create the phone number URI string phoneNumber :
4. Before the intent, add code to show a log message and a toast message with the phone
number:
5. Extract "Phone Status: DIALING: " to a string resource ( dial_number ). Replace the
second use of the string in the Toast.makeText() statement to
getString(R.string.dial_number) .
6. Refactor and rename the dialIntent implicit intent to callIntent , and replace
ACTION_DIAL with ACTION_CALL . As a result, the statements should now look like this:
...
// Create the intent.
Intent callIntent = new Intent(Intent.ACTION_CALL);
// Set the data for the intent as the phone number.
callIntent.setData(Uri.parse(phoneNumber));
// If package resolves to an app, send intent.
if (callIntent.resolveActivity(getPackageManager()) != null) {
startActivity(callIntent);
} else {
Log.e(TAG, "Can't resolve app for ACTION_CALL Intent.");
}
...
46
1.1: Making Phone Calls - Part 1
47
1.1: Making Phone Calls - Part 1
48
1.1: Making Phone Calls - Part 1
To set the app's permission on a device or emulator instance, perform the function that a
user would perform: choose Settings > Apps > Phone Calling Sample > Permissions on
the device or emulator, and turn on the Phone permission for the app. Since the user can
turn on or off Phone permission at any time, you have to add a check in your app for this
permission, and request it from the user if required. You will do this in the next task.
If you don't have cellular service on your device, or if telephony is not enabled, you can test
the app using two emulator instances—one emulator instance calls the other one. Follow
these steps:
1. To launch an emulator directly from the AVD Manager, choose Tools > Android > AVD
Manager.
2. Double-click a predefined device. Note the number that appears in the emulator's
window title on the far right, as shown in the figure below as #1 (5556). This is the port
3. Open the Android Studio project for the app, if it isn't already open.
49
1.1: Making Phone Calls - Part 1
4. Run the app, but choose another emulator—not the one that is already running. Android
Studio launches the other emulator.
5. In the app, enter the port number of the other emulator rather than a real phone number.
6. Click the call button in the app. The emulator shows the phone call starting up, as
shown in the figure below.
50
1.1: Making Phone Calls - Part 1
51
1.1: Making Phone Calls - Part 1
The other emulator instance should now be receiving the call, as shown in the figure
below:
52
1.1: Making Phone Calls - Part 1
53
1.1: Making Phone Calls - Part 1
7. Click Answer or Dismiss on the emulator receiving the call. If you click Answer, also
click the red Hang-up button to end the call.
54
1.1: Making Phone Calls - Part 1
55
1.1: Making Phone Calls - Part 1
56
1.2: Making Phone Calls - Part 2
In addition, your app must always get permission to use anything that is not part of the app
itself. In the previous task you added the following permission to the AndroidManifest.xml
file:
This statement enables a permission setting for this app in Settings. The user can allow or
disallow this permission at any time in Settings. You can add code to request permission if
the user has turned off phone permission.
3. Add the following statement to onCreate() method in MainActivity to use the string
constant TELEPHONY_SERVICE with getSystemService() and assign it to
57
1.2: Making Phone Calls - Part 2
mTelephonyManager . This gives you access to some of the telephony features of the
device.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create a telephony manager.
mTelephonyManager = (TelephonyManager)
getSystemService(TELEPHONY_SERVICE);
5. Call the above method in the onCreate() method, right after assigning
mTelephonyManager , in an if statement to take action if telephony is enabled. The
action should be to log a message (to show that telephony is enabled), and include a
comment about checking permission, which you will add in the next step. If telephony is
not enabled, display a toast message, log a message, and disable the call button:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mTelephonyManager = (TelephonyManager)
getSystemService(TELEPHONY_SERVICE);
if (isTelephonyEnabled()) {
Log.d(TAG, "Telephony is enabled");
// ToDo: Check for phone permission.
// ToDo: Register the PhoneStateListener.
} else {
Toast.makeText(this,
"TELEPHONY NOT ENABLED! ",
Toast.LENGTH_LONG).show();
Log.d(TAG, "TELEPHONY NOT ENABLED! ");
// Disable the call button
disableCallButton();
}
}
58
1.2: Making Phone Calls - Part 2
Display a toast to notify the user that the phone feature is disabled.
Find and then set the call button to be invisible so that the user can't make a call.
If telephony is enabled (but the phone permission had not been granted), set the
Retry button to be visible, so that the user can start the activity again and allow
permission.
8. Extract a string resource ( phone_disabled ) for the hard-coded string "Phone calling
disabled" in the toast statement.
9. Create an enableCallButton() method in MainActivity that finds and then sets the call
button to be visible:
10. Create the retryApp() method in MainActivity that will be called when the user clicks
the visible Retry button. Add code to:
Call enableCallButton() to enable the call button.
Create an intent to start (in this case, restart) the activity.
11. Add the android:onClick attribute to the Retry button to call retryApp:
59
1.2: Making Phone Calls - Part 2
<Button
...
android:id="@+id/button_retry"
...
android:onClick="retryApp"/>
Why the integer 1? Each permission request needs three parameters: the context , a
string array of permissions, and an integer requestCode . The requestCode is a code
attached to the request, and can be any integer that suits your use case. When a result
returns back to the activity, it contains this code and uses it to differentiate multiple
permission results from each other.
60
1.2: Making Phone Calls - Part 2
61
1.2: Making Phone Calls - Part 2
5. Extract the hard-coded string "PERMISSION NOT GRANTED!" in the above code to the string
resource permission_not_granted .
6. In the onCreate() method after checking to see if telephony is enabled, add a call to
checkForPhonePermission() :
@Override
protected void onCreate(Bundle savedInstanceState) {
...
if (isTelephonyEnabled()) {
// Check for phone permission.
checkForPhonePermission();
// ToDo: Register the PhoneStateListener.
...
7. When the user responds to the request permission dialog, the system invokes your
app's onRequestPermissionsResult() method, passing it the user response. Override
that method to find out whether the permission was granted:
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
// Check if permission is granted or not for the request.
...
}
62
1.2: Making Phone Calls - Part 2
...
// Check if permission is granted or not for the request.
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
if (permissions[0].equalsIgnoreCase
(Manifest.permission.CALL_PHONE)
&& grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
} else {
// Permission denied.
Log.d(TAG, "Failure to obtain permission!");
Toast.makeText(this,
"Failure to obtain permission!",
Toast.LENGTH_LONG).show();
// Disable the call button
disableCallButton();
}
}
}
9. Extract the hard-coded string "Failure to obtain permission!" in the above code to the
string resource failure_permission , and note the following:
The user's response to the request dialog is returned in the permissions array
(index 0 if only one permission is requested in the dialog). The code snippet
above compares this to the corresponding grant result, which is either
PERMISSION_GRANTED or PERMISSION_DENIED .
If the user denies a permission request, your app should take appropriate action.
For example, your app might disable the functionality that depends on this
permission and show a dialog explaining why it could not perform it. For now, log a
debug message, display a toast to show that permission was not granted, and
disable the call button with disableCallButton() .
i. Choose Settings > Apps > Phone Calling Sample > Permissions on the device
or emulator.
2. Run the app again. You should see the request dialog in the figure in the previous
section.
63
1.2: Making Phone Calls - Part 2
i. Tap Deny to deny permission. The app should display a toast message showing
the failure to gain permission, and the Retry button. The phone icon should
disappear.
ii. Tap Retry, and when the request dialog appears, tap Allow. The phone icon
should reappear. Test the app's ability to make a phone call.
3. Since the user might turn off Phone permission while the app is still running, add the
same permission check method to the callNumber() method—after the intent resolves
to a package, as shown below—to check for permission right before making a call:
4. Run the app. If the user changes the Phone permission for the app while the app is
running, the request dialog appears again for the user to Allow or Deny the permission.
i. Click Allow to test the app's ability to make a phone call. The app should make the
call without a problem.
ii. Jump to the Settings app to turn off Phone permission for the app (the app should
still be running):
i. Choose Settings > Apps > Phone Calling Sample > Permissions on the
device or emulator.
iii. Go back to the app and try to make a call. The request dialog should appear again.
This time, Click Deny to deny permission to make a phone call. The app should
display a toast message showing the failure to gain permission, and the Retry
button. The phone icon should disappear.
64
1.2: Making Phone Calls - Part 2
When the phone call finishes and the phone switches to the idle state, your app's activity
resumes if the app is running on KitKat (version 19) or newer versions. However, if the app
is running on a version of Android older than KitKat (version 19), the Phone app remains
active. You can check the phone state and restart the activity if the state is idle.
65
1.2: Making Phone Calls - Part 2
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// Incoming call is ringing (not used for outgoing call).
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Phone call is active -- off the hook.
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone is idle before and after phone call.
break;
default:
// Must be an error. Raise an exception or just log it.
break;
}
}
3. Just above the switch (state) line, create a String called message to use in a toast
as a prefix for the phone state:
...
// Define a string for the message to use in a toast.
String message = "Phone Status: ";
switch (state) { ...
4. Extract the string "Phone Status: " to the string resource phone_status .
5. For the CALL_STATE_RINGING state, assemble a message for logging and displaying a
toast with the incoming phone number:
...
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// Incoming call is ringing (not used for outgoing call).
message = message + "RINGING, number: " + incomingNumber;
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
break;
...
state:
66
1.2: Making Phone Calls - Part 2
Tip: An app running on Android versions prior to KitKat (version 19) doesn't resume
when the phone state returns to CALL_STATE_IDLE from CALL_STATE_OFFHOOK at the end
of a call. The boolean returningFromOffHook is used as a flag, and set to true when
the state is CALL_STATE_OFFHOOK , so that when the state is back to CALL_STATE_IDLE , the
flag designates an end-of-call in order to restart the app's activity.
8. For the CALL_STATE_OFFHOOK state, assemble a message for logging and displaying a
toast, and set the returningFromOffHook boolean to true .
...
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
// Phone call is active -- off the hook.
message = message + "OFFHOOK";
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
returningFromOffHook = true;
break;
...
67
1.2: Making Phone Calls - Part 2
...
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// Phone is idle before and after phone call.
// If running on version older than 19 (KitKat),
// restart activity when phone call ends.
message = message + "IDLE";
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
if (returningFromOffHook) {
// No need to do anything if >= version KitKat.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
Log.i(TAG, "Restarting app");
// Restart the app.
Intent intent = getPackageManager()
.getLaunchIntentForPackage(
.getPackageName());
intent.addFlags
(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
break;
...
If the app is running on KitKat (version 19) or newer versions, there is no need to restart
the activity after the phone call ends. But if the app is running on a version of Android
older than KitKat (version 19), the code must restart the current activity so that the user
can return to the app after the call ends.
Tip: The code also sets FLAG_ACTIVITY_CLEAR_TOP so that instead of launching a new
instance of the current activity, any other activities on top of the current activity are
closed and an intent is delivered to the (now on top) current activity. This flag helps you
manage a stack of activities in an app.
11. Extract "IDLE" to the string resource idle , and extract "Restarting app" to the
string resource restarting_app .
...
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// Define a string for the message to use in a toast.
String message = getString(R.string.phone_status);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// Incoming call is ringing (not used for outgoing call).
68
1.2: Making Phone Calls - Part 2
message = message +
getString(R.string.ringing) + incomingNumber;
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Phone call is active -- off the hook.
message = message + getString(R.string.offhook);
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
returningFromOffHook = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone is idle before and after phone call.
// If running on version older than 19 (KitKat),
// restart activity when phone call ends.
message = message + getString(R.string.idle);
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
if (returningFromOffHook) {
// No need to do anything if >= version KitKat.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
Log.i(TAG, getString(R.string.restarting_app));
// Restart the app.
Intent intent = getPackageManager()
.getLaunchIntentForPackage(
.getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
break;
default:
message = message + "Phone off";
Toast.makeText(MainActivity.this, message,
Toast.LENGTH_SHORT).show();
Log.i(TAG, message);
break;
}
}
...
69
1.2: Making Phone Calls - Part 2
2. In the onCreate() method, add the following code after checking for telephony and
permission:
...
if (isTelephonyEnabled()) {
...
checkForPhonePermission();
// Register the PhoneStateListener to monitor phone activity.
mListener = new MyPhoneCallListener();
telephonyManager.listen(mListener,
PhoneStateListener.LISTEN_CALL_STATE);
} else { ...
3. You must also unregister the listener in the activity's onDestroy() method. Override the
onDestroy() method by adding the following code:
@Override
protected void onDestroy() {
super.onDestroy();
if (isTelephonyEnabled()) {
telephonyManager.listen(mListener,
PhoneStateListener.LISTEN_NONE);
}
}
70
1.2: Making Phone Calls - Part 2
3. The other emulator instance or device should now be receiving the call, as shown in the
figure below. Click Answer or Dismiss on the device or emulator receiving the call.
71
1.2: Making Phone Calls - Part 2
72
1.2: Making Phone Calls - Part 2
4. If you click Answer, be sure to also click the red Hang-up button to finish the call, as
shown in the figure below.
73
1.2: Making Phone Calls - Part 2
74
1.2: Making Phone Calls - Part 2
After you hang up, the app should reappear with a toast message showing that the phone is
now in the idle state, as shown in the figure below.
75
1.2: Making Phone Calls - Part 2
76
1.2: Making Phone Calls - Part 2
Solution code
Android Studio project: PhoneCallingSample
Coding challenge
Note: All coding challenges are optional and are not prerequisites for later lessons.
Challenge:
2. Add an invisible TextView to the PhoneCallingSample app. This TextView should appear
below the invisible Retry button, but only when the phone is ringing (indicating an
incoming call), and it should show the phone number of the caller.
If you have both emulators open as described previously, install the app on both emulators.
You can then test an incoming call by using the app on one emulator to call the other
emulator.
Tip: You can also emulate receiving a call by clicking the … (More) icon at the bottom of the
emulator's toolbar on the right side. Click Phone in the left column to see the extended
phone controls, and click Call Device to call the emulator.
Summary
To send an intent to the Phone app with a phone number, your app needs to prepare a
URI for the phone number as a string prefixed by "tel:" (for example tel:14155551212).
To dial a phone number, create an implicit intent with ACTION_DIAL , and set the phone
number URI as the data for the intent with setData() :
77
1.2: Making Phone Calls - Part 2
To make a phone call, create an implicit intent with ACTION_CALL , and set the phone
number URI as the data for the intent with setData() :
telephony features.
Use checkSelfPermission() to determine whether your app has been granted a
particular permission by the user. If permission has not been granted, use the
requestPermissions() method to display a standard dialog for the user to grant
permission.
To monitor the phone state with PhoneStateListener, register a listener object using the
TelephonyManager class.
For phone monitoring permission, add the following to the AndroidManifest.xml file:
To monitor phone states, create a private class that extends PhoneStateListener, and
override the onCallStateChanged() method of PhoneStateListener to take different
actions based on the phone state: CALL_STATE_RINGING , CALL_STATE_OFFHOOK , or
CALL_STATE_IDLE .
Related concept
Phone Calls
Learn more
Android developer documentation:
Common Intents
TelephonyManager
78
1.2: Making Phone Calls - Part 2
PhoneStateListener
Requesting Permissions at Run Time
checkSelfPermission
Run Apps on the Android Emulator
Intents and Intent Filters
Intent
Stack Overflow:
How to format a phone number using PhoneNumberUtils?
How to make phone call using intent in android?
Ringing myself using android emulator
Fake Incoming Call Android
Simulating incoming call or sms in Android Studio
Other:
User (beginner) tutorial: How to Make Phone Calls with Android
Developer Video: How to Make a Phone Call
79
2: SMS Messages
2: SMS Messages
Contents:
Android devices can send and receive messages to or from any other phone that supports
Short Message Service (SMS). Android offers the Messenger app that can send and receive
SMS messages. A host of third-party apps for sending and receiving SMS messages are
also available in Google Play.
This chapter describes how to use SMS in your app. You can add code to your app to:
Launch an SMS messaging app from your app to handle all SMS communication.
Send an SMS message from within your app.
Receive SMS messages in your app.
Note: The SMS protocol was primarily designed for user-to-user communication and is not
well-suited for apps that want to transfer data. You should not use SMS to send data
messages from a web server to your app on a user device. SMS is neither encrypted nor
strongly authenticated on either the network or the device.
However, your app doesn't need permission to pass a phone number to an installed SMS
app, such as Messenger, for sending the message. The Messenger app itself is governed by
user permission.
Use an implicit Intent to launch a messaging app such as Messenger, with the
ACTION_SENDTO action.
80
2: SMS Messages
This is the simplest choice for sending messages. The user can add a picture or
other attachment in the messaging app, if the messaging app supports adding
attachments.
Your app doesn't need code to request permission from the user.
If the user has multiple SMS messaging apps installed on the Android phone, the
App chooser will appear with a list of these apps, and the user can choose which
one to use. (Android smartphones will have at least one, such as Messenger.)
The user can change the message in the messaging app before sending it.
The user navigates back to your app using the Back button.
Send the SMS message using the sendTextMessage() method or other methods of the
SmsManager class.
This is a good choice for sending messages from your app without having to use
another installed app.
Your code must ask the user for permission before sending the message if the user
hasn't already granted permission.
The user stays in your app during and after sending the message.
You can manage SMS operations such as dividing a message into fragments,
sending a multipart message, get carrier-dependent configuration values, and so
on.
To receive SMS messages, the best practice is to use the onReceive() method of the
BroadcastReceiver class. The Android framework sends out system broadcasts of events
such as receiving an SMS message, containing intents that are meant to be received using
a BroadcastReceiver. Your app receives SMS messages by listening for the
SMS_RECEIVED_ACTION broadcast.
Most smartphones and mobile phones support what is known as "PDU mode" for sending
and receiving SMS. PDU (protocol data unit) contains not only the SMS message, but also
metadata about the SMS message, such as text encoding, the sender, SMS service center
address, and much more. To access this metadata, SMS apps almost always use PDUs to
encode the contents of a SMS message. The sendTextMessage() and
sendMultimediaMessage() methods of the SmsManager class encode the contents for you.
When receiving a PDU, you can create an SmsMessage object from the raw PDU using
createFromPdu().
81
2: SMS Messages
a support message center, or provide an EditText field in the layout to enable the user to
enter a phone number.
Tip: For details about using methods in the PhoneNumberUtils class to format a phone
number string, see the related concept Phone Calls.
Use a button (such as an ImageButton) that the user can tap to pass the phone number to
the SMS app. For example, an app that enables a user make a phone call and/or send a
message to the phone number might offer a simple layout with a phone icon button for
calling, and a messaging icon button for sending a message, as shown in the figure below.
82
2: SMS Messages
83
2: SMS Messages
To call a method such as smsSendMessage() that would launch a messaging app with a
phone number, you can add the android:onClick attribute to the button for sending a
message:
<ImageButton
...
android:onClick="smsSendMessage"/>
In the smsSendMessage() method, you would convert the phone number to a string prefixed
by "smsto:" (as in smsto:14155551212 ). Use an implicit intent with ACTION_SENDTO to pass the
phone number to the SMS app, and set the phone number and message for the intent with
setData() and putExtra .
Tip: The "smsto:" prefix with ACTION_SENDTO ensures that your intent is handled only by a
text messaging app (and not by other email or social apps).
If the user has several SMS messaging apps, the user can choose which one to open. The
SMS app opens with the supplied phone number and message, enabling the user to tap a
button to send the message, or change the number and message before sending. The SMS
app then sends the message.
The following code demonstrates how to perform an implicit intent to send a message:
84
2: SMS Messages
The method gets the phone number from the number_to_call TextView, and
concatenates it with the smsto: prefix (as in smsto:14155551212 ) before assigning it to
smsNumber . It also gets the message entered into the EditText view.
and putExtra .
The putExtra() method needs two strings: the key identifying the type of data
( "sms_body" ) and the data itself, which is the text of the message ( sms ). For more
information about common intents and the putExtra() method, see Common Intents:
Text Messaging.
You need to supply a check to see if the implicit intent resolves to a package (an app),
and if it does, you need to start the smsIntent activity. If it doesn't, display a log
message about the failure.
Tip: For a complete description of the request permission process, see Requesting
Permissions at Run Time.
Add the SEND_SMS permission to the AndroidManifest.xml file after the first line (with the
package definition) and before the <application> section:
85
2: SMS Messages
Because the user can turn permissions on or off for each app, your app must check whether
it still has permission every time it does something that requires permission (such as
sending an SMS message). If the user has turned SMS permission off for the app, your app
can display a dialog to request permission.
1. At the top of the activity that sends an SMS message, and below the activity's class
definition, define a constant variable to hold the request code, and set it to an integer:
Why the integer 1? Each permission request needs three parameters: the context , a
string array of permissions, and an integer requestCode . The requestCode is the
integer attached to the request. When a result returns in the activity, it contains this
code and uses it to differentiate multiple permission results from each other.
2. In the activity that makes a phone call, create a method that uses the
checkSelfPermission() method to determine whether your app has been granted the
permission:
The code uses checkSelfPermission() to determine whether your app has been
granted a particular permission by the user. If permission has not been granted, the
code uses the requestPermissions() method to display a standard dialog for the user to
grant permission.
86
2: SMS Messages
Use your checkForSmsPermission() method to check for permission at the following times:
When your app calls requestPermissions() , the system shows a standard dialog to the user,
as shown in the figure below.
87
2: SMS Messages
88
2: SMS Messages
When the user responds to the request permission dialog by tapping Deny or Allow, the
system invokes the onRequestPermissionsResult() method, passing it the user response.
Your app has to override that method to find out whether the permission was granted.
The following code demonstrates how you can use a switch statement in your
implementation of onRequestPermissionsResult() based on the value of requestCode . The
user's response to the request dialog is returned in the permissions array (index 0 if only
one permission is requested in the dialog). This is compared to the corresponding grant
result, which is either PERMISSION_GRANTED or PERMISSION_DENIED .
If the user denies a permission request, your app should disable the functionality that
depends on this permission and show a dialog explaining why it could not perform it. The
code below logs a debug message, displays a toast to show that permission was not
granted, and disables the message icon used as a button.
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_SEND_SMS: {
if (permissions[0].equalsIgnoreCase(Manifest.permission.SEND_SMS)
&& grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
} else {
// Permission denied.
Log.d(TAG, getString(R.string.failure_permission));
Toast.makeText(MainActivity.this,
getString(R.string.failure_permission),
Toast.LENGTH_SHORT).show();
// Disable the message button.
disableSmsButton();
}
}
}
}
destinationAddress : The string for the phone number to receive the message.
scAddress : A string for the service center address, or null to use the current default
SMSC. A Short Message Service Center (SMSC) is a network element in the mobile
telephone network. The mobile network operator usually presets the correct service
89
2: SMS Messages
center number in the default profile of settings stored in the device's SIM card.
Tip: You can find the default SMSC in an Android smartphone's hidden menu. Open the
Phone app and dial ##4636## to open the testing menu. Tap Phone information, and
scroll to the bottom. The SMSC number should appear blank. Tap Refresh to see the
number.
...
// Set the service center address if needed, otherwise null.
String scAddress = null;
// Set pending intents to broadcast
// when message sent and when delivered, or set to null.
PendingIntent sentIntent = null, deliveryIntent = null;
...
...
// Use SmsManager.
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage
(destinationAddress, scAddress, smsMessage,
sentIntent, deliveryIntent);
...
The following code snippet shows a sample onClick handler for sending a message:
90
2: SMS Messages
1. Add the broadcast receiver by choosing File > New > Other > Broadcast Receiver.
The <receiver...</receiver> tags are automatically added to the AndroidManifest.xml
file.
2. Register the receiver by adding an intent filter within the <receiver...</receiver> tags
to specify the type of broadcast intent you want to receive.
3. Implement the onReceive() method.
91
2: SMS Messages
<receiver
android:name="com.example.android.phonecallingsms.MySmsReceiver"
android:enabled="true"
android:exported="true">
</receiver>
<receiver
android:name="com.example.android.smsmessaging.MySmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
The following shows the first part of the onReceive() method, which does the following:
92
2: SMS Messages
@Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
// Retrieve the SMS message received.
...
}
The onReceive() method then retrieves from the bundle one or more pieces of data in the
PDU:
...
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus != null) {
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
...
Use createFromPdu(byte[] pdu, String format) to fill the msgs array for Android version 6.0
(Marshmallow) and newer versions. For earlier versions of Android, use the deprecated
signature createFromPdu(byte[] pdu):
For Android version 6.0 (Marshmallow) and newer versions, use the following, which
includes format :
The onReceive() method then builds the strMessage to show in a toast message. It gets
the originating address using the getOriginatingAddress() method, and the message body
using the getMessageBody() method.
93
2: SMS Messages
...
// Build the message to show.
strMessage += "SMS from " + msgs[i].getOriginatingAddress();
strMessage += " :" + msgs[i].getMessageBody() + "\n";
...
The following shows the complete onReceive() method for SMS messages:
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus != null) {
// Check the Android version.
boolean isVersionM =
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
// Check Android version and use appropriate createFromPdu.
if (isVersionM) {
// If Android version M or newer:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
} else {
// If Android version L or older:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
// Build the message to show.
strMessage += "SMS from " + msgs[i].getOriginatingAddress();
strMessage += " :" + msgs[i].getMessageBody() + "\n";
// Log and display the SMS message.
Log.d(TAG, "onReceive: " + strMessage);
Toast.makeText(context, strMessage, Toast.LENGTH_LONG).show();
}
}
}
Tip: To build an SMS app with more features, see Telephony in the Android Developer's
Documentation, and read the blog post Getting Your SMS Apps Ready for KitKat.
94
2: SMS Messages
You can emulate receiving a call or an SMS text message by clicking the … (More) icon at
the bottom of the emulator's toolbar on the right side, as shown in the figure below.
95
2: SMS Messages
The extended controls for the emulator appear. Click Phone in the left column to see the
extended phone controls:
Enter a message (or use the default "marshmallows" message) and click Send Message to
send an SMS message to your emulator.
The emulator essentially sends itself the message, and responds as if receiving a call or
receiving an SMS message.
Related practical
Sending and Receiving SMS Messages - Part 1
Sending and Receiving SMS Messages - Part 2
Learn more
Android Developer Reference:
Intent
Common Intents: Text Messaging
96
2: SMS Messages
97
2.1: Sending and Receiving SMS Messages - Part 1
Android smartphones can send and receive messages to or from any other phone that
supports Short Message Service (SMS). You have two choices for sending SMS messages:
Use an implicit Intent to launch a messaging app with the ACTION_SENDTO intent
action.
This is the simplest choice for sending messages. The user can add a picture or
other attachment in the messaging app, if the messaging app supports adding
attachments.
Your app doesn't need code to request permission from the user.
If the user has multiple SMS messaging apps installed on the Android phone, the
App chooser will appear with a list of these apps, and the user can choose which
one to use. (Android smartphones will have at least one, such as Messenger.)
The user can change the message in the messaging app before sending it.
The user navigates back to your app using the Back button.
Send the SMS message using the sendTextMessage() method or other methods of the
SmsManager class.
This is a good choice for sending messages from your app without having to use
another installed app.
Your app must ask the user for permission before sending the SMS message, if the
user hasn't already granted permission.
The user stays in your app during and after sending the message.
You can manage SMS operations such as dividing a message into fragments,
sending a multipart message, get carrier-dependent configuration values, and so
on.
To receive SMS messages, use the onReceive() method of the BroadcastReceiver class.
98
2.1: Sending and Receiving SMS Messages - Part 1
Launch an SMS messaging app from your app with a phone number and message.
Send an SMS message from within an app.
Check for the SMS permission, and request permission if necessary.
Receive SMS events using a broadcast receiver.
Extract an SMS message from an SMS event.
App overview
You will create two new apps based on apps you created previously for the lesson about
making phone calls:
PhoneMessaging: Rename and refactor the PhoneCallDial app from the previous
chapter, and add code to enable a user to not only dial a hard-coded phone number but
also send an SMS message to the phone number. It uses an implicit intent using
ACTION_SENDTO and the phone number to launch a messaging app to send the
message.
99
2.1: Sending and Receiving SMS Messages - Part 1
As shown in the figure below, the PhoneCallDial app already has TextEdit views for the
contact name and the hard-coded phone number, and an ImageButton for making a
phone call. You will copy the app, rename it to PhoneMessaging, and modify the layout
to include an EditText for entering the message, and another ImageButton with an icon
that the user can tap to send the message.
100
2.1: Sending and Receiving SMS Messages - Part 1
101
2.1: Sending and Receiving SMS Messages - Part 1
SMS Messaging: Change the PhoneCallingSample app from the previous chapter to
enable a user to enter a phone number, enter an SMS message, and send the message
from within the app. It checks for permission and then uses the SmsManager class to
send the message.
As shown in the figure below, the PhoneCallingSample app already has an EditText
view for entering the phone number and an ImageButton for making a phone call. You
will copy the app, rename it to SmsMessaging, and modify the layout to include
another EditText for entering the message, and change the ImageButton to an icon that
the user can tap to send the message.
102
2.1: Sending and Receiving SMS Messages - Part 1
103
2.1: Sending and Receiving SMS Messages - Part 1
The user can tap the messaging icon in your app to send the message. In the messaging
app launched by the intent, the user can tap to send the message, or change the message
or the phone number before sending the message. After sending the message, the user can
navigate back to your app using the Back button.
i. Select drawable in the Project: Android view and choose File > New > Vector
Asset.
ii. Click the Android icon next to "Icon:" to choose an icon. To find a messaging icon,
choose Communication in the left column.
iii. Select the icon, click OK, click Next, and then click Finish.
3. Add the following EditText to the existing layout after the phone_icon ImageButton:
...
<ImageButton
android:id="@+id/phone_icon"
... />
<EditText
android:id="@+id/sms_message"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_below="@id/number_to_call"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:hint="Enter message here"
android:inputType="textMultiLine"/>
104
2.1: Sending and Receiving SMS Messages - Part 1
You will use the android:id sms_message to retrieve the message in your code. You
can use @dimen/activity_horizontal_margin and @dimen/activity_vertical_margin for
the EditText margins because they are already defined in the dimens.xml file. The
EditText view uses the android:inputType attribute set to "textMultiLine" for entering
multiple lines of text.
4. After adding hard-coded strings and dimensions, extract them into resources:
android:layout_width="@dimen/edittext_width" : The width of the EditText message
(200dp).
android:hint="@string/enter_message_here" : The hint for the EditText ("Enter
message here").
5. Add the following ImageButton to the layout after the above EditText:
<ImageButton
android:id="@+id/message_icon"
android:contentDescription="Send a message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_toRightOf="@id/sms_message"
android:layout_toEndOf="@id/sms_message"
android:layout_below="@id/phone_icon"
android:src="@drawable/ic_message_black_24dp"
android:onClick="smsSendMessage"/>
You will use the android:id message_icon to refer to the ImageButton for launching
the messaging app. Use the vector asset you added previously (such as
ic_message_black_24dp for a messaging icon) for the ImageButton.
6. After adding the hard-coded string for the android:contentDescription attribute, extract
it into the resource send_a_message .
7. Click smsSendMessage in the android:onClick attribute, click the red light bulb that
appears, and then select Create smsSendMessage(View) in 'MainActivity'. Android
Studio automatically creates the smsSendMessage() method in MainActivity as public ,
returning void , with a View parameter. This method is called when the user taps the
message_icon ImageButton.
105
2.1: Sending and Receiving SMS Messages - Part 1
Your app's layout should now look like the following figure:
106
2.1: Sending and Receiving SMS Messages - Part 1
107
2.1: Sending and Receiving SMS Messages - Part 1
...
TextView textView = (TextView) findViewById(R.id.number_to_call);
// Use format with "smsto:" and phone number to create smsNumber.
String smsNumber = String.format("smsto: %s",
textView.getText().toString());
...
2. Get the string of the message entered into the EditText view:
...
// Find the sms_message view.
EditText smsEditText = (EditText) findViewById(R.id.sms_message);
// Get the text of the SMS message.
String sms = smsEditText.getText().toString();
...
3. Create an implicit intent ( smsIntent ) with the intent action ACTION_SENDTO , and set the
phone number and text message as intent data and extended data, using setData()
and putExtra :
...
// Create the intent.
Intent smsIntent = new Intent(Intent.ACTION_SENDTO);
// Set the data for the intent as the phone number.
smsIntent.setData(Uri.parse(smsNumber));
// Add the message (sms) with the key ("sms_body").
smsIntent.putExtra("sms_body", sms);
...
The putExtra() method needs two strings: the key identifying the type of data
( "sms_body" ) and the data itself, which is the text of the message ( sms ). For more
information about common intents and the putExtra() method, see Common Intents:
Text Messaging.
4. Add a check to see if the implicit intent resolves to a package (a messaging app). If it
does, send the intent with startActivity() , and the system launches the app. If it does
not, log an error.
108
2.1: Sending and Receiving SMS Messages - Part 1
...
// If package resolves (target app installed), send intent.
if (smsIntent.resolveActivity(getPackageManager()) != null) {
startActivity(smsIntent);
} else {
Log.e(TAG, "Can't resolve app for ACTION_SENDTO Intent");
}
...
109
2.1: Sending and Receiving SMS Messages - Part 1
3. Use the Back button to return to the PhoneMessaging app. You may need to tap or
click it more than once to leave the SMS messaging app.
Solution code
Android Studio project: PhoneMessaging
In the first step you will add the code to send the message, but the app will work only if you
first turn on SMS permission manually for the app in Settings on your device or emulator.
In subsequent steps you will do away with setting this permission manually by requesting
SMS permission from the app's user if it is not already set.
110
2.1: Sending and Receiving SMS Messages - Part 1
Sending an SMS message is permission-protected. Your app can't use SMS without the
SEND_SMS permission line in AndroidManifest.xml. This permission line enables a
setting for the app in the Settings app that gives the user the choice of allowing or
disallowing use of SMS. (In the next task you will add a way for the user to grant that
permission from within the app.)
4. Add a messaging icon as you did in the previous task, and remove the phone icon from
the drawable folder.
5. Open activity_main.xml and edit the EditText view and replace the
android:layout_margin attribute with the following:
...
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
...
...
<EditText
android:id="@+id/sms_message"
android:layout_width="@dimen/edittext_width"
android:layout_height="wrap_content"
android:layout_below="@id/editText_main"
android:layout_margin="@dimen/activity_horizontal_margin"
android:hint="Enter message here"
android:inputType="textMultiLine"/>
You will use the android:id attribute to sms_message to identify it as the EditText for
the message. The EditText view uses the android:inputType attribute set to
"textMultiLine" for entering multiple lines of text.
111
2.1: Sending and Receiving SMS Messages - Part 1
7. After adding the hard-coded string "Enter message here" for the android:hint attribute,
extract it into the text resource "enter_message_here" .
8. Change the android:layout_below attribute for the button_retry Button to refer to the
sms_message EditText view. The Button should appear below the SMS message in the
android:layout_below="@id/sms_message"
The button_retry Button is set to invisible. It appears only if the app detected that
telephony is not enabled, or if the user previously denied phone permission when the
app requested it.
9. Replace the phone_icon ImageButton from the existing layout with the following:
<ImageButton
android:id="@+id/message_icon"
android:contentDescription="Send a message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_toRightOf="@id/sms_message"
android:layout_toEndOf="@id/sms_message"
android:layout_below="@id/editText_main"
android:src="@drawable/ic_message_black_24dp"
android:visibility="visible"
android:onClick="smsSendMessage"/>
You will use the android:id message_icon in your code to refer to the ImageButton for
sending the message. Use the vector asset you added previously (such as
ic_message_black_24dp for a messaging icon) for the ImageButton. Make sure you
include the android:visibility attribute set to "visible" . You will control the visibility
of this ImageButton from your code.
10. After adding a hard-coded string for the android:contentDescription attribute, extract it
to the send_a_message string resource.
11. Click smsSendMessage in the android:onClick attribute, click the red light bulb that
appears, and then select Create smsSendMessage(View) in 'MainActivity'. Android
Studio automatically creates the smsSendMessage() method in MainActivity as public ,
112
2.1: Sending and Receiving SMS Messages - Part 1
returning void , with a View parameter. This method is called when the user taps the
message_icon ImageButton.
Your app's layout should look like the following figure (the button_retry Button is invisible):
113
2.1: Sending and Receiving SMS Messages - Part 1
114
2.1: Sending and Receiving SMS Messages - Part 1
view:
...
// Set the service center address if needed, otherwise null.
String scAddress = null;
// Set pending intents to broadcast
// when message sent and when delivered, or set to null.
PendingIntent sentIntent = null, deliveryIntent = null;
...
115
2.1: Sending and Receiving SMS Messages - Part 1
...
// Use SmsManager.
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage
(destinationAddress, scAddress, smsMessage,
sentIntent, deliveryIntent);
...
If you run the app now, on either a device or an emulator, the app may crash depending on
whether the device or emulator has been previously set to allow the app to use SMS. In
some versions of Android, this permission is turned on by default. In other versions, this
permission is turned off by default.
To set the app's permission on a device or emulator instance, choose Settings > Apps >
SMS Messaging > Permissions, and turn on the SMS permission for the app. Since the
user can turn on or off SMS permission at any time, you need to add a check in your app for
this permission, and request it from the user if necessary. You will do this in the next step.
116
2.1: Sending and Receiving SMS Messages - Part 1
This permission enables a permission setting in the Settings app for your app. The user can
allow or disallow this permission at any time from the Settings app. You can add code to
request permission from the user if the user has turned off SMS permission for the app.
Follow these steps:
1. At the top of MainActivity, below the class definition, change the global constant for the
MY_PERMISSIONS_REQUEST_CALL_PHONE request code to the following:
3. Remove the isTelephonyEnabled() method, and remove all of the code in the
onCreate() method that starts with the mTelephonyManager assignment, leaving only
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
ii. Find and then set the smsButton (the message icon) to be invisible so that the user
can't send a message.
iii. Set the Retry button to be visible, so that the user can restart the activity and allow
permission.
117
2.1: Sending and Receiving SMS Messages - Part 1
Extract a string resource ( sms_disabled ) for the hard-coded string "SMS usage
disabled" in the toast statement.
118
2.1: Sending and Receiving SMS Messages - Part 1
When your app calls requestPermissions(), the system shows a standard dialog for
each permission to the user, as shown in the figure below.
119
2.1: Sending and Receiving SMS Messages - Part 1
120
2.1: Sending and Receiving SMS Messages - Part 1
8. When the user responds to the request permission dialog, the system invokes your
app's onRequestPermissionsResult() method, passing it the user response. Find the
onRequestPermissionsResult() method you created for the previous version of this app.
CALL_PHONE with SEND_SMS . The switch block should now look like the following:
...
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_SEND_SMS: {
if (permissions[0].equalsIgnoreCase
(Manifest.permission.SEND_SMS)
&& grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
// Permission was granted. Enable sms button.
enableSmsButton();
} else {
// Permission denied.
Log.d(TAG, getString(R.string.failure_permission));
Toast.makeText(this,
getString(R.string.failure_permission),
Toast.LENGTH_LONG).show();
// Disable the sms button.
disableSmsButton();
}
}
}
If the user allows the permission request, the message button is re-enabled with
enableSmsButton() in case it was made invisible by lack of permission.
If the user denies the permission requests, your app should take appropriate action. For
example, your app might disable the functionality that depends on a specific permission
and show a dialog explaining why it could not perform it. For now, log a debug
message, display a toast to show that permission was not granted, and disable the
message button with disableSmsButton() .
121
2.1: Sending and Receiving SMS Messages - Part 1
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkForSmsPermission();
}
10. Remove the callNumber() method and the MyPhoneCallListener inner class (including
the onCallStateChanged() method, as you are no longer using the Telephony Manager).
11. Remove the onDestroy() method since you are no longer using a listener.
12. Since the user might turn off SMS permission while the app is still running, add a check
for SMS permission in the smsSendMessage() method after setting the sentIntent but
before using the SmsManager class:
...
PendingIntent sentIntent = null, deliveryIntent = null;
// Check for permission first.
checkForSmsPermission();
// Use SmsManager.
...
122
2.1: Sending and Receiving SMS Messages - Part 1
123
2.1: Sending and Receiving SMS Messages - Part 1
4. Click Deny. In the app's UI, the message icon button no longer appears, and a Retry
button appears, as shown below.
124
2.1: Sending and Receiving SMS Messages - Part 1
125
2.1: Sending and Receiving SMS Messages - Part 1
126
2.2: Sending and Receiving SMS Messages - Part 2
2. Select the package name in the Project:Android: view and choose File > New > Other
> Broadcast Receiver.
3. Name the class "MySmsReceiver" and make sure "Exported" and "Enabled" are
checked.
The "Exported" option allows your app to respond to outside broadcasts, while
"Enabled" allows it to be instantiated by the system.
127
2.2: Sending and Receiving SMS Messages - Part 2
4. Open the AndroidManifest.xml file again. Note that Android Studio automatically
generates a <receiver> tag with your chosen options as attributes:
<receiver
android:name=
"com.example.android.smsmessaging.MySmsReceiver"
android:enabled="true"
android:exported="true">
</receiver>
Add the following inside the <receiver> tags to register your receiver:
<receiver
android:name="com.example.android.smsmessaging.MySmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
1. Open MySmsReceiver and add under the class declaration a string constant TAG for
log messages and a string constant pdu_type for identifying PDUs in a bundle:
128
2.2: Sending and Receiving SMS Messages - Part 2
i. Add the @TargetAPI annotation for the method, because it performs a different
action depending on the build version.
iv. Get the format for the message from the bundle .
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
...
4. Retrieve from the bundle one or more pieces of data in the protocol data unit (PDU)
format, which is the industry-standard format for an SMS message:
...
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get(pdu_type);
...
5. If there are messages ( pdus ), check for Android version 6.0 (Marshmallow) and newer
versions. You will use this boolean to check if your app needs the deprecated signature
createFromPdu(byte[] pdu) for earlier versions of Android:
...
if (pdus != null) {
// Check the Android version.
boolean isVersionM = (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.M);
...
6. Initialize the msgs array, and use its length in the for loop:
129
2.2: Sending and Receiving SMS Messages - Part 2
...
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
// Check Android version and use appropriate createFromPdu.
if (isVersionM) {
// If Android version M or newer:
msgs[i] =
SmsMessage.createFromPdu((byte[]) pdus[i], format);
} else {
// If Android version L or older:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
...
Use createFromPdu(byte[] pdu, String format) to fill the msgs array for Android version
6.0 (Marshmallow) and newer versions. For earlier versions of Android, use the
deprecated signature createFromPdu(byte[] pdu).
...
// Build the message to show.
strMessage += "SMS from " + msgs[i].getOriginatingAddress();
strMessage += " :" + msgs[i].getMessageBody() + "\n";
...
...
// Log and display the SMS message.
Log.d(TAG, "onReceive: " + strMessage);
Toast.makeText(context, strMessage, Toast.LENGTH_LONG).show();
...
130
2.2: Sending and Receiving SMS Messages - Part 2
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get(pdu_type);
if (pdus != null) {
// Check the Android version.
boolean isVersionM =
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
// Check Android version and use appropriate createFromPdu.
if (isVersionM) {
// If Android version M or newer:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
} else {
// If Android version L or older:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
// Build the message to show.
strMessage += "SMS from " + msgs[i].getOriginatingAddress();
strMessage += " :" + msgs[i].getMessageBody() + "\n";
// Log and display the SMS message.
Log.d(TAG, "onReceive: " + strMessage);
Toast.makeText(context, strMessage, Toast.LENGTH_LONG).show();
}
}
}
You can also receive an SMS text message when testing on an emulator. Follow these
steps:
131
2.2: Sending and Receiving SMS Messages - Part 2
3. The extended controls for the emulator appear. Click Phone in the left column to see
the extended phone controls:
132
2.2: Sending and Receiving SMS Messages - Part 2
4. You can now enter a message (or use the default "marshmallows" message) and click
Send Message to have the emulator send an SMS message to itself.
5. The emulator responds with a notification about receiving an SMS message. The app
should also display a toast message showing the message and its originating address,
as shown below:
133
2.2: Sending and Receiving SMS Messages - Part 2
134
2.2: Sending and Receiving SMS Messages - Part 2
Solution Code
Android Studio project: SmsMessaging
Coding challenge
Note: All coding challenges are optional.
Challenge: Create a simple app with one button, Choose Picture and Send, that enables
the user to select an image from the Gallery and send it as a Multimedia Messaging Service
(MMS) message. After tapping the button, a choice of apps may appear, including the
Messenger app. The user can select the Messenger app, and select an existing
conversation or create a new conversation, and then send the image as a message.
To access and share an image from the Gallery, you need the following permission in
the AndroidManifest.xml file:
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" />
To enable the above permission, follow the model shown previously in this chapter to
check for the READ_EXTERNAL_STORAGE permission, and request permission if necessary.
Use the following intent for picking an image:
Override the onActivityResult method to retrieve the intent result, and use getData() to
get the Uri of the image in the result:
Set the image's Uri, and use an intent with ACTION_SEND , putExtra() , and setType() :
135
2.2: Sending and Receiving SMS Messages - Part 2
Android Studio emulators can't pass MMS messages to and from each other. You must
test this app on real Android devices.
For more information about sending multimedia messages, see Sending MMS with
Android.
Summary
136
2.2: Sending and Receiving SMS Messages - Part 2
To send an intent to an SMS messaging app with a phone number, your app needs to
prepare a URI for the phone number as a string prefixed by "smsto:" (as in
smsto:14155551212 ).
Use an implicit intent with ACTION_SENDTO to launch an SMS app, and set the phone
number and message for the intent with setData() and putExtra .
To send SMS messages from within your app, add the "android.permission.SEND_SMS"
permission to the AndroidManifest.xml file:
Use the sendTextMessage() method of the SmsManager class to send the message,
which takes the following parameters:
destinationAddress : The string for the phone number to receive the message.
scAddress : A string for the service center address, or null to use the current
Use the following createFromPdu() signature for Android version 6.0 (Marshmallow)
and newer versions:
Use the following createFromPdu() signature for versions older than Android version
6.0:
137
2.2: Sending and Receiving SMS Messages - Part 2
To send an SMS message to an app running in an emulator, click the … (More) icon at
the bottom of the emulator's toolbar on the right side, choose Phone, enter a message
(or use the default "marshmallows" message), and click Send Message.
Related concept
SMS Messages
Learn more
Android Developer Reference:
Intent
Common Intents: Text Messaging
Intents and Intent Filters
SmsManager
Requesting Permissions at Run Time
checkSelfPermission
Run Apps on the Android Emulator
Stack Overflow: Simulating incoming call or sms in Android Studio
Android blog: Getting Your SMS Apps Ready for KitKat
138