Bonjour à tous. Depuis Gingerbread [citation nécessaire] (android 2.3.3) notre OS mobile préféré sait créer et gérer un point d'accès wifi (en anglais, Wifi Access Point aka AP). Il est possible d'activer cette fonctionnalité dans Paramètres > Sans fil et réseaux > Point d'accès et mobile > Point d'accès mobile.

Néanmoins, pour une raison qui m'est inconnue, il n'est pas possible − selon la documentation d'android − d'activer cette option par programmation. En effet, les méthodes du WifiManager qui gèrent l'activation et la configuration de l'AP sont cachées (annotation @hide spécifique à android).

Voici une première ébauche de classe contournant ce problème.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.developpez.android
 
import java.lang.reflect.Method;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
 
/**
 * This class provides Wifi Access Point basic functions.
 * 
 * This class needs the following permissions:<ul>
 * <li>CHANGE_WIFI_STATE;</li>
 * <li>ACCESS_WIFI_STATE.</li>
 * </ul>
 * @author Yankel Scialom
 * @todo Use {@code WifiLock} to prevent the WiFi radio to turn
 * off when the user has not used the device in a while.
 */
public class WifiApManager {
	private WifiManager wifiMan;
	protected Method setWifiApEnabledMethod, isWifiApEnabledMethod;
	protected final static int MAX_ITER = 10;
 
	/**
         * Creates a new WifiApManager from an instanced WifiManager.
         * @param wifiMan a WifiManager obtain by {@code (WifiManager) this.getSystemService(Context.WIFI_SERVICE)}.
         */
	public WifiApManager(WifiManager wifiMan) {
		this.wifiMan = wifiMan;
		getHiddenMethods();
	}
 
	/**
         * Since {@code WifiManager.setWifiApEnabled()} and
         * {@code WifiManager.setWifiApEnabledMethod()} are hidden
         * ({@literal @}hide), we need to bypass this restriction. This method
         * sets the {@code setWifiApEnabledMethod} and {@code isWifiApEnabledMethod}
         * private members to be called with {@link setWifiApEnabled()} and
         * {@link isWifiApEnabled()}.
         */
	private void getHiddenMethods() {
		try {
			setWifiApEnabledMethod = wifiMan.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
			isWifiApEnabledMethod = wifiMan.getClass().getMethod("isWifiApEnabled");
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}
 
	/**
         * Return whether WiFi Access Point is enabled or disabled.
         * @return {@code true} if WiFi Access Point is enabled
         * @see WifiManager#isWifiApEnabled()
         */
	public boolean isWifiApEnabled() {
		try {
			return (Boolean)isWifiApEnabledMethod.invoke(wifiMan);
		} catch (Exception e) {
			return false;
		}
	}
 
	/**
         * Return whether WiFi is enabled or disabled.
         * @return {@code true} if WiFi is enabled
         * @see WifiManager#isWifiEnabled()
         */
	public boolean isWifiEnabled() {
		return wifiMan.isWifiEnabled();
	}
 
	/**
         * Start AccessPoint mode with the specified
         * configuration. If the radio is already running in
         * AP mode, update the new configuration.
         * Note that starting in Access Point mode disables station
         * mode operation
         * @param conf SSID, security and channel details as
         *              part of WifiConfiguration;
         * @param enabled ignored.
         * @return {@code true} if the operation succeeds, {@code false} otherwise.
         */
	public boolean setWifiApEnabled(WifiConfiguration conf, boolean enabled) {
		try {
			return (Boolean) setWifiApEnabledMethod.invoke(wifiMan, conf, true);
		} catch (Exception e) {
			return false;
		}
	}
 
	/** Toggles the Wifi Access Point radio.<ul>
         * <li>If Access Point mode Wifi is enabled, this method disables it and returns;</li>
         * <li>if Station mode Wifi is enabled, this method enables the Access Point mode.</li>
         * </ul>
         * @param ssid The SSID of the Access Point.
         * @returns {@code true} if the operation succeeds, {@code false} otherwise.
         */
	public boolean toggleWifi(String ssid) {
		// WifiConfiguration creation:
		WifiConfiguration conf = new WifiConfiguration();
		conf.SSID = ssid;
		conf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
 
		// If AP Wifi is enabled, disables it and returns:
		if(isWifiApEnabled()) {
			//setWifiApEnabled(null, false); Won't work, see two further lines
			wifiMan.setWifiEnabled(true);
			wifiMan.setWifiEnabled(false);
			int maxIter = MAX_ITER;
			while (isWifiApEnabled() && maxIter-- >= 0) {
				try {Thread.sleep(500);} catch (Exception e) {}
			}
			return isWifiApEnabled();
		}
 
		// If standard Wifi is enabled, disables it:
		if (isWifiEnabled()) {
			if (wifiMan.setWifiEnabled(false)) {
				int maxIter = MAX_ITER;
				while (wifiMan.isWifiEnabled() && maxIter-- >= 0) {
					try {Thread.sleep(500);} catch (Exception e) {}
				}
			}
			if (isWifiEnabled()) {
				return false;
			}
		}
 
		// Enables AP Wifi
		try {
			if (! setWifiApEnabled(conf, true)) {
				System.out.println("setWifiApEnabledMethod failed.");
				return false;
			}
			int maxIter = MAX_ITER;
			while (! isWifiApEnabled() && maxIter-- > 0) {
				try {Thread.sleep(500);} catch (Exception e) {}
			}
		} catch(Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
}
Cette classe s'instancie à partir du WifiManager obtenu par (WifiManager) this.getSystemService(Context.WIFI_SERVICE)this désigne l'activité (Activity) ou assimilé. À la création d'une instance de WifiApManager, les méthodes publiques (mais cachées) setWifiApEnabled et isWifiApEnabled de la classe WifiManager sont recherchées (grâce à getClass() et getMethod()).

* * *

Voici un exemple d'utilisation. L'activité suivante composée d'un ToggleButton active / désactive le Wifi en mode AP. Notez que la méthode proposée WifiApManager.toggleWifi(String ssid) n'est qu'un exemple d'utilisation des méthodes liées à la configuration de point d'accès ; il est tout à fait possible de créer un réseau plus complexe (voir WifiConfiguration et DhcpInfo). Notez aussi que ladite méthode est bloquante ; il est donc de bon usage de l'appeler dans un Thread différent, ou si l'on veut modifier l'interface graphique selon le résultat, dans une AsyncTask.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.developpez.android
 
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.ToggleButton;
 
public class MainActivity extends Activity implements OnClickListener {
 
	private WifiApManager wifiMan;
	private ToggleButton wifiButton;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		wifiMan = new WifiApManager((WifiManager) this.getSystemService(Context.WIFI_SERVICE));
		setContentView(R.layout.activity_main);
		makeUI();
	}
 
	private void makeUI() {
		LinearLayout subLayout = (LinearLayout) findViewById(R.id.subLayout);
		wifiButton = new ToggleButton(this);
		wifiButton.setTextOn("Disable Wifi");
		wifiButton.setTextOff("Enable AP Wifi");
		wifiButton.setChecked(wifiMan.isWifiApEnabled());
		wifiButton.setOnClickListener(this);
		subLayout.addView(wifiButton);
	}
 
 
 
	@Override
	public void onClick(View sender) {
		if (!wifiButton.equals(sender))
			return;
 
		AsyncTask<Object, Void, Boolean> task = new AsyncTask<Object, Void, Boolean>() {
			private ToggleButton bt;
			private WifiApManager wm;
 
			@Override
			protected Boolean doInBackground(Object... args) {
				bt = (ToggleButton) args[0];
				wm = (WifiApManager) args[1];
				return wm.toggleWifi("Developpez.com");
			}
			@Override
			protected void onPostExecute (Boolean result) {
				bt.setChecked(result.booleanValue());
				bt.setEnabled(true);
			}
		};
		wifiButton.setEnabled(false);
		task.execute(wifiButton, wifiMan);
	}
}
J'encourage les lecteurs de ce fil à tester et modifier le code ci dessus, ainsi qu'à partager leur avis à propos de cette implémentation et de son utilité.