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
Les informations associées au réseau wifi sont :
·
Son état
(Enable, enabling, disabling, disabled, unknown)
· Les informations sur sa connexion (son adresse mac, IP, sa vitesse, le ssid du réseau et la force du signal)
Ensuite vous pouvez vous abonner à l’écoute des changements :
· Des états de la connexion
· Des états du supplicant (plus fin que les états de la connexion) qui est l’état de l’établissement de la connexion à un point d’accès.
· De la valeur du RSSI, la force du signal
· De l’état de la connexion wifi (perte ou récupération de la connexion)
· De l’identifiant du réseau
Il ne faut pas écouter tout ces états, certains s’incluant les uns les autres, d’autres se simplifiant. Nous montrons dans l’exemple ci-dessous comment utiliser et écouter tous ces changements d’états, vous laissant le choix de l’évènement à écouter.
/** * The Wifi Manager */
WifiManager
wifiManager;
/* * (non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// First Instanciate the Wifi and Connectivity Managers:
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
// Browse wifi networks and retrieve their parameters
browseWifiNetworks();
}
/************************************************************************************/
/** Browsing the WIFI networks
**********************************************************/
/************************************************************************************/
/** * Browse wifi network and detect their parameters */
private void
browseWifiNetworks() {
// Managing wifi state
wifiManager.isWifiEnabled();
switch (wifiManager.getWifiState())
{
case
WifiManager.WIFI_STATE_ENABLING:
case
WifiManager.WIFI_STATE_ENABLED:
case
WifiManager.WIFI_STATE_DISABLING:
case
WifiManager.WIFI_STATE_DISABLED:
case
WifiManager.WIFI_STATE_UNKNOWN:
break;
}
// Retrieveing active wifi informations
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
// Basic Service Set Identifier is null if no connection available
if
(wifiInfo.getBSSID() != null) {
String macAdress
= wifiInfo.getMacAddress();
int
ipAddress = wifiInfo.getIpAddress();
int
linkSpeed = wifiInfo.getLinkSpeed();//
in WifiInfo.LINK_SPEED_UNITS
String ssid =
wifiInfo.getSSID();
int
signalStrenght = WifiManager.calculateSignalLevel(wifiInfo.getRssi(),
5);
}
// Listening for WIFI changes
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.WIFI_STATE_CHANGED_ACTION));
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION));
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.RSSI_CHANGED_ACTION));
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.NETWORK_STATE_CHANGED_ACTION));
registerReceiver(wifiChangesBroadCastReceiver, new IntentFilter(
WifiManager.NETWORK_IDS_CHANGED_ACTION));
}
/** Listening for WIFI changes */
/** ---------------------------------- */
/** * Define the brodcast receiver that listen for connectivty changes
*/
private
BroadcastReceiver wifiChangesBroadCastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
//
insure you are listening for the right intent
// The WIFI
State changed listening:Wi-Fi has been enabled, disabled, enabling,
// disabling, or
unknown
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
// Check the current Wifi Stat (you can
also retrieve the EXTRA_WIFI_PREVIOUS_STATE
switch
(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN)) {
case
WifiManager.WIFI_STATE_ENABLING:// Do something
case
WifiManager.WIFI_STATE_ENABLED:// Do something
case
WifiManager.WIFI_STATE_DISABLING:// Do something
case
WifiManager.WIFI_STATE_DISABLED:// Do something
case
WifiManager.WIFI_STATE_UNKNOWN:// Do something
break;
}
}
// The
Supplicant State changed:the state of establishing a connection to an access
// point has
changed
else if
(action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
SupplicantState supplicantstate = (SupplicantState) intent
.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
switch
(supplicantstate) {
case
UNINITIALIZED:
// no wpa_supplicant
case
SCANNING:
// Scanning for a network
case
ASSOCIATING:
// Trying to associate with a BSS/SSID.
case
ASSOCIATED:
// Association completed.
This state is entered when the driver
reports that association has been successfully completed with an AP. If IEEE
802.1X is used (with or without WPA/WPA2), wpa_supplicant remains in this
state until the IEEE 802.1X/EAPOL
authentication has been completed.
case
COMPLETED:
// All authentication completed.
This state is entered when the full authentication
process is completed. In case of WPA2, this happens when the 4-Way Handshake is
successfully completed. With WPA, this state is entered after the Group Key
Handshake; with IEEE 802.1X (non-WPA)
connection is completed after dynamic keys arereceived (or if not used, after
the EAP authentication has been completed). With static WEP keys and plaintext
connections, this state is entered when an association has been completed. This state indicates that the supplicant has
completed its processing for the association phase and that data connection is
fully configured. Note, however, that there may not be any IP address associated
with the connection yet. Typically, a DHCP request needs to be sent at this
point to obtain an address.
case
FOUR_WAY_HANDSHAKE:
// WPA 4-Way Key Handshake in progress.
This state is entered when WPA/WPA2
4-Way Handshake is started. In case of WPA-PSK, this happens when
receiving the first EAPOL-Key frame after association. In case of WPA-EAP, this
state is entered when the IEEE 802.1X/EAPOL authentication has been
completed.
case
GROUP_HANDSHAKE:
// WPA Group Key Handshake in progress.
This state is entered when 4-Way Key
Handshake has been completed (i.e., when the supplicant sends out message 4/4)
and when Group Key rekeying is started by the AP (i.e., when supplicant
receives message 1/2).
case
DORMANT:
// An Android-added state that is
reported when a client issues an explicit DISCONNECT
command.
In such a case, the supplicant is not
only dissociated from the current access point (as for the DISCONNECTED state
above), but it also does not attempt to connect to any access point until a
RECONNECT or REASSOCIATE command is
issued by the client.
case
DISCONNECTED:
// This state indicates that client is
not associated, but is likely to start looking for an access point. This state
is entered when a connection is lost.
case
INACTIVE:
// Inactive state (wpa_supplicant
disabled).
This state is entered if there are no
enabled networks in the configuration. wpa_supplicant is
not trying to associate with a new network and external interaction (e.g.,
ctrl_iface call to add or enable a network) is needed to start association
case
INVALID:
// A pseudo-state that should normally
never be seen.
break;
}
// Detect a supplicant error
if
(intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0) = =
WifiManager.ERROR_AUTHENTICATING)
{
// Do something
}
}
// A connection
to the supplicant has been established (and it is now possible to
// perform Wi-Fi
operations) or the connection to the supplicant has been lost
else if
(action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
// The lookup key for a boolean that
indicates whether a connection to the
// supplicant daemon has been gained or
lost. true means a connection now exists.
if
(intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
// A connection now exist, do something
} else
{
// A connection has been lost, do
something
}
}
// The RSSI
(signal strength) has changed.
else if
(action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
int
newRSSI = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, 0);
// handle the newRSSI identification key
(the network changed its id)
}
// The state of
Wi-Fi connectivity has changed
else if
(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
// Do something with this new Network
information
if
(networkInfo.isConnected() && intent.hasExtra(WifiManager.EXTRA_BSSID)) {
// The lookup key for a String giving
the BSSID of the access point to which we
// are connected.
String newBSSID = intent.getStringExtra(WifiManager.EXTRA_BSSID);
}
}
// The network
IDs of the configured networks could have changed
else if
(action.equals(WifiManager.NETWORK_IDS_CHANGED_ACTION)) {
// You should update your access point
}
}
};
Pour scanner les Hot Spots Wifi, il faut d’abord enregistrer un BroadCastReceiver comme écouteur de l’intention SCAN_RESULTS_AVAILABLE_ACTION et récupérer la liste des nouveaux réseaux trouvés dans l’attribut scanResults du WifiManager. Quand l’évènement est écouté par le BroadCastReceiver, cette liste est chargée dans le WifiManager.
La liste des ScanResult peut-être parcourue pour obtenir des informations sur les nouveaux réseaux (BSSID, SSID, Capabilities, fréquence du signal et force de celui-ci). Elle peut aussi être utilisée pour enrichir la liste des réseaux Wifi disponible pour l’établissement d’une connexion. Les réseaux disponibles étant enregistrés en tant qu’instance de l’objet WifiConfiguration et peuvent être obtenus par la méthode getConfiguredNetworks du WifiManager.
Pour se connecter à l’une de ces configurations (et donc à l’un de ces réseaux) il faut utiliser la méthode enableNetwork du WifiManager.
/** * The Wifi Manager */
WifiManager
wifiManager;
/* * (non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
First Instanciate the Wifi and Connectivity Managers:
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
//
Browse wifi networks and retrieve their parameters
browseWifiNetworks();
}
/*****************************************************************************************/
/** Browsing the WIFI networks
**********************************************************/
/*****************************************************************************************/
/** * Browse wifi network and detect their parameters */
private void
browseWifiNetworks() {
//
Scan the hotspot around
registerWifiScannerBroadcastReceiver();
wifiManager.startScan();
//
Set the usage of a specific wifi network
connectToWifiSpot();
}
/** Scan the hotspot around */
/** ----------------------------- */
/** * Register the broadcast to listen to End of Wifi Scan */
private void
registerWifiScannerBroadcastReceiver() {
registerReceiver(wifiScannerBroadCastReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
/** * Define the brodcast receiver that listen for connectivty changes
*/
private
BroadcastReceiver wifiScannerBroadCastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
//
insure you are listening for the right intent
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
//
The scan is over, you can browse the results
manageWifiScanResults();
}
}
};
/** * Manage the Results of the Wifi Scan */
private void
manageWifiScanResults() {
List<ScanResult> scanResults = wifiManager.getScanResults();
List<String> results = new
ArrayList<String>();
for (ScanResult scanResult : scanResults) {
//
adress of the access point
String bssid = scanResult.BSSID;
//
Describes the authentication, key management, and encryption schemes supported
by the
//
access point.
String capabilities = scanResult.capabilities;
if (capabilities.contains("WEP")) { //
WEP security
} else if (capabilities.contains("WAP")) { // WAP
security
} else if (capabilities.contains("WAP2")) { //
WaP2 security
} else if (capabilities.contains("Open")) { //
No security
} else if (capabilities.contains("PSK")) { //
PSK ??
} else if (capabilities.contains("EAP")) { //
EAP for entreprise
} else { //
No security
}
//
The frequency in MHz of the channel over which the client is communicating with
the
//
access point.
int frequency = scanResult.frequency;
//
The network name.
String ssid = scanResult.SSID;
//
The detected signal level in dBm.
int level = scanResult.level;
results.add(String .format(
"New Wifi Spot : (SSID =%s,
BSSID=%s, Capabilities = %s, frequency %i, level %i)",
ssid, bssid, capabilities, frequency,
level));
}
addResultsToConfiguredNetworks(scanResults);
}
/** * Add the hotSpot found in the WifiConfiguration *
* @param
results the list of ScanResult to add to the WifiConfiguration */
private void
addResultsToConfiguredNetworks(List<ScanResult> results) {
//
List of already configured hotspot
List<WifiConfiguration>
wifiConfigurations = wifiManager.getConfiguredNetworks();
//
List of ssid of the already configured hotspot
List<String> ssidConfigured = new
ArrayList<String>();
//
Fill that list with ssid of the already configured hotspot
for (WifiConfiguration wifiConfiguration :
wifiConfigurations) {
ssidConfigured.add(wifiConfiguration.SSID);
}
//
The new configuration to add built using ScanResult and the associated
networkId
WifiConfiguration newWifiConf;
int newNetworkId;
//
Browse the Scan result
for (ScanResult result : results) {
if (ssidConfigured.contains(result.SSID)) {
//
Do nothing hotSpot already configured
} else {
//
You can here ask the user if he wants to add the current ScanResult of the loop
//
if he agrees run the following lines, else skip them
//
Add this hot spot to the WifiConfiguration
newWifiConf = new
WifiConfiguration();
newWifiConf.BSSID = result.BSSID;
newWifiConf.SSID = result.SSID;
newWifiConf.hiddenSSID = false;
newWifiConf.priority = 1;
newNetworkId = wifiManager.addNetwork(newWifiConf);
if (newNetworkId < 0) {
Toast.makeText(this,
String.format("Unable to add SSID:%s", result.SSID),
Toast.LENGTH_LONG).show();
}
//
if you want to connect to a network use this id (newNetworkId)
//
cf the method connectTo WifiSpot
}
}
}
/** Connect to a hotspot around */
/** ----------------------------------- */
/** * Choose a random WifiConfiguration and connect to it */
private void
connectToWifiSpot() {
//
List of already configured hotspot
List<WifiConfiguration>
wifiConfigurations = wifiManager.getConfiguredNetworks();
if (!wifiConfigurations.isEmpty()) {
//Set the disable All
others (to be sure that only your network will be used for connection as your
network
//will be the only one
enabled)
boolean disableOthers = true;
//Select
the network you want to connect to using the WifiConfiguration
WifiConfiguration selectedWifiConf
= wifiConfigurations.get(0);
//Ask
for enabling this network connection
Boolean success = wifiManager.enableNetwork(selectedWifiConf.networkId,
disableOthers);
//test
if you request succeded
if (!success) {
Toast.makeText(
this,
String.format("Unable to enable the network (SSID:%s,
networkId:%i)",
selectedWifiConf.SSID,
selectedWifiConf.networkId),
Toast.LENGTH_LONG).show();
} }
}