Android,
A Complete Course, From
Basics to Enterprise Edition
Android, A Complete Course, From Basics to Enterprise Edition
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
Pour une communication Bluetooth, il faut suivre les étapes suivantes :
· Demander les permissions BLUETOOTH et BLUETOOT_ADMIN
· Activer le Bluetooth de l’appareil
· Découvrir les périphériques Bluetooth alentour :
o Rendre visible votre appareil pour la phase de découverte
o Lancer le processus de découverte
o Découvrir les périphériques Bluetooth alentour
· Ouvrir une communication Bluetooth :
o Ecouter les demandes de connexion avec un listener socket server
o Ecouter les demandes de connexion avec une connexion cliente
o Se connecter en tant que serveur ou en tant que client
· Transmettre les données
Si vous voulez utiliser le service Bluetooth il vous faut demander la permission dans votre manifest.xml :
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
Il y a quatre éléments qui permettent de manipuler les communications Bluetooth :
· Le Bluetooth Adapter est l’adaptateur de votre Android, il permet d’accéder aux paramètres de votre Bluetooth (son nom, son adresse, son état (Actif ou pas), sa découvrabilité, son mode de scan)
· Le Bluetooth Device est un autre appareil Bluetooth, il peut être appareillé, connecté ou pas.
· Le Bluetooth Socket qui est le connecteur au réseau Bluetooth qui est utilisé pour la communication.
· L’UUID (Universal Unique Identifier) de votre application qui est un identifiant unique de votre application en tant que terminal Bluetooth. Vous pouvez aller en générer un sur http://www.famkruithof.net/uuid/uuidgen.
Pour connaitre si votre appareil est équipé du Bluetooth et s’il est activer, il faut :
· Récupérer le Bluetooth Adapter de l’appareil, s’il n’existe pas, l’appareil n’a pas le Bluetooth.
· Ensuite il faut lancer l’activité qui demande à l’utilisateur d’activer le Bluetooth
· Et écouter la réponse de l’utilisateur
Le code associé est le suivant :
/** * The Bluetooth Adapter */
private
BluetoothAdapter bluetoothAdapter;
/** * The unique Request code send with the Intent
BluetoothAdapter.ACTION_REQUEST_ENABLE when
* starting the activty to enable
bluetooth */
private final int REQUEST_ENABLE_BT =
11021974;
/** * A boolean to know if BlueTooth is enabled */
boolean blueToothEnable = false;
/* * (non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// settingUpBluetooth
if
(settingUpBluetooth()) {
// Then Enable bluetooth
enableBluetooth();
// And listen for state changed
registerStateBroadcastReceiver();
}
/***************************************************************************************/
/** ENABLE BlueTooth
*******************************************************************/
/***************************************************************************************/
/** * Instanciate the bluetoothadapter *
* @return
true is device support bluetooth
*/
private boolean
settingUpBluetooth() {
boolean
isBluetooth = false;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
// the device supports BlueTooth
isBluetooth = true;
}
return
isBluetooth;
}
/** * Test if bluetooth is enabled, If the Bluetooth is not enable, then
ask the user to set it enable */
private void
enableBluetooth() {
blueToothEnable = bluetoothAdapter.isEnabled();
if (!blueToothEnable) {
//Ask
the user to set enable the Bluetooth
Intent
enableBtIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
REQUEST_ENABLE_BT);
}
}
/* * (non-Javadoc) @see android.app.Activity#onActivityResult(int, int,
android.content.Intent) */
@Override
protected void
onActivityResult(int
requestCode, int
resultCode, Intent data) {
// The Activty ACTION_REQUEST_ENABLE returns
if (requestCode == REQUEST_ENABLE_BT) {
switch
(resultCode) {
case
Activity.RESULT_OK:
// The result is ok
blueToothEnable = true;
break;
case
Activity.RESULT_CANCELED:
default:
// the result is KO
blueToothEnable = false;
break;
}
}
}
Il peut être utile d’écouter l’état de l’appareil.
Le code suivant montre comment effectuer cette écoute :
/****************************************************************************************/
/** Listening for BlueTooth state Change
*************************************************/
/*****************************************************************************************/
/** * Define the brodcast receiver that listen for state changes */
private
BroadcastReceiver bluetoothStateBroadCastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
// Find the cuurent state (you can also call
EXTRA_PREVIOUS_STATE for the previous
// state)
int state
= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
switch
(state) {
case
(BluetoothAdapter.STATE_TURNING_ON):// Do something
case
(BluetoothAdapter.STATE_ON):// Do something
case
(BluetoothAdapter.STATE_TURNING_OFF):// Do something
case
(BluetoothAdapter.STATE_OFF):// Do something
default:// Do something
break;
}
}
};
/**
* To be call when setting up the
Bluetooth
*/
private void
registerStateBroadcastReceiver() {
// register the previous BroadCast associated to the Intent Action State
Changed
registerReceiver(bluetoothStateBroadCastReceiver, new IntentFilter(
BluetoothAdapter.ACTION_STATE_CHANGED));
}
Maintenant que le Bluetooth est actif il faut pouvoir vérifier si l’appareil auquel on souhaite se connecter est autour. Pour cela, il faut d’abord regarder les appareils déjà appareillés au votre et si l’appareil cible n’y est pas, il faut lancer le processus de découverte des appareils Bluetooth alentour.
Le processus de découverte se déroule ainsi :
· Vérifier l’état du ScanMode de l’appareil (qui peut être découvrable, connectable, découvrable et connectable ou non connectable)
· Si cet état n’est pas découvrable, il faut activer la capacité de l’appareil à être découvert. Pour cela il faut lancer l’activité d’activation de la découvrabilité et soit :
o écouter le résultat obtenu dans onActivityResult
o écouter directement le changement d’état du Scan mode de l’appareil au moyen d’un BroadCast
o écouter les évènements Activity_DISCOVERY started et finished
· Quand la découvrabilité est activée, il faut écouter l’événement de découverte d’un nouvel appareil au moyen d’un BroadCast adéquat. A chaque nouvel appareil découvert, il faut stocker cet appareil.
· Quand le processus est terminé, il ne reste plus qu’a choisir l’appareil auquel se connecter (soit laisser l’utilisateur le choisir).
/** * The Bluetooth Adapter */
private
BluetoothAdapter bluetoothAdapter;
/** * The map that store the name and the associated blueTooth device */
private
HashMap<String, BluetoothDevice> blueToothDevice = new HashMap<String, BluetoothDevice>();
/** * The unique Request code send with the Intent BluetoothAdapter.ACTION_DISCOVERABLE
when
* starting the activty to
discover bluetooth */
private final int REQUEST_DISCOVERABLE
= 13121974;
/** * A boolean to know if BlueTooth is enabled */
boolean blueToothEnable = false;
/** * The boolean to know is the device is discoverable */
boolean isDiscoverable = false;
/** * The duration of the discoverable mode */
int discoverableTimeRemaining = 0;
/* * (non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We suppose the Bluetooth is enable
if (blueToothEnable) {
// read bluetooth information
String adress = bluetoothAdapter.getAddress();
String name = bluetoothAdapter.getName();
// First check if the device is already paired with
you:
Set<BluetoothDevice>
pairedDevices = bluetoothAdapter.getBondedDevices();
// If there are paired devices
if
(pairedDevices.size() > 0) {
// Loop through paired devices
for
(BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to
show in a ListView
ArrayAdapter
mArrayAdapter = new
ArrayAdapter(this,
R.layout.list);
mArrayAdapter.add(device.getName()
+ "\n" + device.getAddress());
// Then ask the user if the device he wants to connect
to is in the list
// CF GUI chapter for that
}
}
// We suppose the user hasn't found the desired device
// And then we need to discover it
manageDiscovering();
// register the Discoverability state changed
registerDiscoverabilityBroadcastReceiver();
registerDiscoveryBroadcastReceiver();
// Now we suppose the scanMode is
SCAN_MODE_CONNECTABLE_DISCOVERABLE
startListeningNewBlueToothDevice();
}
}
/* * (non-Javadoc) * * @see
android.app.Activity#onPause() */
@Override
protected void
onPause() {
super.onPause();
// Unregister elements
// unregister the broadcast that listen for bluetooth state changed
unregisterReceiver(bluetoothStateBroadCastReceiver);
// unregister the broadcast that listen for bluetooth discoverability
state changed
unregisterReceiver(bluetoothDiscoverabilityBroadCastReceiver);
// unregister the broacastreciever that are used during the discovery
phase
unregisterDiscoveryBroadcastReceiver();
//Stop listening for new device finding
stopListeningNewBlueToothDevice();
}
/***************************************************************************************/
/** Managing Discovery
*******************************************************************/
/**************************************************************************************/
/** * Manage the discovery processus */
private void
manageDiscovering() {
// To know if we need to ask for settting the mode Discovery on
boolean
askForDiscovery = false;
// First you need to manage the visibility of the device:
switch (bluetoothAdapter.getScanMode())
{
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
isDiscoverable = true;
break;
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE:
askForDiscovery =
true;
break;
case
BluetoothAdapter.SCAN_MODE_NONE:
askForDiscovery =
true;
break;
}
// Ask for discovery
if (askForDiscovery)
{
startActivityForResult(new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE),
REQUEST_DISCOVERABLE);
}
}
/* * (non-Javadoc) * * @see
android.app.Activity#onActivityResult(int, int, android.content.Intent) */
@Override
protected void
onActivityResult(int
requestCode, int
resultCode, Intent data) {
// The Activty ACTION_REQUEST_ENABLE returns
if (requestCode == REQUEST_ENABLE_BT) {
//Nothing to deal with discovery process
}
// The Activity Action_REQUEST_DISCOVERABLE
else if (requestCode == REQUEST_DISCOVERABLE)
{
// the resultCode is the time during the device is
discoverable
if (resultCode >
0) {
isDiscoverable = true;
discoverableTimeRemaining = resultCode;
// Start listening for new devices finding
startListeningNewBlueToothDevice();
} else {
isDiscoverable = false;
// Do a smartest stuff:Stop listening for new device
finding
stopListeningNewBlueToothDevice();
}
}
}
/**************************************************************************************/
/** Managing Discovery ******************************************************************/
/**************************************************************************************/
/** * Manage the discovery processus */
private void
manageDiscovering() {
// To know if we need to ask for settting the mode Discovery on
boolean
askForDiscovery = false;
// First you need to manage the visibility of the device:
switch (bluetoothAdapter.getScanMode())
{
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
isDiscoverable = true;
break;
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE:
askForDiscovery =
true;
break;
case
BluetoothAdapter.SCAN_MODE_NONE:
askForDiscovery =
true;
break;
}
// Ask for discovery
if (askForDiscovery)
{
startActivityForResult(new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE),
REQUEST_DISCOVERABLE);
}
}
/** Listening for BlueTooth
Discoverability state change **/
/** ---------------------------------------------------------------- **/
/** * Define the brodcast receiver that listen for ScanMode changes */
private
BroadcastReceiver bluetoothDiscoverabilityBroadCastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
// Find the cuurent scanMode (you can also call EXTRA_PREVIOUS_SCAN_MODE
for the
// previous state)
int
scanMode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1);
switch
(scanMode) {
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
// Start listening for new devices finding
startListeningNewBlueToothDevice();
break;
case
BluetoothAdapter.SCAN_MODE_CONNECTABLE:
case
BluetoothAdapter.SCAN_MODE_NONE:
// Do a smartest stuff:Stop listening for new device
finding
stopListeningNewBlueToothDevice();
break;
}
}
};
/** * To be call when setting up the Bluetooth */
private void
registerDiscoverabilityBroadcastReceiver() {
// register the previous BroadCast associated to the Intent Action State
Changed
registerReceiver(bluetoothDiscoverabilityBroadCastReceiver, new IntentFilter(
BluetoothAdapter.ACTION_SCAN_MODE_CHANGED));
}
/** Listening for BlueTooth Discovery
Process Begin and End **/
/** ---------------------------------------------------------------------- **/
/** * Define the brodcast receiver that listen for Start and End of the
discovery process */
private
BroadcastReceiver bluetoothDiscoveryBroadCastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
// The Start Discovery Process
if
(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
// Do a smart stuff:Start listening for new devices
finding
startListeningNewBlueToothDevice();
}
// The Stop Discovery Process
else if
(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
// Do a smartest stuff:Stop listening for new device
finding
stopListeningNewBlueToothDevice();
}
}
};
/** * To be call when discovering others device */
private void
registerDiscoveryBroadcastReceiver() {
//Listen for begin and end of the discoverability process
registerReceiver(bluetoothDiscoveryBroadCastReceiver, new IntentFilter(
BluetoothAdapter.ACTION_DISCOVERY_STARTED));
registerReceiver(bluetoothDiscoveryBroadCastReceiver, new IntentFilter(
BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
}
/** * To call when activity pause or leave */
private void
unregisterDiscoveryBroadcastReceiver() {
// unregister the previous Broadcast receiver
unregisterReceiver(bluetoothDiscoveryBroadCastReceiver);
unregisterReceiver(bluetoothDiscoveryBroadCastReceiver);
unregisterReceiver(newBluetoothFoundBroadCastReceiver);
}
/** Listening for new BlueTooth Devices
finding **/
/** ---------------------------------------------------------- **/
/** * Define the brodcast receiver that listen for new Bluetooth Devices
Found */
private
BroadcastReceiver newBluetoothFoundBroadCastReceiver = new BroadcastReceiver() {
@Override
public void
onReceive(Context context, Intent intent) {
// retireve the device name
String deviceName
= intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
// retrieve the devicen itself
BluetoothDevice
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// store them
blueToothDevice.put(deviceName,
device);
// for fun tell it to the user
Toast.makeText(getApplicationContext(),
"New Device found : " + deviceName,
Toast.LENGTH_SHORT).show();
}
};
/** * Start listening for new Device found */
private void
startListeningNewBlueToothDevice(){
registerReceiver(newBluetoothFoundBroadCastReceiver, new IntentFilter(
BluetoothDevice.ACTION_FOUND));
}
/** * Stop listening for new Device found */
private void
stopListeningNewBlueToothDevice(){
unregisterReceiver(newBluetoothFoundBroadCastReceiver);
}
Pour se connecter à un appareil et communiquer avec lui, il faut toujours que ces opérations soient effectuées dans des threads séparées au risque de voir votre IHM tomber. Il faut ainsi utiliser le pattern Thread – Handler d’Android.
Ensuite, il faut implémenter les deux types d’ouverture de connexion, l’une en tant que serveur, l’autre en tant que client pour pouvoir ouvrir la connexion dans tous les cas. Quand la connexion est ouverte, il ne reste plus qu’à lancer la thread de communication qui dialoguera avec le Handler. Le Handler aura à charge la mise à jour de l’IHM.
Le code ci-dessous explique ce processus.
/** * The Bluetooth Adapter */
private
BluetoothAdapter bluetoothAdapter;
/** * The BlueTooth socket */
private
BluetoothSocket bluetoothSocket;
/** * The map that store the name and the associated blueTooth device */
private
HashMap<String, BluetoothDevice> blueToothDevice = new HashMap<String, BluetoothDevice>();
/** * The unique UUID of the application to etablish a connection */
private static final UUID MY_UUID =
UUID.fromString("fa87c0e0-dgef-11de-8a39-0800200c9a66");
/** * The unique bluetooth server name use for connection */
private static final
String MY_BLUETOOTH_SERVER_NAME = "blueToothServerName";
/** * The handler that update the UI using data thrown by the
ConnectedThread */
Handler
myHandlerSocketConnected;
/** * The message.isWhat launched to the handler */
private final int MESSAGE_READ=4112008;
/** * The thread that manage the data exchange between the both device
*/
ConnectedThread
connectedThread;
/* * (non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
We suppose the device we want to talk with is found
//
Here two cases, we act as a server or as a client
//
But in reality, you have cover those 2 cases by implementing the both
//Initialise
the Handler that will listen to the connection exchange between the devices
myHandlerSocketConnected=new Handler(){
/*
(non-Javadoc)
* @see
android.os.Handler#handleMessage(android.os.Message)
*/
@Override
public void handleMessage(Message msg) {
byte[] readBuf = (byte[]) msg.obj;
//
construct a string from the valid bytes in the buffer
String readMessage = new
String(readBuf, 0, msg.arg1);
//update
the Gui with the message
//mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
}
};
//
Initialize the connection as a server
creatingServerSocketConnection();
//
Initialize the connection as a client:
creatingClientSocketConnection();
}
/****************************************************************************************/
/** Managing connection
*******************************************************************/
/****************************************************************************************/
/** * Create a server socket connection Acting like a server */
private void
creatingServerSocketConnection() {
try {
final BluetoothServerSocket bluetoothServerSocket = bluetoothAdapter.
listenUsingRfcommWithServiceRecord(MY_BLUETOOTH_SERVER_NAME, MY_UUID);
//
The thread that will listen for client to connect
Thread acceptServerThread = new
Thread() {
@Override
public void run() {
//
Keep listening until exception occurs or a socket is returned
while (true) {
try {
bluetoothSocket = bluetoothServerSocket.accept();
} catch (IOException e) {
break;
}
//
If a connection was accepted
if (bluetoothSocket != null) {
//
Do work to manage the connection (in a separate thread)
manageConnectedSocket();
try {
bluetoothSocket.close();
} catch (IOException e) {
}
break;
}
}
}
};
acceptServerThread.start();
} catch (IOException e) {
}
}
/** * Create a server socket connection Acting like a server */
private void
creatingClientSocketConnection() {
try {
//
find the device you want to connect to
BluetoothDevice bluetoothDevice = blueToothDevice.get("knowDeviceName");
//
Ask to connect to
final BluetoothSocket bluetoothClientSocket =
bluetoothDevice
.createRfcommSocketToServiceRecord(MY_UUID);
//
The thread that will listen for client to connect
Thread acceptClientThread = new
Thread() {
@Override
public void run() {
//
Cancel discovery because it will slow down the connection
bluetoothAdapter.cancelDiscovery();
try {
//
Connect the device through the socket. This will block
//
until it succeeds or throws an exception
bluetoothClientSocket.connect();
//Set
the bluetoothSocket with that socket
bluetoothSocket=bluetoothClientSocket;
} catch (IOException connectException) {
//
Unable to connect; close the socket and get out
try {
bluetoothSocket.close();
} catch (IOException closeException) {
}
return;
}
//
Do work to manage the connection (in a separate thread)
manageConnectedSocket();
}
};
acceptClientThread.start();
} catch (IOException e) {
}
}
/*************************************************************************************/
/** Managing data exchange
**************************************************************/
/*************************************************************************************/
/** * This method is called when a Bluetooth socket is created and the
attribute bluetoothSocket is instanciated*/
private void
manageConnectedSocket() {
//launch
the connected thread
connectedThread=new ConnectedThread();
connectedThread.start();
//And
if you want to talk somewhere in your code, just use the following lines:
String str="message";
connectedThread.write(str.getBytes());
}
/** * The thread that manage communication */
private class
ConnectedThread extends Thread {
/** * The input stream from the socket */
private final InputStream inputSocketStream;
/** * The output stream from the socket */
private final OutputStream outputSocketStream;
/** Constructor
*/
public ConnectedThread() {
InputStream tmpIn = null;
OutputStream tmpOut = null;
//
Get the input and output streams, using temp objects because
//
member streams are final
try {
tmpIn = bluetoothSocket.getInputStream();
tmpOut = bluetoothSocket.getOutputStream();
} catch (IOException e) {
}
inputSocketStream = tmpIn;
outputSocketStream = tmpOut;
}
/*
(non-Javadoc) * @see
java.lang.Thread#run() */
public void run() {
byte[] buffer = new byte[1024]; //
buffer store for the stream
int bytes; //
bytes returned from read()
//
Keep listening to the InputStream until an exception occurs
while (true) {
try {
//
Read from the InputStream
bytes = inputSocketStream.read(buffer);
//
Send the obtained bytes to the UI Activity
myHandlerSocketConnected.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
/*
Call this from the main Activity to send data to the remote device */
public void write(byte[] bytes) {
try {
outputSocketStream.write(bytes);
} catch (IOException e) {
}
}
/*
Call this from the main Activity to shutdown the connection */
public void cancel() {
try {
bluetoothSocket.close();
} catch
(IOException e) {
}
}
}