Sunteți pe pagina 1din 138

TableofContents

TableofContents

Introduction

Introduction
 

1.1

1.1

Lesson1.PhoneCalls

Lesson1.PhoneCalls
 

1.2

1.2
Concepts   1.2.1

Concepts

 

1.2.1

1.2.1
1:PhoneCalls   1.2.1.1

1:PhoneCalls

 

1.2.1.1

1.2.1.1
Practicals   1.2.2

Practicals

 

1.2.2

1.2.2
1.1:MakingPhoneCalls-Part1   1.2.2.1

1.1:MakingPhoneCalls-Part1

 

1.2.2.1

1.2.2.1
1.2:MakingPhoneCalls-Part2   1.2.2.2

1.2:MakingPhoneCalls-Part2

 

1.2.2.2

1.2.2.2

Lesson2.SMSMessages

Lesson2.SMSMessages
 

1.3

1.3
Concepts   1.3.1

Concepts

 

1.3.1

1.3.1
2:SMSMessages   1.3.1.1

2:SMSMessages

 

1.3.1.1

1.3.1.1
Practicals   1.3.2

Practicals

 

1.3.2

1.3.2
2.1:SendingandReceivingSMSMessages-Part1 1.3.2.1

2.1:SendingandReceivingSMSMessages-Part1

1.3.2.1

1.3.2.1
2.2:SendingandReceivingSMSMessages-Part2 1.3.2.2

2.2:SendingandReceivingSMSMessages-Part2

1.3.2.2

1.3.2.2

Introduction

AndroidApps–PhoneCallsandSMS

TheAndroidApps–PhoneCallsandSMScourseincludestwolessonscreatedbythe

GoogleDeveloperTrainingteam.Thelessonsaredesignedtobeusedininstructor-led

training,butthematerialsarealsoavailableonlineforself-study.

Prerequisites

CompletionoftheentireAndroidDeveloperFundamentalscourse,orequivalent

knowledge

Javaprogrammingexperience

KnowledgeofAndroidprogrammingfundamentals

Coursematerials

ThecoursematerialsincludetheconceptuallessonsandpracticalexercisesinthisGitBook.

Slidedecksarealsoavailableforoptionalusebyinstructors.

Whatdothelessonscover?

InAndroidPhoneCalls,studentslearnhowtousethetelephonyfeaturesinAndroid.Inthe

practical,theycreateanappthatlaunchesthePhoneappwithaphonenumbertomakea

call,andanotherappthatchecksforneededpermissionsandservices,andthenletsthe

usermakeaphonecallfromwithintheapp.

InAndroidSMSMessages,studentslearnhowtousetheSMSfeaturesinAndroid.Inthe

practical,theycreateanappthatlaunchesanSMSmessagingappwithamessage,and

anotherappthatchecksforneededpermissions,sendsanSMSmessage,andreceives

SMSmessages.

DevelopedbytheGoogleDeveloperTrainingTeam

Lastupdated:March2017

Introduction

Introduction ThisworkislicensedunderaCreativeCommonsAttribution-NonCommercial4.0 InternationalLicense 4

ThisworkislicensedunderaCreativeCommonsAttribution-NonCommercial4.0

InternationalLicense

1:PhoneCalls

1:PhoneCalls

Contents:

Thedifferencebetweendialingandcalling

Sendinganintentwithaphonenumbertodial

Makingacallfromwithinyourapp

Usingemulatorstotestphonecalls

RelatedpracticalMakingacallfromwithinyourapp Usingemulatorstotestphonecalls Learnmore

LearnmoreUsingemulatorstotestphonecalls Relatedpractical

Androidmobiledeviceswithtelephone/cellularservicearesuppliedwithaPhoneappfor

makingcalls,whichincludesadialerfordialingaphonenumber.Thischapterdescribesthe

AndroidtelephonyfeaturesyoucanusefromwithinyourappbylaunchingthePhoneapp

withanimplicitintent.Youcanaddcodetoyourappto:

Dial:LaunchthePhoneapp'sdialerwithaphonenumbertodialacall.Thisisthe

preferredtechniqueforappsthatdon'tneedtomonitorthephone'sstate.

Call:Requesttheuser'spermissionifnecessary,andmakeaphonecallfromwithinthe

app,withtheabilitytomonitorthephone'sstate.Thistechniquekeepstheuserwithin

yourapp,withouthavingtonavigatebacktotheapp.Italsoenablesphonecallsifthe

PhoneapphasbeendisabledinSettings.

Android'sPhoneappautomaticallyreceivesincomingphonecalls.Youcanusethe

PhoneStateListenerclasstomonitorthephone'sringingstateandshowtheincomingphone

number.

Tip:YoucanalsouseabroadcastreceiverinyourapptodetectanincomingcallorSMS

message.BroadcastreceiversaredescribedinBroadcastReceiversintheAndroid

DeveloperFundamentalsCourse.

Thedifferencebetweendialingandcalling

YouuseanimplicitintenttolaunchthePhoneappfromyourapp.Youcandothisintwo

ways:

UseanimplicitIntent and Intentand

numberinthedialer.

tolaunchthePhoneappanddisplaythephone

Thisisthesimplestway,withnoneedtorequestpermissionfromtheuser(the

Phoneappasksforuserpermissionifneeded).

1:PhoneCalls

Theusercanchangethephonenumberbeforedialingthecall.

TheusernavigatesbacktoyourappusingtheBackbuttonafterthecallis

completed.

Back buttonafterthecallis completed. Useanimplicit Intent and app. ACTION_CALL

UseanimplicitIntentand

app.

tomakethephonecalldirectlyfromwithinyour

Thisactionkeepstheuserwithinyourapp,withouthavingtonavigatebackfrom

thePhoneapp.

Yourcodemustasktheuserforpermissionbeforemakingthecalliftheuserhasn't

alreadygrantedpermission.Justasyourappneedstheuser'spermissionto

accessthecontactsorusethebuilt-incamera,itneedstheuser'spermissionto

directlyusethephone.

Yourappcanmonitorthestateofthephonecall.

Formattingaphonenumber

TouseanintenttolaunchthePhoneappwithaphonenumbertodial,yourappneedsto

prepareaUniformResourceIdentifier(URI)forthephonenumber.TheURIisastring

prefixedby"tel:",forexample,

numberasyouwouldenteritonaphonekeypad).Youcanhard-codeaphonenumber

insideyourapp,orprovideanEditTextfieldwheretheusercanenteraphonenumber.

tel:14155551212

foraU.S.number(usethecomplete

ThePhoneNumberUtilsclassprovidesutilitymethodsfornormalizingandformattingphone

numberstrings.Forexample,toremoveextraneouscharacterssuchasdashesand

parentheses,usethenormalizeNumber()method,whichremovescharactersotherthan

digitsfromaphonenumberstring.Forexample,thestatementbelownormalizesaphone

numberenteredintoanEditTextviewnamed

editText

:

String normalizedPhoneNumber = PhoneNumberUtils.normalizeNumber(editText.getText().toString());

Note:ThenormalizeNumber()method,addedtoAndroidAPIlevel21(correspondingto

Lollipop),isnotavailableinolderversionsoftheAPI.

UsetheformatNumber()methodtoformataphonenumberstringforaspecificcountryifthe

givennumberdoesn'tincludeacountrycode.Youcanuse

Locale.getDefault().getCountry()

togetthecurrentcountrysetting,orusetheISO3166-1

two-lettercountrycodetospecifyacountrytouse:

String formattedNumber = PhoneNumberUtils.formatNumber(normalizedPhoneNumber, Locale.getDefault().getCountry());

1:PhoneCalls

Usinganintentwiththephonenumbertodial

TouseanintenttolaunchthePhoneapp,useabuttontolettheuserstartthecall.When

theusertapsthebutton,itsclickhandlerinitiatesthecall.Forexample,asimplelayout

couldprovideanImageButtonlikethephoneiconinthefigurebelow.

1:PhoneCalls

1:PhoneCalls 8

1:PhoneCalls

ThePhoneappopenswiththenumbertobedialed.Theusercanchangethenumberand

initiatethecall.ThePhoneappthenmakesthecall.

<ImageButton

android:id="@+id/phone_icon"

android:onClick="dialNumber"/>

Inthe

passthephonenumbertothePhoneappasaURI.

dialNumber()

method,useanimplicitintentwiththeintentaction

ACTION_DIAL

to

public void dialNumber() { TextView textView = (TextView) findViewById(R.id.number_to_call); // Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", textView.getText().toString());

// 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)); // 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.");

}

}

Intheaboveexample,thecodedoesthefollowing:

Getsthetextofthephonenumberfrom

textView

with

String.format

toincludethe

tel:

prefix(forexample

getText()

andusesitwith

tel:14155551212

):

String phoneNumber = String.format("tel: %s", textView.getText().toString());

Createsanimplicitintentwiththeintentaction

numberasthedatafortheintentusingsetData():

ACTION_DIAL

,andsetsthephone

Intent intent = new Intent(Intent.ACTION_DIAL); // Set the data for the intent as the phone number. intent.setData(Uri.parse(phoneNumber));

1:PhoneCalls

Checksiftheimplicitintentresolvestoanappthatisinstalledonthedevice.

1. Ifitdoes,thecodesendstheintentwith

startActivity()

,andthesystem

launchesthePhoneapp,asshowninthefigurebelow.

1:PhoneCalls

1:PhoneCalls 11

1:PhoneCalls

2. Ifitdoesnot,anerrorislogged.

Iftherearenoappsonthedevicethatcanreceivetheimplicitintent,yourappwillcrash

whenitcalls

resolveActivity()onyourIntentobjectwithgetPackageManager()togeta

PackageManagerinstanceforfindingpackageinformation.The

methoddeterminesthebestactiontoperformforagivenintent.Iftheresultisnon-null,

thereisatleastoneappthatcanhandletheintentandit'ssafetocall

startActivity()

.Tofirstverifythatanappexiststoreceivetheintent,call

resolveActivity()

startActivity()

.

if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Log.e(TAG, "Can't resolve app for ACTION_DIAL Intent.");

}

Thisexampleusesahard-codedphonenumber,whichisausefultechniqueforprovidinga

supporthotlinenumber,ortheselectedphonenumberforacontact.Inthenextexample,

userscanentertheirownnumberstomakecalls.

Makingacallfromwithinyourapp

Tomakeaphonecalldirectlyfromyourapp,dothefollowing:

1. Addpermissionsthatenablemakingacallandreadingthephoneactivity.

2. Checktoseeiftelephonyisenabled;ifnot,disablethephonefeature.

3. Checktoseeiftheusercontinuestograntpermission,orrequestpermissionifneeded.

4. ExtendPhoneStateListener,andregisterthelistenerusingtheTelephonyManager

class.

5. Useanimplicitintentwith

ACTION_CALL

tomakethephonecall.

Addingpermissionstothemanifest

Accesstotelephonyinformationispermission-protected.Inordertomakeacall,yourapp

needsthe

CALL_PHONE

permission.Inaddition,inordertomonitorthephonestate,yourapp

needsthe

READ_PHONE_STATE

permission.Bothmustbedeclaredintheapps's

AndroidManifest.xmlfile.

Addthefollowingtoyourapp'sAndroidManifest.xmlfileafterthefirstline(withthe

definition)andbeforethe

<application>

section:

package
package

1:PhoneCalls

<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />

<application

CheckingforTelephonyManager

NotalldevicesareenabledtouseTelephonyManager.Tochecktoseeiftelephonyis

enabled,followthesesteps:

1. RetrieveaTelephonyManagerusinggetSystemService()withthestringconstant

TELEPHONY_SERVICEintheonCreate()methodoftheactivity:

@Override protected void onCreate(Bundle savedInstanceState) {

// Create a telephony manager. mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

}

2. Createamethodtoensurethat

ready:

mTelephonyManager

isnotnull,andthattheSIMstateis

private boolean isTelephonyEnabled() { if (mTelephonyManager != null) { if (mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY) {

return true;

}

}

return false;

}

The getSimState() Theabove return not,itreturns true
The
getSimState()
Theabove
return
not,itreturns
true

methodreturnsaconstantindicatingthestateoftheSIMcard.

statementfirstchecksif

telephonyManager

ifthestateoftheSIMis"ready".

isnot

null
null

,andifitis

3. Calltheabovemethodinthe

onCreate()

methodofyouractivity.Iftelephonyisnot

enabled,yourcodeshoulddisablethefeature.Theexamplebelowdisplaysatoast

message,logsadebugmessage,anddisablesthecallbutton,effectivelydisablingthe

phonefeature:

1:PhoneCalls

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();

}

Checkingandrequestinguserpermission

BeginninginAndroid6.0(APIlevel23),usersgrantpermissionstoappswhiletheappis

running,notwhentheyinstalltheapp.Thisapproachstreamlinestheappinstallprocess,

sincetheuserdoesnotneedtograntpermissionswhentheyinstallorupdatetheapp.It

alsogivestheusermorecontrolovertheapp'sfunctionality.However,yourappmustcheck

forpermissioneverytimeitdoessomethingthatrequirespermission(suchasmakinga

phonecall).IftheuserhasusedtheSettingsapptoturnoffPhonepermissionsfortheapp,

yourappcandisplayadialogtorequestpermission.

Followthesestepstocheckforandrequestuserpermissiontomakephonecalls:

1. Atthetopoftheactivitythatmakesaphonecall,andbelowtheactivity'sclass

definition,defineaconstantvariabletoholdtherequestcode,andsetitto

1 :
1
:

private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;

Whytheinteger1?Eachpermissionrequestneedsthreeparameters:the context ,a stringarrayofpermissions,andaninteger
Whytheinteger1?Eachpermissionrequestneedsthreeparameters:the
context
,a
stringarrayofpermissions,andaninteger
requestCode
.The
requestCode
isaninteger

attachedtotherequest,anditcanbeanyintegerthatsuitsyourusecase.Whena

resultreturnsintheactivity,itcontainsthiscodeandusesittodifferentiatemultiple

permissionresultsfromeachother.

2. Intheactivitythatmakesaphonecall,createaprivatemethod

checkForPhonePermission()

thatreturns

void .
void
.

1:PhoneCalls

private void checkForPhonePermission() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { // Permission not yet granted. Use requestPermissions(). Log.d(TAG, getString(R.string.permission_not_granted)); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);

}

else { // Permission already granted.

}

3. Intheactivity's

 

onCreate()

method,callthemethodtoperformthetelephonycheck:

if (isTelephonyEnabled()) { // Check for phone permission. checkForPhonePermission(); // Todo: Register the PhoneStateListener.

}

else {

Notethefollowingaboutthe

checkForPhonePermission()

method:

Thecodeuses{ Notethefollowingaboutthe checkForPhonePermission() method: checkSelfPermission() todeterminewhetheryourapphasbeen

todeterminewhetheryourapphasbeen

grantedaparticularpermissionbytheuser.

Ifpermissionhasnotbeengranted,thecodeusesthe

displayastandarddialogfortheusertograntpermission.

methodto

TherequestPermissions() methodto requestPermissions()

requestPermissions()

methodneedsthreeparameters:thecontext,astringarray

ofpermissions,andthepredefinedinteger

requestCode

.

Whenyourappcallsofpermissions,andthepredefinedinteger requestCode . requestPermissions() ,thesystemshowsastandardpermission

requestPermissions()

,thesystemshowsastandardpermission

dialogtotheuser,asshowninthefigurebelow.Yourappcan'tconfigureoralterthe

dialog.

dialog. Tip

Tip:Ifyouwanttoprovideanyinformationorexplanationtotheuser,youmustdothat

1:PhoneCalls

Whentheuserrespondstotherequestpermissiondialog,thesysteminvokesyourapp's

onRequestPermissionsResult()method,passingittheuserresponse.Overridethatmethod

tofindoutwhetherthepermissionwasgranted:

@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();

}

}

}

}

Theabovecodesnippetshowsa

withone

switch
switch

statementbasedonthevalueof

case
case

tocheckifthepermissionistheoneyoudefinedas

MY_PERMISSIONS_REQUEST_CALL_PHONE

.

requestCode

,

Tip:Ithelpstousea

switch
switch

statementsothatyoucanaddmorerequeststotheapp.

Theuser'sresponsetotherequestdialogisreturnedinthe

onlyonepermissionisrequestedinthedialog).Comparethistothecorrespondinggrant

result,whichiseither

permissions

array(index

0
0

PERMISSION_GRANTED

or

PERMISSION_DENIED

.

if

Iftheuserdeniesapermissionrequest,yourappshouldtakeappropriateaction.For

example,yourappmightdisablethefunctionalitythatdependsonthispermission(suchas

thecallbutton)andshowadialogexplainingwhyitcouldnotperformit.

ExtendingandregisteringPhoneStateListener

PhoneStateListenermonitorschangesinspecifictelephonystatessuchasringing,off-hook,

andidle.TousePhoneStateListener:

ImplementalistenerclassthatextendsPhoneStateListener,andoverrideits

1:PhoneCalls

IntheonCallStateChanged()method,provideactionsbasedonthephonestate.

RegisterthelistenerusingtheTelephonyManagerclass,whichprovidesaccessto

informationaboutthetelephonyservicesonthedevice.

Implementingalistener

CreateaprivateclassinyouractivitythatextendsPhoneStateListener:

private class MyPhoneCallListener extends PhoneStateListener {

}

Withinthisclass,implementthe

takeactionsbasedonthephonestate.Thecodebelowusesa

constantsoftheTelephonyManagerclasstodeterminewhichofthreestatesthephoneisin:

methodofPhoneStateListenerto

switch
switch

statementwith

CALL_STATE_RINGING

,

CALL_STATE_OFFHOOK

,and

CALL_STATE_IDLE

:

@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;

}

}

Provideactionsforphonestates

Addtheactionsyouwanttotakebasedonthephonestates.Forexample,yourcodecan

logamessagefortestingpurposes,anddisplayatoasttotheuser.The

stateincludestheincomingphonenumber,whichyourcodecanshowinatoast.

CALL_STATE_RINGING

1:PhoneCalls

Thephoneisinthe

CALL_STATE_IDLE

stateuntilacallisstarted.Thephonestatechangesto

CALL_STATE_OFFHOOK

inordertomaketheconnectionandstaysinthestatefortheduration

stateafterthecallfinishesorif

ofthecall.Thephonestatereturnstothe

thecallisdeniedornotcompleted.

CALL_STATE_IDLE

Yourappresumeswhenthestatechangesbacktothe

CALL_STATE_IDLE

state.

Tip:AnapprunningonAndroidversionspriortoKitKat(version19)doesn'tresumewhen

thephonestatereturnsto

Thecodebelowsetstheflag

CALL_STATE_IDLE

from

CALL_STATE_OFFHOOK

to

true
true

attheendofacall.

returningFromOffHook

whenthestateis

CALL_STATE_OFFHOOK

,sothatwhenthestateisbackto

CALL_STATE_IDLE

,youcanusethe

flagtocatchtheend-of-callandrestarttheapp'sactivity.

private class MyPhoneCallListener extends PhoneStateListener { private boolean returningFromOffHook = false;

@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.

1:PhoneCalls

Intent intent = getPackageManager() .getLaunchIntentForPackage( .getPackageName()); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i);

}

}

break;

default:

message = message + "Phone off"; Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();

Log.i(TAG, message); break;

}

}

}

Registeringyourlistener

RegisterthelistenerobjectusingtheTelephonyManagerclass:

UsetelephonyManager.listen()withthePhoneStateListenersettothe

Context.TELEPHONY_SERVICE

.

LISTEN_CALL_STATE

.

Agoodplacetodothisisintheactivity's

permission,whichisafterensuringthattelephonyisenabled.Followthesesteps:

onCreate()

methodrightaftercheckingforphone

1. Atthetopoftheactivity,defineavariableforthePhoneStateListener:

private MyPhoneCallListener mListener;

2. Inthe

onCreate()

permission:

method,addthefollowingcodeaftercheckingfortelephonyand

if (isTelephonyEnabled()) {

checkForPhonePermission(); // Register the PhoneStateListener to monitor phone activity. mListener = new MyPhoneCallListener(); telephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);

} else {

3. Youmustalsounregisterthelistenerintheactivity'sonDestroy()method.Thismethod

isusuallyimplementedtofreeresourceslikethreadsthatareassociatedwithan

1:PhoneCalls

activity,sothatadestroyedactivitydoesnotleavesuchthingsaroundwhiletherestof

itsapplicationisstillrunning.Overridethe

code:

onDestroy()

methodbyaddingthefollowing

@Override protected void onDestroy() { super.onDestroy(); if (isTelephonyEnabled()) { telephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);

}

}

Usinganimplicitintenttomakethecall

TolaunchthePhoneappandstartthecall:

Useabuttoninthelayoutwithan

onClick
onClick

methodsuchas

callNumber().

Inthe callNumber() ACTION_CALL .
Inthe
callNumber()
ACTION_CALL
.

method,createanimplicitintentwiththeintentaction

Setthephonenumberasthedatafortheintentwith

setData()

.

Thefollowingisansample

callNumber()

method:

public void callNumber(View view) { EditText editText = (EditText) findViewById(R.id.editText_main); // Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", editText.getText().toString());

// 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, check for phone permission, // and send intent. if (callIntent.resolveActivity(getPackageManager()) != null) { checkForPhonePermission(); startActivity(callIntent); } else { Log.e(TAG, "Can't resolve app for ACTION_CALL Intent.");

}

}

Asinthepreviousexampleforpassinganumberfordialing,youuseastringforthephone

numberwiththe

tel:
tel:

prefix.

1:PhoneCalls

Iftheimplicitintentresolvestoaninstalledapp,usethe

youcreatedpreviouslytochecktoseeiftheappstillhaspermissiontomakethecall.You

mustcheckforthatpermissioneverytimeyouperformanoperationthatrequiresit,because

theuserisalwaysfreetorevokethepermission.Eveniftheappusedthephoneaminute

ago,itcan'tassumeitstillhasthatpermissionaminutelater.

checkForPhonePermission()

method

Usingemulatorstotestphonecallfunctionality

Ifyoudon'thavecellularserviceonyourdevice,ortelephonyisnotenabled,youcantest

theappusingtwoemulatorinstances—oneemulatorinstancecallstheotherone.

1. LaunchanemulatordirectlyfromtheAVDManagerbychoosingTools>Android> AVDManager.

2. Double-clickapredefineddevice.Notethenumberthatappearsintheemulator's

windowtitleonthefarright,asshowninthefigurebelowas#1(5556).Thisistheport

numberoftheemulatorinstance.

numberoftheemulatorinstance. 3. OpentheAndroidStudioprojectforthephone-callingapp. 4.

3. OpentheAndroidStudioprojectforthephone-callingapp.

4. Runthephone-callingapp,butchooseanotheremulatorfromthelist—nottheonethat

1:PhoneCalls

isalreadyrunning. 5. Inthephone-callingapp,insteadofarealphonenumber,entertheportnumber(asin

5556),andclickthecallbutton.Theemulatorshowsthephonecallstartingup,as

showninthefigurebelow.

1:PhoneCalls

1:PhoneCalls 23

1:PhoneCalls

Theotheremulatorinstanceshouldnowbereceivingthecall,asshowninthefigure

below:

1:PhoneCalls

1:PhoneCalls 25

1:PhoneCalls

6. ClickAnswerorDismissontheemulatorreceivingthecall,.AfteryouclickAnswer, alsoclicktheredHang-upbuttontoendthecall.

1:PhoneCalls

1:PhoneCalls 27

1.1:MakingPhoneCalls-Part1

1.1:Part1-MakingPhoneCalls

Contents:

WhatyoushouldalreadyKNOW

WhatyouwillLEARNContents : WhatyoushouldalreadyKNOW WhatyouwillDO Appoverview

WhatyouwillDOContents : WhatyoushouldalreadyKNOW WhatyouwillLEARN Appoverview Task1:Sendanintentwiththephonenumbertodial

Appoverview: WhatyoushouldalreadyKNOW WhatyouwillLEARN WhatyouwillDO Task1:Sendanintentwiththephonenumbertodial

Task1:Sendanintentwiththephonenumbertodial

Task2:Makeaphonecallfromwithinanapp

Androidmobiledeviceswithtelephone/cellularservicearepre-installedwithaPhoneappfor

makingcalls,whichincludesadialerfordialinganyphonenumber.YouuseanimplicitIntent

tolaunchthePhoneappfromyourapp.Youhavetwochoices:

Intent tolaunchthePhoneappfromyourapp.Youhavetwochoices: Use ACTION_DIAL

tolaunchthePhoneappindependentlyfromyourappwiththephone

numberdisplayedinthedialer.TheuserthenmakesthecallinthePhoneapp.Thisis

thepreferredactionforappsthatdon'thavetomonitorthephone'sstate.

Use ACTION_CALL

tolaunchthePhoneappinthecontextofyourapp,makingthecall

directlyfromyourapp,andmonitoringthephonestate.Thisactionkeepstheuser

withinyourapp,withouthavingtonavigatebacktotheapp.Yourappmustrequest

permissionfromtheuserbeforemakingthecalliftheuserhasn'talreadygranted

permission.

WhatyoushouldalreadyKNOW

Fromthepreviouschapters,youshouldbeableto:

CreateandruninteractiveappsinAndroidStudio.

WorkwithXMLlayouts.CreateandruninteractiveappsinAndroidStudio. Createanimplicitintenttoperformanactionusinganotherapp.

Createanimplicitintenttoperformanactionusinganotherapp.

WhatyouwillLEARN

Inthispractical,youwilllearnto:

PassaphonenumbertothePhoneapp'sdialer.

Performaphonecallwithinyourapp.

Testtoseeiftelephonyservicesareenabled.

1.1:MakingPhoneCalls-Part1

Checkforcallingpermission,andrequestpermissionifrequired.

WhatyouwillDO

Inthispractical,youwill:

CreateanappthatusesanimplicitintenttolaunchthePhoneapp.

Createanotherappthatmakesphonecallsfromwithintheapp.

Testtoseeiftelephonyservicesareenabledbeforeenablingtheapp.

Checkforcallingpermission,whichcanchangeatanytime.

Requestpermissionfromtheuser,ifnecessary,tomakethecall.

Appoverview

Youwillcreatetwoapps:

PhoneCallDial:AbasicappthatusesanimplicitintenttolaunchthePhoneappwitha

hard-codedphonenumberfordialing.ThePhoneappmakesthecall.Youcoulduse

thistechniquetoprovideaone-buttondialertocustomsupport.Inthislessonyouwill

buildalayout,showninthefigurebelow.ItincludesaTextViewwithahard-coded

phonenumber,andanImageButtonwithanicontolaunchthePhoneappwiththat

phonenumberinitsdialer.

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 31

1.1:MakingPhoneCalls-Part1

PhoneCallingSample:Anappthatsecurespermission,usesanimplicitintentto

makeaphonecallfromtheapp,andusestheTelephonyManagerclasstomonitorthe

phone'sstate.Youwouldusethistechniqueifyouwanttokeeptheuserwithinyour

app,withouthavingtonavigatebacktotheapp.Inthislesson,youmodifytheabove

layouttouseanEditTextsothatuserscanenterthephonenumber.Thelayoutlooks

likethefigurebelow:

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 33

1.1:MakingPhoneCalls-Part1

Task1.Sendanintentwiththephonenumber

todial

InthistaskyouwillcreateanappthatusesanimplicitintenttolaunchthePhoneapptodial

agivenphonenumber.Tosendthatintent,yourappneedstoprepareaUniformResource

Identifier(URI)thatisprefixedby"tel:"(forexample

tel:14155551212

).

1.1Createtheappandlayout

1. CreateaprojectusingtheEmptyActivitytemplateandcallitPhoneCallDial.

2. Addaniconforthecallbuttonbyfollowingthesesteps:

i. Selectthedrawable/folderintheProject:AndroidviewandchooseFile>New>

VectorAsset.

ii. ClicktheAndroidiconnextto"Icon:"tochooseanicon.Tofindahandseticon,

chooseCommunicationintheleftcolumn.

iii. Selecttheicon,clickOK,clickNext,andthenclickFinish.

3. Opentheactivity_main.xmllayoutfile.

i. ChangetherootviewtoRelativeLayout.

ii. Inthe"HelloWorld"TextViewelement,removethe

theyarepresent.

layout_constraint

attributes,if

iii. ChangetheTextViewtoshowadummycontactname,asiftheapphadretrieved

thenamefromacontactsdatabaseandassignedittoaTextView:

<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" />

4. Extractthestringsanddimensionsintoresources:

24sp : Jane Doe : contact_name
24sp
:
Jane Doe
: contact_name

contact_text_size

forthetextsize.

forthetext.

5. AddanotherTextViewforthephonenumber:

1.1:MakingPhoneCalls-Part1

<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" />

Youwillusethe

android:id

number_to_call

toretrievethephonenumber.

6. Afteraddingahard-codedphonenumberstring,extractitintotheresource

phone_number

.

7. AddanImageButtonforinitiatingthecall:

<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"/>

Usethevectorassetyouaddedpreviously(forexample

phonehandseticon)forthe

torefertothebuttonfordialingthephone.

@phone_icon

ic_call_black_24dp

fora

android:src

attribute.Youwillusethe

android:id

The

highlighteduntilyoucreatethismethodintheMainActivity,whichyoudointhenext

step.

dialNumber

methodreferredtointhe

android:onClick

attributeremains

8. Afteraddingahard-codedcontentdescription,extractitintothestringresource

9.

make_a_call

.

Click

andthenselectCreatedialNumber(View)in'MainActivity'.AndroidStudio

automaticallycreatesthe

parameter.Thismethodiscalledwhentheusertapsthe

dialNumber

inthe

android:onClick

dialNumber()

attribute,clicktheredlightbulbthatappears,

methodinMainActivityas

public
public

,returning

void ,witha View ImageButton.
void
,witha
View
ImageButton.

public void dialNumber(View view) {

}

1.1:MakingPhoneCalls-Part1

Thelayoutshouldlooksomethinglikethefigurebelow.

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 37

1.1:MakingPhoneCalls-Part1

ThefollowingisthecompletecodefortheXMLlayoutinactivity_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" />

<!-- TextView for a hard-coded phone number --> <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="@string/phone_number" />

<!-- The dialNumber() method will be called by this button. --> <ImageButton android:id="@+id/phone_icon" android:contentDescription="@string/make_a_call" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/contact_name" android:layout_toRightOf="@id/number_to_call" android:layout_toEndOf="@id/number_to_call"

android:src="@drawable/ic_call_black_24dp"

android:onClick="dialNumber"/>

</RelativeLayout>

1.2EdittheonClickmethodinMainActivity

1. InMainActivity,defineaconstantforthelogtag.

public static final String TAG = MainActivity.class.getSimpleName();

2. Insidethe

dialNumber()

methodcreatedintheprevioussection,createareferenceto

the

number_to_call

TextView:

public void dialNumber(View view) { TextView textView = (TextView) findViewById(R.id.number_to_call);

public void dialNumber(View view) { TextView textView = (TextView) findViewById(R.id.number_to_call);

public void dialNumber(View view) { TextView textView = (TextView) findViewById(R.id.number_to_call);

1.1:MakingPhoneCalls-Part1

3. TocreatethephonenumberURIstring

phoneNumber

,getthephonenumberfrom

textView

anduseitwith

String.format

toincludethe

tel:

prefix:

// Use format with "tel:" and phone number to create mPhoneNum. String phoneNumber = String.format("tel:
// Use format with "tel:" and phone number to create mPhoneNum. String phoneNumber = String.format("tel:
// Use format with "tel:" and phone number to create mPhoneNum. String phoneNumber = String.format("tel:
// Use format with "tel:" and phone number to create mPhoneNum. String phoneNumber = String.format("tel:

// Use format with "tel:" and phone number to create mPhoneNum. String phoneNumber = String.format("tel: %s", textView.getText().toString());

phone number to create mPhoneNum. String phoneNumber = String.format("tel: %s", textView.getText().toString());

4. Defineanimplicitintent(

dialIntent

)withtheintentaction

ACTION_DIAL

,andsetthe

phoneNumber

asdatafortheintent:

// Create the intent. Intent dialIntent = new Intent(Intent.ACTION_DIAL); // Set the data for the

// 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. Toverifythatanappexiststoreceivetheintent,callresolveActivity()onyourIntent

objectwithgetPackageManager()togetaPackageManagerinstanceforfinding

packageinformation.The

performforagivenintent.Iftheresultisnon-null,thereisatleastoneappthatcan

resolveActivity()

methoddeterminesthebestactionto

handletheintentandit'ssafetocall

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.");

}

Thefullmethodshouldnowlooklikethefollowing:

1.1:MakingPhoneCalls-Part1

public void dialNumber() { TextView textView = (TextView) findViewById(R.id.number_to_call); // Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", textView.getText().toString());

// 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)); // 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.");

}

}

1.3Runtheapp

Youcanruntheapponeitheranemulatororadevice:

1. Clickortapthephoneicon.Thedialershouldappearwiththephonenumberreadyto use,asshowninthefigurebelow:

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 41

1.1:MakingPhoneCalls-Part1

2. The

phone_number

stringholdsafixednumber(1-415-555-1212).Youcanchangethe

numberinthePhoneapp'sdialerbeforecalling.

3. UsetheBackbuttontoreturntotheapp.Youmayneedtotaporclickittwoorthree

timestonavigatebackwardsfromthePhoneapp'sdialerandFavoriteslist.

Solutioncode

AndroidStudioproject:PhoneCallDial

Task2.Makeaphonecallfromwithinanapp

InthistaskyouwillcopythePhoneCallDialappfromtheprevioustask,refactorandrename

ittoPhoneCallingSample,andmodifyitslayoutandcodetocreateanappthatenablesa

usertoenteraphonenumberandperformthephonecallfromwithinyourapp.

Inthefirststepyouwilladdthecodetomakethecall,buttheappwillworkonlyiftelephony

isenabled,andiftheapp'spermissionforPhoneissetmanuallyinSettingsonthedeviceor

emulator.

Insubsequentstepsyouwilldoawaywithsettingthispermissionmanuallybyrequesting

phonepermissionfromtheuserifitisnotalreadygranted.Youwillalsoaddatelephony

checktodisplayamessageiftelephonyisnotenabledandcodetomonitorthephonestate.

2.1Createtheappandaddpermission

1. CopythePhoneCallDialprojectfolder,renamethefoldertoPhoneCallingSample,and

refactortheapptopopulatethenewnamethroughouttheappproject.(Seethe

Appendixforinstructionsoncopyingaproject.)

2. AddthefollowingpermissiontotheAndroidManifest.xmlfileafterthefirstline(withthe

package
package

definition)andbeforethe

<application>

section:

<uses-permission android:name="android.permission.CALL_PHONE" />

Yourappcan'tmakeaphonecallwithoutthe

AndroidManifest.xml.ThispermissionlineenablesasettingfortheappintheSettings

appthatgivestheuserthechoiceofallowingordisallowinguseofthephone.(Inthe

nexttaskyouwilladdawayfortheusertograntthatpermissionfromwithintheapp.)

CALL_PHONE

permissionlinein

2.2Createtheapplayout

1.1:MakingPhoneCalls-Part1

1. Openactivity_main.xmltoeditthelayout.

2. Removethe

contact_name

TextView,andreplacethe

thefollowingEditTextview:

number_to_call

TextViewwith

<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. Afteraddingahard-codedstringforthe

android:hint

resource

enter_phone

,andnotethefollowing:

attribute,extractitintothestring

,andnotethefollowing: attribute,extractitintothestring Youwillusethe android:id

Youwillusethe

android:id

fortheEditTextviewinyourcodetoretrievethe

phonenumber.

TheEditTextviewusesthe

phone-stylenumerickeypad.

android:inputType

attributesetto

"phone"
"phone"

fora

4. ChangetheImageButtonasfollows:

i. Changethe

android:layout_below

,

android:layout_toRightOf

android:layout_toEndOf

attributestoreferto

editText_main

.

,and

ii. Addthe

android:visibility

attributesetto

ofthisImageButtonfromyourcode.

visible
visible

.Youwillcontrolthevisibility

iii. Changetheandroid:onClickmethodto

callNumber

untilyouaddthatmethodtoMainActivity.

.Thiswillremainhighlighted

<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. AddthefollowingButtonattheendofthelayout,beforetheending

tag:

</RelativeLayout>

1.1:MakingPhoneCalls-Part1

<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>

6. Afteraddingahard-codedstring"Retry"forthe

android:contentDescription

attribute,

extractitintothestringresource

retry
retry

,andthenreplacethehard-codedstringinthe

android:text

attributeto

"@string/retry"

.

7. Notethefollowing:

Youwillrefertothetheattributeto "@string/retry" . 7. Notethefollowing: Makesureyouincludethe android:id button_retry

Makesureyouincludethe. 7. Notethefollowing: Youwillrefertothethe android:id button_retry android:visibility inyourcode.

android:id button_retry
android:id
button_retry

android:visibility

inyourcode.

attributesetto

"invisible"

.It

shouldappearonlyiftheappdetectsthattelephonyisnotenabled,oriftheuser

previouslydeniedphonepermissionwhentheapprequestedit.

Yourapp'slayoutshouldlooklikethefollowingfigure(the

button_retry

Buttonisinvisible):

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 45

1.1:MakingPhoneCalls-Part1

2.3ChangetheonClickmethodinMainActivity

1. InMainActivity,refactorandrenamethe

dialNumber()

methodtocallit

callNumber()

.

2. Changethefirststatement,whichreferredtoaTextView,touseanEditTextview:

 

public void callNumber(View view) { EditText editText = (EditText) findViewById(R.id.editText_main);

 

}

3. ChangethenextstatementtogetthephonenumberfromtheEditTextview(

editText

)

tocreatethephonenumberURIstring

phoneNumber

:

// Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel:

// Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", editText.getText().toString());

phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", editText.getText().toString());

4. Beforetheintent,addcodetoshowalogmessageandatoastmessagewiththephone

number:

// Log the concatenated phone number for dialing. Log.d(TAG, "Phone Status: DIALING: " + phoneNumber); Toast.makeText(this, "Phone Status: DIALING: " + phoneNumber, Toast.LENGTH_LONG).show();

5. Extract

"Phone Status: DIALING: "

toastringresource(

dial_number

seconduseofthestringinthe

Toast.makeText()

statementto

getString(R.string.dial_number)

.

).Replacethe

6. Refactorandrenamethe

dialIntent

implicitintentto

callIntent

,andreplace

ACTION_DIAL

with

ACTION_CALL

.Asaresult,thestatementsshouldnowlooklikethis:

// 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.");

}

Thefullmethodshouldnowlooklikethefollowing:

1.1:MakingPhoneCalls-Part1

public void callNumber() { EditText editText = (EditText) findViewById(R.id.editText_main); // Use format with "tel:" and phone number to create phoneNumber. String phoneNumber = String.format("tel: %s", editText.getText().toString()); // Log the concatenated phone number for dialing. Log.d(TAG, getString(R.string.dial_number) + phoneNumber); Toast.makeText(this, getString(R.string.dial_number) + phoneNumber, Toast.LENGTH_LONG).show(); // 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.");

}

}

2.4Runtheapp

Whenyouruntheapp,theappmaycrashwiththefollowingscreendependingonwhether

thedeviceoremulatorhasbeenpreviouslysettoallowtheapptomakephonecalls:

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 48

1.1:MakingPhoneCalls-Part1

InsomeversionsofAndroid,thispermissionisturnedonbydefault.Inothers,this

permissionisturnedoffbydefault.

Tosettheapp'spermissiononadeviceoremulatorinstance,performthefunctionthata

userwouldperform:chooseSettings>Apps>PhoneCallingSample>Permissionson

thedeviceoremulator,andturnonthePhonepermissionfortheapp.Sincetheusercan

turnonoroffPhonepermissionatanytime,youhavetoaddacheckinyourappforthis

permission,andrequestitfromtheuserifrequired.Youwilldothisinthenexttask.

Ifyoudon'thavecellularserviceonyourdevice,oriftelephonyisnotenabled,youcantest

theappusingtwoemulatorinstances—oneemulatorinstancecallstheotherone.Follow

thesesteps:

1. TolaunchanemulatordirectlyfromtheAVDManager,chooseTools>Android>AVD Manager.

2. Double-clickapredefineddevice.Notethenumberthatappearsintheemulator's

windowtitleonthefarright,asshowninthefigurebelowas#1(5556).Thisistheport

numberoftheemulatorinstance.

numberoftheemulatorinstance. 3.

3. OpentheAndroidStudioprojectfortheapp,ifitisn'talreadyopen.

1.1:MakingPhoneCalls-Part1

4. Runtheapp,butchooseanotheremulator—nottheonethatisalreadyrunning.Android

Studiolaunchestheotheremulator.

5. Intheapp,entertheportnumberoftheotheremulatorratherthanarealphonenumber.

6. Clickthecallbuttonintheapp.Theemulatorshowsthephonecallstartingup,as

showninthefigurebelow.

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 51

1.1:MakingPhoneCalls-Part1

Theotheremulatorinstanceshouldnowbereceivingthecall,asshowninthefigure

below:

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 53

1.1:MakingPhoneCalls-Part1

7. ClickAnswerorDismissontheemulatorreceivingthecall.IfyouclickAnswer,also clicktheredHang-upbuttontoendthecall.

1.1:MakingPhoneCalls-Part1

1.1:MakingPhoneCalls-Part1 55

1.1:MakingPhoneCalls-Part1

EndofPart1-ContinuewithPart2

1.2:MakingPhoneCalls-Part2

1.2:Part2-MakingPhoneCalls

Contents:

Task3:Checkfortelephonyserviceandrequestpermission

Task4:Monitorthephonestate

CodingchallengeTask4:Monitorthephonestate Summary Relatedconcept Learnmore

SummaryTask4:Monitorthephonestate Codingchallenge Relatedconcept Learnmore Task3.Checkfortelephonyserviceand

RelatedconceptTask4:Monitorthephonestate Codingchallenge Summary Learnmore Task3.Checkfortelephonyserviceand

LearnmoreCodingchallenge Summary Relatedconcept Task3.Checkfortelephonyserviceand requestpermission

Task3.Checkfortelephonyserviceand

requestpermission

Iftelephonyfeaturesarenotenabledforadevice,yourappshoulddetectthatanddisable

thephonefeatures.

Inaddition,yourappmustalwaysgetpermissiontouseanythingthatisnotpartoftheapp

itself.IntheprevioustaskyouaddedthefollowingpermissiontotheAndroidManifest.xml

file:

<uses-permission android:name="android.permission.CALL_PHONE" />

ThisstatementenablesapermissionsettingforthisappinSettings.Theusercanallowor

disallowthispermissionatanytimeinSettings.Youcanaddcodetorequestpermissionif

theuserhasturnedoffphonepermission.

3.1Checkiftelephonyservicesareenabled

1. OpentheAndroidStudioprojectforthePhoneCallingSampleapp,ifitisn'talready

open.

2. AtthetopofMainActivitybelowtheclassdefinition,defineavariableforthe

TelephonyManagerclassobject:

private TelephonyManager mTelephonyManager;

3. AddthefollowingstatementtoonCreate()methodinMainActivitytousethestring

constant

TELEPHONY_SERVICE

with

getSystemService()

andassignitto

1.2:MakingPhoneCalls-Part2

mTelephonyManager

device.

.Thisgivesyouaccesstosomeofthetelephonyfeaturesofthe

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a telephony manager. mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

4. CreateamethodinMainActivitytocheckiftelephonyisenabled:

private boolean isTelephonyEnabled() { if (mTelephonyManager != null) { if (mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY) {

}

return true;

}

}

return false;

5. Calltheabovemethodinthe

mTelephonyManager

,inan

onCreate() if
onCreate()
if

method,rightafterassigning

statementtotakeactioniftelephonyisenabled.The

actionshouldbetologamessage(toshowthattelephonyisenabled),andincludea

commentaboutcheckingpermission,whichyouwilladdinthenextstep.Iftelephonyis

notenabled,displayatoastmessage,logamessage,anddisablethecallbutton:

@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();

}

}

1.2:MakingPhoneCalls-Part2

6. Extractthehard-codedstringsintheabovecodetostringresources: Telephony is enabled" : telephony_enabled
6.
Extractthehard-codedstringsintheabovecodetostringresources:
Telephony is enabled"
:
telephony_enabled
"TELEPHONY NOT ENABLED! "
:
telephony_not_enabled
7.
Createthe
disableCallButton()
methodinMainActivity,andcodeto:
Displayatoasttonotifytheuserthatthephonefeatureisdisabled.
Findandthensetthecallbuttontobeinvisiblesothattheusercan'tmakeacall.
Iftelephonyisenabled(butthephonepermissionhadnotbeengranted),setthe
Retrybuttontobevisible,sothattheusercanstarttheactivityagainandallow
permission.
private void disableCallButton() {
Toast.makeText(this,
"Phone calling disabled", Toast.LENGTH_LONG).show();
ImageButton callButton = (ImageButton) findViewById(R.id.phone_icon);
callButton.setVisibility(View.INVISIBLE);
if (isTelephonyEnabled()) {
Button retryButton = (Button) findViewById(R.id.button_retry);
retryButton.setVisibility(View.VISIBLE);
}
}
8.
Extractastringresource(
phone_disabled
)forthehard-codedstring"Phonecalling
disabled"inthetoaststatement.
9.
Createan
enableCallButton()
methodinMainActivitythatfindsandthensetsthecall
buttontobevisible:
private void enableCallButton() {
ImageButton callButton = (ImageButton) findViewById(R.id.phone_icon);
callButton.setVisibility(View.VISIBLE);
}
10.
Createthe
retryApp()
methodinMainActivitythatwillbecalledwhentheuserclicks
thevisibleRetrybutton.Addcodeto:
Call
enableCallButton()
toenablethecallbutton.
Createanintenttostart(inthiscase,restart)theactivity.
public void retryApp(View view) {
enableCallButton();
Intent intent = getPackageManager()
.getLaunchIntentForPackage(getPackageName());
startActivity(intent);
}
11.
Addthe
android:onClick
attributetotheRetrybuttontocallretryApp:

1.2:MakingPhoneCalls-Part2

<Button

android:id="@+id/button_retry"

android:onClick="retryApp"/>

3.2Requestpermissionforphonecalling

1. AtthetopofMainActivitybelowtheclassdefinition,defineaglobalconstantforthecall-

phonepermissionrequestcode,andsetitto1:

private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;

Whytheinteger1?Eachpermissionrequestneedsthreeparameters:the context ,a stringarrayofpermissions,andaninteger
Whytheinteger1?Eachpermissionrequestneedsthreeparameters:the
context
,a
stringarrayofpermissions,andaninteger
requestCode
.The
requestCode
isacode

attachedtotherequest,andcanbeanyintegerthatsuitsyourusecase.Whenaresult

returnsbacktotheactivity,itcontainsthiscodeandusesittodifferentiatemultiple

permissionresultsfromeachother.

2. InMainActivity,createaprivatemethodcalled

checkForPhonePermission

tocheckfor

CALL_PHONE

permission,whichreturns

void
void

.Youputthiscodeinaseparatemethod

becauseyouwilluseitmorethanonce:

private void checkForPhonePermission() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "PERMISSION NOT GRANTED!"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);

} else { // Permission already granted. Enable the call button. enableCallButton();

}

}

3. Use

todeterminewhetheryourapphasbeengranteda

particularpermissionbytheuser.Ifpermissionhasnotbeengrantedbytheuser,use

the

permission.

methodtodisplayastandarddialogfortheusertogrant

4. Whenyourappcalls

user,asshowninthefigurebelow.

,thesystemshowsastandarddialogtothe

1.2:MakingPhoneCalls-Part2

1.2:MakingPhoneCalls-Part2 61

1.2:MakingPhoneCalls-Part2

5. Extractthehard-codedstring

"PERMISSION NOT GRANTED!"

resource

permission_not_granted

.

intheabovecodetothestring

6. Inthe

onCreate()

methodaftercheckingtoseeiftelephonyisenabled,addacallto

checkForPhonePermission()

:

@Override protected void onCreate(Bundle savedInstanceState) {

if (isTelephonyEnabled()) { // Check for phone permission. checkForPhonePermission(); // ToDo: Register the PhoneStateListener.

7. Whentheuserrespondstotherequestpermissiondialog,thesysteminvokesyour

app's

thatmethodtofindoutwhetherthepermissionwasgranted:

method,passingittheuserresponse.Override

@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { // Check if permission is granted or not for the request.

}

8. Foryourimplementationof onRequestPermissionsResult() ,usea switch statement witheach case basedonthevalueof
8. Foryourimplementationof
onRequestPermissionsResult()
,usea
switch
statement
witheach
case
basedonthevalueof
requestCode
.Useone
case
tocheckifthe

permissionistheoneyoudefinedas

MY_PERMISSIONS_REQUEST_CALL_PHONE

:

1.2:MakingPhoneCalls-Part2

// 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. Extractthehard-codedstring

"Failure to obtain permission!"

intheabovecodetothe

stringresource

failure_permission

,andnotethefollowing:

Theuser'sresponsetotherequestdialogisreturnedinthe

(index

abovecomparesthistothecorrespondinggrantresult,whichiseither

permissions

array

0
0

ifonlyonepermissionisrequestedinthedialog).Thecodesnippet

PERMISSION_GRANTED

or

PERMISSION_DENIED

.

Iftheuserdeniesapermissionrequest,yourappshouldtakeappropriateaction.

Forexample,yourappmightdisablethefunctionalitythatdependsonthis

permissionandshowadialogexplainingwhyitcouldnotperformit.Fornow,loga

debugmessage,displayatoasttoshowthatpermissionwasnotgranted,and

disablethecallbuttonwith

disableCallButton()

.

3.3Runtheappandtestpermission

1. Runtheapponce.Afterrunningtheapp,turnoffthePhonepermissionfortheappon

yourdeviceoremulatorsothatyoucantestthepermission-requestfunction:

i. ChooseSettings>Apps>PhoneCallingSample>Permissionsonthedevice oremulator.

ii. TurnoffthePhonepermissionfortheapp.

2. Runtheappagain.Youshouldseetherequestdialoginthefigureintheprevious

section.

1.2:MakingPhoneCalls-Part2

i. TapDenytodenypermission.Theappshoulddisplayatoastmessageshowing

thefailuretogainpermission,andtheRetrybutton.Thephoneiconshould

disappear.

ii. TapRetry,andwhentherequestdialogappears,tapAllow.Thephoneicon

shouldreappear.Testtheapp'sabilitytomakeaphonecall.

3. SincetheusermightturnoffPhonepermissionwhiletheappisstillrunning,addthe

samepermissioncheckmethodtothe

toapackage,asshownbelow—tocheckforpermissionrightbeforemakingacall:

callNumber()

method—aftertheintentresolves

// If package resolves to an app, check for phone permission, // and send intent. if (callIntent.resolveActivity(getPackageManager()) != null) { checkForPhonePermission(); startActivity(callIntent); } else { Log.e(TAG, "Can't resolve app for ACTION_CALL Intent");

}

4. Runtheapp.IftheuserchangesthePhonepermissionfortheappwhiletheappis

running,therequestdialogappearsagainfortheusertoAlloworDenythepermission.

i. ClickAllowtotesttheapp'sabilitytomakeaphonecall.Theappshouldmakethe

callwithoutaproblem.

ii. JumptotheSettingsapptoturnoffPhonepermissionfortheapp(theappshould

stillberunning):

i. ChooseSettings>Apps>PhoneCallingSample>Permissionsonthe deviceoremulator.

ii. TurnoffthePhonepermissionfortheapp.

iii. Gobacktotheappandtrytomakeacall.Therequestdialogshouldappearagain. Thistime,ClickDenytodenypermissiontomakeaphonecall.Theappshould displayatoastmessageshowingthefailuretogainpermission,andtheRetry button.Thephoneiconshoulddisappear.

Task4.Monitorthephonestate

YoucanmonitorthephonestatewithPhoneStateListener,whichmonitorschangesin

specifictelephonystates.Youcanthenshowtheuserthestateinatoastmessage,sothat

theusercanseeifthephoneisidleoroffthehook.

1.2:MakingPhoneCalls-Part2

Whenthephonecallfinishesandthephoneswitchestotheidlestate,yourapp'sactivity

resumesiftheappisrunningonKitKat(version19)ornewerversions.However,iftheapp

isrunningonaversionofAndroidolderthanKitKat(version19),thePhoneappremains

active.Youcancheckthephonestateandrestarttheactivityifthestateisidle.

TousePhoneStateListener,youneedtoregisteralistenerobjectusingthe

TelephonyManagerclass,whichprovidesaccesstoinformationaboutthetelephonyservices

onthedevice.CreateanewclassthatextendsPhoneStateListenertoperformactions

dependingonthephonestate.Youcanthenregisterthelistenerobjectinthe

methodoftheactivity,usingtheTelephonyManagerclass.

onCreate()

4.1Setthepermissionandloggingtag

1. OpentheAndroidStudioprojectforthePhoneCallingSampleapp,ifitisn'talready

open.

2. Addthefollowing

READ_PHONE_STATE

permissiontotheAndroidManifest.xmlfileafter

aftertheCALL_PHONEpermission,andbeforethe

<application>

section:

<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />

Monitoringthestateofaphonecallispermission-protected.Thispermissionisin

additiontothe

CALL_PHONE

permission.

4.2CreateaclassthatextendsPhoneStateListener

1. Tocreatealistenerobjectandlistentothephonestate,createaprivateinnerclass

called

MyPhoneCallListener

inMainActivitythatextendsPhoneStateListener.

private class MyPhoneCallListener extends PhoneStateListener {

}

2. Withinthisclass,implementthe

methodofPhoneStateListener

totakeactionsbasedonthephonestate.Thecodebelowusesa

withconstantsoftheTelephonyManagerclasstodeterminewhichofthreestatesthe

phoneisin:

statement

switch
switch

CALL_STATE_RINGING

,

CALL_STATE_OFFHOOK

,and

CALL_STATE_IDLE

:

1.2:MakingPhoneCalls-Part2

@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. Justabovethe

switch (state)

line,createa

asaprefixforthephonestate:

String
String

called

message
message

touseinatoast

// Define a string for the message to use in a toast. String message = "Phone Status: "; switch (state) {

4. Extractthestring

5. Forthe

"Phone Status: "

tothestringresource

phone_status

.

CALL_STATE_RINGING

state,assembleamessageforlogginganddisplayinga

toastwiththeincomingphonenumber:

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;

6. Extract

7. Addaboolean

"RINGING, number: "

tothestringresource

,setto

ringing . false
ringing
.
false

returningFromOffHook

,atthetopofthe

MyPhoneCallListener

declaration,inordertouseitwiththethe

CALL_STATE_OFFHOOK

state:

1.2:MakingPhoneCalls-Part2

private class MyPhoneCallListener extends PhoneStateListener { private boolean returningFromOffHook = false;

}

Tip:AnapprunningonAndroidversionspriortoKitKat(version19)doesn'tresume

whenthephonestatereturnsto

ofacall.Theboolean

thestateis

flagdesignatesanend-of-callinordertorestarttheapp'sactivity.

CALL_STATE_IDLE

from

CALL_STATE_OFFHOOK

attheend

when

,the

returningFromOffHook

isusedasaflag,andsetto

true
true

CALL_STATE_OFFHOOK

,sothatwhenthestateisbackto

CALL_STATE_IDLE

8. Forthe

CALL_STATE_OFFHOOK

state,assembleamessageforlogginganddisplayinga

toast,andsetthe

returningFromOffHook

booleanto

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;

9. Extract

10. Forthe

"OFFHOOK"

tothestringresource

offhook .
offhook
.

CALL_STATE_IDLE

state,loganddisplayatoast,andcheckif

returningFromOffHook

is

true
true

;ifso,restarttheactivityiftheversionofAndroidis

earlierthanKitKat.

1.2:MakingPhoneCalls-Part2

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;

IftheappisrunningonKitKat(version19)ornewerversions,thereisnoneedtorestart

theactivityafterthephonecallends.ButiftheappisrunningonaversionofAndroid

olderthanKitKat(version19),thecodemustrestartthecurrentactivitysothattheuser

canreturntotheappafterthecallends.

Tip:Thecodealsosets

instanceofthecurrentactivity,anyotheractivitiesontopofthecurrentactivityare

closedandanintentisdeliveredtothe(nowontop)currentactivity.Thisflaghelpsyou

manageastackofactivitiesinanapp.

sothatinsteadoflaunchinganew

11. Extract

"IDLE"
"IDLE"

tothestringresource

stringresource

restarting_app

.

idle
idle

,andextract

"Restarting app"

Thecodebelowshowstheentire

onCallStateChanged()

method:

tothe

@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).

1.2:MakingPhoneCalls-Part2

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;

}

}

4.3RegisterthePhoneStateListener

1. AtthetopofMainActivitybelowtheclassdefinition,defineavariableforthe PhoneStateListener:

1.2:MakingPhoneCalls-Part2

private MyPhoneCallListener mListener;

2. Inthe

onCreate()

permission:

method,addthefollowingcodeaftercheckingfortelephonyand

if (isTelephonyEnabled()) {

checkForPhonePermission(); // Register the PhoneStateListener to monitor phone activity. mListener = new MyPhoneCallListener(); telephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);

} else {

3. Youmustalsounregisterthelistenerintheactivity'sonDestroy()method.Overridethe

onDestroy()

methodbyaddingthefollowingcode:

@Override protected void onDestroy() { super.onDestroy(); if (isTelephonyEnabled()) { telephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);

}

}

4.4Runtheapp

1. Runtheapp.IftheuserchangesthePhonepermissionfortheappwhiletheappis

running,therequestdialogappearsagainfortheusertoAlloworDenythepermission.

ClickAllowtotesttheapp'sabilitytomakeaphonecall.

2. Afterenteringaphonenumberandclickingthecallbutton,theemulatorordevice

showsthephonecallstartingup,asshowninthefigurebelow.Atoastmessage

appearsshowingthephonenumber(leftsideoffigure),andthetoastmessagechanges

toshowanewstatusof"OFFHOOK"(rightsideoffigure)afterthecallhasstarted.

1.2:MakingPhoneCalls-Part2

1.2:MakingPhoneCalls-Part2 3. Theotheremulatorinstanceordeviceshouldnowbereceivingthecall,asshowninthe figurebelow.Click

3. Theotheremulatorinstanceordeviceshouldnowbereceivingthecall,asshowninthe figurebelow.ClickAnswerorDismissonthedeviceoremulatorreceivingthecall.

1.2:MakingPhoneCalls-Part2

1.2:MakingPhoneCalls-Part2 72

1.2:MakingPhoneCalls-Part2

4. IfyouclickAnswer,besuretoalsoclicktheredHang-upbuttontofinishthecall,as showninthefigurebelow.

1.2:MakingPhoneCalls-Part2

1.2:MakingPhoneCalls-Part2 74

1.2:MakingPhoneCalls-Part2

Afteryouhangup,theappshouldreappearwithatoastmessageshowingthatthephoneis

nowintheidlestate,asshowninthefigurebelow.

1.2:MakingPhoneCalls-Part2

1.2:MakingPhoneCalls-Part2 76

1.2:MakingPhoneCalls-Part2

Solutioncode

AndroidStudioproject:PhoneCallingSample

Codingchallenge

Note:Allcodingchallengesareoptionalandarenotprerequisitesforlaterlessons.

Challenge:

1. UsethenormalizeNumber()methodinthePhoneNumberUtilsclasstoremove charactersotherthandigitsfromthephonenumberaftertheuserhasenteredit.This

methodwasaddedtoAPIlevel21.Ifyouneedyourapptorunonolderversions,

includeacheckfortheversionthatusesthenormalizeNumber()methodonlyifthe versionisolderthanLollipop.Yourappalreadyusesalogstatementtoshowthephone

numberasdialed,soiftheuserenters"1-415-555-1212"thelogmessageshouldshow

thatthenumberwasnormalized:

D/MainActivity: Phone Status: DIALING: tel: 14155551212

2. AddaninvisibleTextViewtothePhoneCallingSampleapp.ThisTextViewshouldappear

belowtheinvisibleRetrybutton,butonlywhenthephoneisringing(indicatingan

incomingcall),anditshouldshowthephonenumberofthecaller.

Ifyouhavebothemulatorsopenasdescribedpreviously,installtheapponbothemulators.

Youcanthentestanincomingcallbyusingtheappononeemulatortocalltheother

emulator.

Tip:Youcanalsoemulatereceivingacallbyclickingthe(More)iconatthebottomofthe

emulator'stoolbarontherightside.ClickPhoneintheleftcolumntoseetheextended

phonecontrols,andclickCallDevicetocalltheemulator.

AndroidStudioproject:PhoneCallingSampleChallenge

Summary

TosendanintenttothePhoneappwithaphonenumber,yourappneedstopreparea

URIforthephonenumberasastringprefixedby"tel:"(forexampletel:14155551212).

Todialaphonenumber,createanimplicitintentwith

numberURIasthedatafortheintentwith

ACTION_DIAL setData() :
ACTION_DIAL
setData()
:

,andsetthephone

1.2:MakingPhoneCalls-Part2

Intent callIntent = new Intent(Intent.ACTION_DIAL); callIntent.setData(Uri.parse(phoneNumber));

Forphonepermission,addthefollowingtotheAndroidManifest.xmlfile:

<uses-permission android:name="android.permission.CALL_PHONE" />

Tomakeaphonecall,createanimplicitintentwith

ACTION_CALL

,andsetthephone

numberURIasthedatafortheintentwith

setData()

:

Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse(phoneNumber));

 

Tocheckiftelephonyisenabled,usethestringconstant

with

toretrieveaTelephonyManager,whichgivesyouaccessto

telephonyfeatures.

UseTelephonyManager ,whichgivesyouaccessto telephonyfeatures. checkSelfPermission()

todeterminewhetheryourapphasbeengranteda

particularpermissionbytheuser.Ifpermissionhasnotbeengranted,usethe

methodtodisplayastandarddialogfortheusertogrant

permission.

TomonitorthephonestatewithPhoneStateListener,registeralistenerobjectusingthe

Forphonemonitoringpermission,addthefollowingtotheAndroidManifest.xmlfile:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Tomonitorphonestates,createaprivateclassthatextendsPhoneStateListener,and

overridethe

actionsbasedonthephonestate:

methodofPhoneStateListenertotakedifferent

CALL_STATE_RINGING

,

CALL_STATE_OFFHOOK

,or

CALL_STATE_IDLE

.

Relatedconcept

PhoneCalls, CALL_STATE_OFFHOOK ,or CALL_STATE_IDLE . Relatedconcept Learnmore Androiddeveloperdocumentation: CommonIntents

Learnmore

Androiddeveloperdocumentation:

2:SMSMessages

2:SMSMessages

Contents:

SendingandreceivingSMSmessages

UsinganintenttolaunchanSMSapp

SendingSMSmessagesfromyourapp

ReceivingSMSmessagesUsinganintenttolaunchanSMSapp SendingSMSmessagesfromyourapp Relatedpractical Learnmore

RelatedpracticalSendingSMSmessagesfromyourapp ReceivingSMSmessages Learnmore

LearnmoreReceivingSMSmessages Relatedpractical

Androiddevicescansendandreceivemessagestoorfromanyotherphonethatsupports

ShortMessageService(SMS).AndroidofferstheMessengerappthatcansendandreceive

SMSmessages.Ahostofthird-partyappsforsendingandreceivingSMSmessagesare

alsoavailableinGooglePlay.

ThischapterdescribeshowtouseSMSinyourapp.Youcanaddcodetoyourappto:

LaunchanSMSmessagingappfromyourapptohandleallSMScommunication.

SendanSMSmessagefromwithinyourapp.

ReceiveSMSmessagesinyourapp.

Note:TheSMSprotocolwasprimarilydesignedforuser-to-usercommunicationandisnot

well-suitedforappsthatwanttotransferdata.YoushouldnotuseSMStosenddata

messagesfromawebservertoyourapponauserdevice.SMSisneitherencryptednor

stronglyauthenticatedoneitherthenetworkorthedevice.

SendingandreceivingSMSmessages

AccesstotheSMSfeaturesofanAndroiddeviceisprotectedbyuserpermissions.Justas

yourappneedstheuser'spermissiontousephonefeatures,soalsodoesanappneedthe

user'spermissiontodirectlyuseSMSfeatures.

However,yourappdoesn'tneedpermissiontopassaphonenumbertoaninstalledSMS

app,suchasMessenger,forsendingthemessage.TheMessengerappitselfisgovernedby

userpermission.

YouhavetwochoicesforsendingSMSmessages:

UseanimplicitIntenttolaunchamessagingappsuchasMessenger,withthe

ACTION_SENDTOaction.

2:SMSMessages

Thisisthesimplestchoiceforsendingmessages.Theusercanaddapictureor

otherattachmentinthemessagingapp,ifthemessagingappsupportsadding

attachments.

Yourappdoesn'tneedcodetorequestpermissionfromtheuser.

IftheuserhasmultipleSMSmessagingappsinstalledontheAndroidphone,the

Appchooserwillappearwithalistoftheseapps,andtheusercanchoosewhich

onetouse.(Androidsmartphoneswillhaveatleastone,suchasMessenger.)

Theusercanchangethemessageinthemessagingappbeforesendingit.

TheusernavigatesbacktoyourappusingtheBackbutton.

SendtheSMSmessageusingthesendTextMessage()methodorothermethodsofthe

SmsManagerclass.

Thisisagoodchoiceforsendingmessagesfromyourappwithouthavingtouse

anotherinstalledapp.

Yourcodemustasktheuserforpermissionbeforesendingthemessageiftheuser

hasn'talreadygrantedpermission.

Theuserstaysinyourappduringandaftersendingthemessage.

YoucanmanageSMSoperationssuchasdividingamessageintofragments,

sendingamultipartmessage,getcarrier-dependentconfigurationvalues,andso

on.

ToreceiveSMSmessages,thebestpracticeistousetheonReceive()methodofthe

BroadcastReceiverclass.TheAndroidframeworksendsoutsystembroadcastsofevents

suchasreceivinganSMSmessage,containingintentsthataremeanttobereceivedusing

aBroadcastReceiver.YourappreceivesSMSmessagesbylisteningforthe

Mostsmartphonesandmobilephonessupportwhatisknownas"PDUmode"forsending

andreceivingSMS.PDU(protocoldataunit)containsnotonlytheSMSmessage,butalso

metadataabouttheSMSmessage,suchastextencoding,thesender,SMSservicecenter

address,andmuchmore.Toaccessthismetadata,SMSappsalmostalwaysusePDUsto

encodethecontentsofaSMSmessage.ThesendTextMessage()and

sendMultimediaMessage()methodsoftheSmsManagerclassencodethecontentsforyou.

WhenreceivingaPDU,youcancreateanSmsMessageobjectfromtherawPDUusing

UsinganintenttolaunchanSMSapp

TouseanIntenttolaunchanSMSapp,yourappneedstoprepareaUniformResource

Identifier(URI)forthephonenumberasastringprefixedby"smsto:"(asin

smsto:14155551212

).Youcanuseahardcodedphonenumber,suchasthephonenumberof

2:SMSMessages

asupportmessagecenter,orprovideanEditTextfieldinthelayouttoenabletheuserto

enteraphonenumber.

Tip:FordetailsaboutusingmethodsinthePhoneNumberUtilsclasstoformataphone

numberstring,seetherelatedconceptPhoneCalls.

Useabutton(suchasanImageButton)thattheusercantaptopassthephonenumberto

theSMSapp.Forexample,anappthatenablesausermakeaphonecalland/orsenda

messagetothephonenumbermightofferasimplelayoutwithaphoneiconbuttonfor

calling,andamessagingiconbuttonforsendingamessage,asshowninthefigurebelow.

2:SMSMessages

2:SMSMessages 83

2:SMSMessages

Tocallamethodsuchas

phonenumber,youcanaddthe

message:

smsSendMessage()

thatwouldlaunchamessagingappwitha

attributetothebuttonforsendinga

android:onClick

<ImageButton

android:onClick="smsSendMessage"/>

Inthe

by"smsto:"(asin

phonenumbertotheSMSapp,andsetthephonenumberandmessagefortheintentwith

method,youwouldconvertthephonenumbertoastringprefixed

smsSendMessage()

smsto:14155551212

).Useanimplicitintentwith

ACTION_SENDTO

topassthe

setData()

and

putExtra

.

Tip:The"smsto:"prefixwith

textmessagingapp(andnotbyotheremailorsocialapps).

ACTION_SENDTO

ensuresthatyourintentishandledonlybya

IftheuserhasseveralSMSmessagingapps,theusercanchoosewhichonetoopen.The

SMSappopenswiththesuppliedphonenumberandmessage,enablingtheusertotapa

buttontosendthemessage,orchangethenumberandmessagebeforesending.TheSMS

appthensendsthemessage.

Thefollowingcodedemonstrateshowtoperformanimplicitintenttosendamessage:

public void smsSendMessage(View view) { // Find the TextView number_to_call and assign it to textView. TextView textView = (TextView) findViewById(R.id.number_to_call); // Concatenate "smsto:" with phone number to create smsNumber. String smsNumber = "smsto:" + textView.getText().toString(); // 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(); // 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); // 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.");

}

}

2:SMSMessages

Notethefollowingintheabovecode:

Themethodgetsthephonenumberfromthe

concatenatesitwiththe

smsto:
smsto:

prefix(asin

number_to_call

TextView,and

smsto:14155551212

)beforeassigningitto

smsNumber

.ItalsogetsthemessageenteredintotheEditTextview.

TolaunchanSMSmessagingapp,useanimplicitintent(

smsIntent

)with

ACTION_SENDTO and putExtra .
ACTION_SENDTO
and
putExtra
.

,andsetthephonenumberandmessagefortheintentwith

setData()

TheputExtra()methodneedstwostrings:thekeyidentifyingthetypeofdata

"sms_body"

)andthedataitself,whichisthetextofthemessage(

sms
sms

).Formore

Youneedtosupplyachecktoseeiftheimplicitintentresolvestoapackage(anapp),

andifitdoes,youneedtost