Android,
A Complete Course, From
Basics to Enterprise Edition
Android, A Complete Course, From Basics to Enterprise
Edition
1.1 Gestion des appels téléphoniques et des SMS
Cet
article est extraie du livre « Android, A Complete Course »,
disponible sur Android2ee.com.
Les
exemples ou les programmes présents dans cet ouvrage sont fournis pour
illustrer les descriptions théoriques. Ce code est libre de toute utilisation
mais n'est pas distribuable.
La
distribution du code est reservée au site :
La
propriété intellectuelle du code appartient à :
L’utilisation
de ces codes est sous votre unique responsabilité et personne d’autre que vous
ne pourra être tenu responsable des préjudices ou dommages de quelques natures
que ce soit pouvant résulter de son utilisation.
Tous
les noms de produits ou marques cités dans cet ouvrage sont des marques déposés
par leurs propriétaires respectifs.
Publié par http://android2ee.com
Titre Original : Android, A Complete Course, From
Basics to Enterprise Edition. Édition Française.
ISBN : 979-10-90388-00-0
Copyright © 2011 by Mathias Séguy
Aucune
représentation ou reproduction, même partielle, autre que celles prévues à
l’article L. 122-5 2° et 3° a) du code de la propriété intellectuelle ne peut
être faite sans l’autorisation expresse de Mathias Seguy ou, le cas échéant,
sans le respect des modalités prévues à l’article L. 122-10 dudit code
Ce paragraphe est une vue succincte de la téléphonie, vous apprendrez à lancer l’activité du téléphone à partir de votre activité et à récupérer quelques informations concernant les paramètres de téléphonie.
Composer un numéro de téléphone se résume à demander à l’activité Android native de téléphonie de composer ce numéro. Cette demande s’effectue comme toujours par l’envoie d’un Intent :
/*****************************************************************************************/
/**
Call the phone dialer Activity
*******************************************************/
/*****************************************************************************************/
// Declaration of the attribute telephone number
String
telNumber = "tel:0561437624";
Uri
telNumberUri = Uri.parse(telNumber);
// Declaration of the Intent to call the Phone dialer activity
Intent
phoneCallIntent = new
Intent(Intent.ACTION_DIAL, telNumberUri);
// Calling the Phone Dialer Activity as a peer Activity
startActivity(phoneCallIntent);
Et voilà, l’activité de téléphone s’ouvre avec votre numéro de téléphone pré-renseigné.
Vous pouvez obtenir les informations concernant la structure téléphonique de votre appareil, en autres :
· Le type du téléphone
· L’état de connexion
· L’état de la carte SIM
Pour obtenir ces informations, l’objet à utiliser est le TelephonyManager.
Le code suivant montre un exemple de récupération d’informations :
/***************************************************************************************/
/** Looking for Phone parameters
*******************************************************/
/***************************************************************************************/
// Find the Telephony Manager
TelephonyManager
telephonyManager =
(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
// Retrieveing the phone type:
//----------------------------
switch
(telephonyManager.getPhoneType()) {
case
(TelephonyManager.PHONE_TYPE_GSM):
//case
(TelephonyManager.PHONE_TYPE_CDMA):
// retrieve the Device Id (iemi for GSM
and meid for CDMA)
String deviceId =
telephonyManager.getDeviceId();
// retrieve the software version of th
device
String deviceSoftwareVersion =
telephonyManager.getDeviceSoftwareVersion();
// retrieve the phone number
String phoneNumber = telephonyManager.getLine1Number();
break;
case
(TelephonyManager.PHONE_TYPE_NONE):
break;
}
//Retrieving the state of the connection
//--------------------------------------
switch(telephonyManager.getDataState()){
case(TelephonyManager.DATA_CONNECTED)://I am connected
case(TelephonyManager.DATA_CONNECTING)://I am connecting
case(TelephonyManager.DATA_DISCONNECTED)://I am disconnected
case(TelephonyManager.DATA_SUSPENDED)://I am suspended
break;
}
//Retrieving the state of the SIM card
//------------------------------------
switch(telephonyManager.getSimState()){
case(TelephonyManager.SIM_STATE_ABSENT):
case(TelephonyManager.SIM_STATE_NETWORK_LOCKED):
case(TelephonyManager.SIM_STATE_PIN_REQUIRED):
case(TelephonyManager.SIM_STATE_PUK_REQUIRED):
case(TelephonyManager.SIM_STATE_UNKNOWN):
break;
case(TelephonyManager.SIM_STATE_READY):
//You can retrieve the Sim country
Iso,the operator code, the operator name, the serial number of the card
telephonyManager.getSim***();
break;
}
Une bonne pratique pour s’interfacer avec le téléphone est de s’enregistrer en tant qu’écouteur de changement d’états. En effet votre activité, votre application, est alors amène à réagir à ses changements.
Pour cela, il vous suffit de déclarer un PhoneStateListener et de surcharger les méthodes qui correspondent aux changements d’états qui vous intéressent. Ensuite il faut enregistrer ce PhoneStateListener pour chacun des états qui vous intéressent au moyen du TelephonyManager. Et bien sûr, il ne faut pas oublier de le dé-enregistrer quand votre application n’a plus besoin d’écouter ces changements. Il faut aussi demander la permission de pouvoir lire les états du téléphone.
Dans le manifest.xml
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Dans votre code Java :
/*********************************************************************/
/**
Listening for phone states changes
**********************************************/
/*********************************************************************/
//Define the phone state listener
PhoneStateListener
phoneStateListener=new
PhoneStateListener(){
/** * Listen for call state change */
@Override
public
void
onCallStateChanged(int
state, String incomingNumber) {
//Watch the current state of the call
switch(state){
case(TelephonyManager.CALL_STATE_IDLE):
//The phone is not ringing neither calling
case(TelephonyManager.CALL_STATE_OFFHOOK):
//The phone is in a call
case(TelephonyManager.CALL_STATE_RINGING):
//the phone is ringing
break;
}
//the incoming call is the string incomingNumber
}
/** * Listen for data activity change */
@Override
public
void
onDataActivity(int
direction) {
switch(direction){
case(TelephonyManager.DATA_ACTIVITY_IN):
case(TelephonyManager.DATA_ACTIVITY_INOUT):
case(TelephonyManager.DATA_ACTIVITY_NONE):
case(TelephonyManager.DATA_ACTIVITY_OUT):
break;
}
super.onDataActivity(direction);
}
/** * Listen for data connection change */
@Override
public
void
onDataConnectionStateChanged(int state) {
switch(state){
case(TelephonyManager.DATA_CONNECTED)://I am connected
case(TelephonyManager.DATA_CONNECTING)://I am connecting
case(TelephonyManager.DATA_DISCONNECTED)://I am disconnected
case(TelephonyManager.DATA_SUSPENDED)://I am suspended
break;
}
super.onDataConnectionStateChanged(state);
}
/** * Listen for service state changes */
@Override
public
void
onServiceStateChanged(ServiceState serviceState) {
switch(serviceState){
case(ServiceState.STATE_EMERGENCY_ONLY):
case(ServiceState.STATE_IN_SERVICE):
case(ServiceState.STATE_OUT_OF_SERVICE):
case(ServiceState.STATE_POWER_OFF):
break;
}
super.onServiceStateChanged(serviceState);
}
};
//Bind the listener using a bits field
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE|
PhoneStateListener.LISTEN_DATA_ACTIVITY|
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE|
PhoneStateListener.LISTEN_SERVICE_STATE);
//Unbind the listener when you don't need it more (in onPause for
exemple)
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);
Il n’y pas grand-chose à faire, il suffit d’envoyer l’Intent ACTION_SENDTO avec le numéro de téléphone en URI et le corps du SMS en extra de type sms_body :
/*****************************************************************************************/
/** Sending SMS using Intents
************************************************************/
/*****************************************************************************************/
// URI Defintion
String
phoneNumber = "sms:0663443634";
Uri
phoneNumberUri = Uri.parse(phoneNumber);
// SMS Body definition
String
smsBody = "My message i want to send";
// Intent Definition
Intent
smsIntent = new
Intent(Intent.ACTION_SENDTO, phoneNumberUri);
// Adding the body
smsIntent.putExtra("sms_body",
smsBody);
// Launching the SMS Activity
startActivity(smsIntent);
Ce n’est pas tellement plus difficile, mais profondément différent. Il suffit d’envoyer un Intent de type Send_TO et avec pour URI celui du fichier à joindre. Ensuite, il faut ajouter à l’Intent les extras address, sms_body et extraStream (pour l’URI du fichier attaché), puis définir le type MIME du MMS :
/*****************************************************************************************/
/** Sending MMS using Intents
************************************************************/
/*****************************************************************************************/
// URI Defintion
phoneNumber
= "0663443634";
// Attached file URI
String
attachedFile = "content://media/external/images/media/1";
Uri
attachedFileUri = Uri.parse(attachedFile);
// MMS Body definition
String
mmsBody = "My message i want to send with an
attached file";
// Intent Definition /!\ The action is SEND and the URI is the attached
file
Intent
mmsIntent = new
Intent(Intent.ACTION_SEND, attachedFileUri);
// Adding the phone number
mmsIntent.putExtra("address",
phoneNumber);
// Adding the body
mmsIntent.putExtra("sms_body",
mmsBody);
// Adding the attached file
mmsIntent.putExtra(Intent.EXTRA_STREAM,
attachedFileUri);
// Seeting the MIME Type
mmsIntent.setType("image/png");
// Launching the MMS Activity
startActivity(mmsIntent);
L’envoi d’un SMS, sans passer par une activité prédéfinie, n’est pas très compliqué, par contre son suivi s’avère nécessiter plus d’objets à implémenter.
La seule chose à laquelle il faut être attentif, outre les demandes de permissions, est la longueur du SMS à envoyer, en effet celle-ci est limitée à 160 caractères.
Dans le
manifest.xml, il faut ajouter la demande de permission :
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
Dans le fichier Java de votre activité :
/*****************************************************************************************/
/** Sending SMS manually ******************************************************************/
/** Needs to ask the permission SEND_SMS in your manifest.xml
*****************************/
/*****************************************************************************************/
// Retrieveing the SMS Manager
SmsManager
smsManager = SmsManager.getDefault();
// Address Defintion
phoneNumber
= "0663443634";
// SMS Body definition
smsBody
= "My message i want to send";
//Sending an SMS according to its size
if(smsBody.length()>=160){
//your message has to be split in several parts:
ArrayList<String>
smsBodies=smsManager.divideMessage(smsBody);
// send it with no following with the following parameters:
// String destinationAddress : The address destination of the SMS
// String scAddress: The address of the SMS center to use (if null, the
default one is used)
// ArrayList<String> text: The body of the message split in a list
// ArrayList<PendingIntent> sentIntent: The list of Intent to
follow the transfer of each message part
// ArrayList<PendingIntent> deliveryIntent: The list of Intent to
follow the delivery of each message part
smsManager.sendMultipartTextMessage(phoneNumber,
null,
smsBodies, null,
null);
}else{
//no need to split your message
// send an SMS with no following with the following parameters:
// String destinationAddress : The address destination of the SMS
// String scAddress: The address of the SMS center to use (if null, the
default one is used)
// String text: The body of the message
// PendingIntent sentIntent: The Intent to follow the transfer
// PendingIntent deliveryIntent: The Intent to follow the delivery
smsManager.sendTextMessage(phoneNumber,
null,
smsBody, null,
null);
}
Dans le cas d’un suivi du transfert et de la livraison, un ensemble d’éléments sont à définir. Ces éléments sont à définir et pour le suivi de transfert et pour le suivi de la livraison, vous pouvez implémenter l’un ou l’autre ou les deux. Ces éléments sont :
· Le nom de l’intention que vous écouterez,
· L’intention elle-même
· Le PendingIntent associé à votre intention
· Le filtre d’intention pour pouvoir s’enregistrer comme écouteur de votre intention,
· Et enfin, le BroadCastReceiver qui vous permettra d’écouter cette intention
Pour des raisons de synthèse, nous avons regroupé le code au sein d’une même méthode, mais il est évident que vous pouvez définir votre propre classe d’écoute (BroadCastReceiver) dans une classe indépendante.
Ce qui donne :
Dans le
fichier manifest.xml :
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
Dans le fichier Java :
/*****************************************************************************************/
/** Sending SMS manually with Lookup ************************************************/
/*****************************************************************************************/
// Sending an SMS using the transfer and delivery follow up:
// ---------------------------------------------------------
// Define the transfer follower
// ----------------------------
// First define your Intent name
final
String transferFollowerIntentName = "Tr_Fo_In_Na";
// Define Intent to follow the transfer
Intent
transferFollowerIntent = new Intent(transferFollowerIntentName);
// Define the PendingIntent associated
PendingIntent
transferFollowerPendingIntent = PendingIntent.getBroadcast(
getApplicationContext(),// Application context could be this in an activity
0,//
requestCode
transferFollowerIntent,// intent
0);//
flags
// Define the Intent filter
IntentFilter
transferFollowerIntentFilter = new IntentFilter(transferFollowerIntentName);
// Define and bind the Broadcast receiver associated to the intent
BroadcastReceiver
transferFollowerBroadcastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
switch
(getResultCode()) {
case
Activity.RESULT_OK:
// The result is ok
case
SmsManager.RESULT_ERROR_GENERIC_FAILURE:
// A generic error occured
case
SmsManager.RESULT_ERROR_RADIO_OFF:
// The cell network is off
case
SmsManager.RESULT_ERROR_NULL_PDU:
// An error with the Protocol Description Unit occured
break;
}
}
};
// Bind the BroadcastReceiver to the Intent
registerReceiver(transferFollowerBroadcastReceiver,
transferFollowerIntentFilter);
// Define the Delivery follower
// ----------------------------
// First define your Intent name
final
String deliveryFollowerIntentName = "De_Fo_In_Na";
// Define Intent to follow the transfer
Intent
deliveryFollowerIntent = new Intent(deliveryFollowerIntentName);
// Define the PendingIntent associated
PendingIntent
deliveryFollowerPendingIntent = PendingIntent.getBroadcast(
getApplicationContext(),// Application context could be this in an activity
0,//
requestCode
deliveryFollowerIntent,// intent
0);//
flags
// Define the Intent filter
IntentFilter
deliveryFollowerIntentFilter = new IntentFilter(deliveryFollowerIntentName);
// Define and bind the Broadcast receiver associated to the intent
BroadcastReceiver
deliveryFollowerBroadcastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
// The SMS has been delivered: Do
something
// The raw pdu of the status report is
in the extended data ("pdu").
}
};
// Bind the BroadcastReceiver to the Intent
registerReceiver(deliveryFollowerBroadcastReceiver,
deliveryFollowerIntentFilter);
// THEN send your SMS
if(smsBody.length()<160){
smsManager.sendTextMessage(phoneNumber,
null,
smsBody, transferFollowerPendingIntent,
deliveryFollowerPendingIntent);
}else{
//You need to split it:
ArrayList<String>
smsBodies=smsManager.divideMessage(smsBody);
//You need to declare several Pending Intent one for each smsBody part
//To follow transfer and delivery
ArrayList<PendingIntent>
deliveryFollowerPendingIntents=new ArrayList<PendingIntent>();
ArrayList<PendingIntent>
transferFollowerPendingIntents=new ArrayList<PendingIntent>();
for(int
i=0;i<smsBodies.size();i++){
deliveryFollowerPendingIntents.add(deliveryFollowerPendingIntent);
transferFollowerPendingIntents.add(transferFollowerPendingIntent);
}
//Send your sms:
smsManager.sendMultipartTextMessage(phoneNumber,
null,
smsBodies,
transferFollowerPendingIntents,
deliveryFollowerPendingIntents);
}
L’écoute de SMS arrivants ressemble beaucoup à l’écoute du transfert et de la réception lorsque vous envoyer des SMS. Le principe est identique et s’appuie sur l’écoute d’intention. Seul le traitement diffère.
Dans le manifest.xml :
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
Dans le fichier Java :
/*****************************************************************************************/
/**
Listen for incoming SMS
***************************************************************/
/** Needs to ask the permission RECEIVE_SMS in your manifest.xml
*****************************/
/*****************************************************************************************/
//Define the SMS_RECEIVE's INTENT NAME
final
String SMS_RECEIVE_INTENT_NAME="android.provider.telephony.SMS_RECEIVER";
// Define the Broadcast receiver associated to the RECEIVE SMS intent
BroadcastReceiver
incomingSmsBroadcastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
//For exemple rebuild the messages
received:
//Check you receive the right intent
if(intent.getAction().equals(SMS_RECEIVE_INTENT_NAME)){
//Retrieve the bundle that handles the Messages
Bundle
bundle=intent.getExtras();
if(bundle!=null){
//Retrieve the data store in the SMS
Object[] pdus=(Object[])bundle.get("pdus");
//Declare the associated SMS Messages
SmsMessage[] smsMessages=new SmsMessage[pdus.length];
//Rebuild your SMS Messages
for(int
i=0;i<pdus.length;i++){
smsMessages[i]=SmsMessage.createFromPdu((byte[])pdus[i]);
}
//Parse your SMS Message
SmsMessage currentMessage;
String body,from;
for(int
i=0;i<smsMessages.length;i++){
currentMessage=smsMessages[i];
body=currentMessage.getDisplayMessageBody();
from=currentMessage.getDisplayOriginatingAddress();
currentMessage.getTimestampMillis();
}
}
}
}
};
//Define the Intent Filter
IntentFilter
smsReceiverIntentFilter= new IntentFilter(SMS_RECEIVE_INTENT_NAME);
//And Bind the BroadcastReciever to that IntentFilter
registerReceiver(incomingSmsBroadcastReceiver, smsReceiverIntentFilter);