1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.android;
17
18 import android.content.BroadcastReceiver;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.net.ConnectivityManager;
23 import android.net.NetworkInfo;
24 import android.net.wifi.WifiManager;
25 import org.fourthline.cling.UpnpServiceConfiguration;
26 import org.fourthline.cling.model.ModelUtil;
27 import org.fourthline.cling.protocol.ProtocolFactory;
28 import org.fourthline.cling.transport.Router;
29 import org.fourthline.cling.transport.RouterException;
30 import org.fourthline.cling.transport.RouterImpl;
31 import org.fourthline.cling.transport.spi.InitializationException;
32 import org.seamless.util.Exceptions;
33
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
36
37
38
39
40
41
42
43 public class AndroidRouter extends RouterImpl {
44
45 final private static Logger log = Logger.getLogger(Router.class.getName());
46
47 final private Context context;
48
49 final private WifiManager wifiManager;
50 protected WifiManager.MulticastLock multicastLock;
51 protected WifiManager.WifiLock wifiLock;
52 protected NetworkInfo networkInfo;
53 protected BroadcastReceiver broadcastReceiver;
54
55 public AndroidRouter(UpnpServiceConfiguration configuration,
56 ProtocolFactory protocolFactory,
57 Context context) throws InitializationException {
58 super(configuration, protocolFactory);
59
60 this.context = context;
61 this.wifiManager = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE));
62 this.networkInfo = NetworkUtils.getConnectedNetworkInfo(context);
63
64
65 if (!ModelUtil.ANDROID_EMULATOR) {
66 this.broadcastReceiver = createConnectivityBroadcastReceiver();
67 context.registerReceiver(broadcastReceiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
68 }
69 }
70
71 protected BroadcastReceiver createConnectivityBroadcastReceiver() {
72 return new ConnectivityBroadcastReceiver();
73 }
74
75 @Override
76 protected int getLockTimeoutMillis() {
77 return 15000;
78 }
79
80 @Override
81 public void shutdown() throws RouterException {
82 super.shutdown();
83 unregisterBroadcastReceiver();
84 }
85
86 @Override
87 public boolean enable() throws RouterException {
88 lock(writeLock);
89 try {
90 boolean enabled;
91 if ((enabled = super.enable())) {
92
93
94 if (isWifi()) {
95 setWiFiMulticastLock(true);
96 setWifiLock(true);
97 }
98 }
99 return enabled;
100 } finally {
101 unlock(writeLock);
102 }
103 }
104
105 @Override
106 public boolean disable() throws RouterException {
107 lock(writeLock);
108 try {
109
110
111 if (isWifi()) {
112 setWiFiMulticastLock(false);
113 setWifiLock(false);
114 }
115 return super.disable();
116 } finally {
117 unlock(writeLock);
118 }
119 }
120
121 public NetworkInfo getNetworkInfo() {
122 return networkInfo;
123 }
124
125 public boolean isMobile() {
126 return NetworkUtils.isMobile(networkInfo);
127 }
128
129 public boolean isWifi() {
130 return NetworkUtils.isWifi(networkInfo);
131 }
132
133 public boolean isEthernet() {
134 return NetworkUtils.isEthernet(networkInfo);
135 }
136
137 public boolean enableWiFi() {
138 log.info("Enabling WiFi...");
139 try {
140 return wifiManager.setWifiEnabled(true);
141 } catch (Throwable t) {
142
143
144
145
146
147
148
149 log.log(Level.WARNING, "SetWifiEnabled failed", t);
150 return false;
151 }
152 }
153
154 public void unregisterBroadcastReceiver() {
155 if (broadcastReceiver != null) {
156 context.unregisterReceiver(broadcastReceiver);
157 broadcastReceiver = null;
158 }
159 }
160
161 protected void setWiFiMulticastLock(boolean enable) {
162 if (multicastLock == null) {
163 multicastLock = wifiManager.createMulticastLock(getClass().getSimpleName());
164 }
165
166 if (enable) {
167 if (multicastLock.isHeld()) {
168 log.warning("WiFi multicast lock already acquired");
169 } else {
170 log.info("WiFi multicast lock acquired");
171 multicastLock.acquire();
172 }
173 } else {
174 if (multicastLock.isHeld()) {
175 log.info("WiFi multicast lock released");
176 multicastLock.release();
177 } else {
178 log.warning("WiFi multicast lock already released");
179 }
180 }
181 }
182
183 protected void setWifiLock(boolean enable) {
184 if (wifiLock == null) {
185 wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, getClass().getSimpleName());
186 }
187
188 if (enable) {
189 if (wifiLock.isHeld()) {
190 log.warning("WiFi lock already acquired");
191 } else {
192 log.info("WiFi lock acquired");
193 wifiLock.acquire();
194 }
195 } else {
196 if (wifiLock.isHeld()) {
197 log.info("WiFi lock released");
198 wifiLock.release();
199 } else {
200 log.warning("WiFi lock already released");
201 }
202 }
203 }
204
205
206
207
208
209
210 protected void onNetworkTypeChange(NetworkInfo oldNetwork, NetworkInfo newNetwork) throws RouterException {
211 log.info(String.format("Network type changed %s => %s",
212 oldNetwork == null ? "" : oldNetwork.getTypeName(),
213 newNetwork == null ? "NONE" : newNetwork.getTypeName()));
214
215 if (disable()) {
216 log.info(String.format(
217 "Disabled router on network type change (old network: %s)",
218 oldNetwork == null ? "NONE" : oldNetwork.getTypeName()
219 ));
220 }
221
222 networkInfo = newNetwork;
223 if (enable()) {
224
225
226 log.info(String.format(
227 "Enabled router on network type change (new network: %s)",
228 newNetwork == null ? "NONE" : newNetwork.getTypeName()
229 ));
230 }
231 }
232
233
234
235
236
237
238 protected void handleRouterExceptionOnNetworkTypeChange(RouterException ex) {
239 Throwable cause = Exceptions.unwrap(ex);
240 if (cause instanceof InterruptedException) {
241 log.log(Level.INFO, "Router was interrupted: " + ex, cause);
242 } else {
243 log.log(Level.WARNING, "Router error on network change: " + ex, ex);
244 }
245 }
246
247 class ConnectivityBroadcastReceiver extends BroadcastReceiver {
248
249 @Override
250 public void onReceive(Context context, Intent intent) {
251
252 if (!intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION))
253 return;
254
255 displayIntentInfo(intent);
256
257 NetworkInfo newNetworkInfo = NetworkUtils.getConnectedNetworkInfo(context);
258
259
260
261
262
263
264
265 if (networkInfo != null && newNetworkInfo == null) {
266 for (int i = 1; i <= 3; i++) {
267 try {
268 Thread.sleep(1000);
269 } catch (InterruptedException e) {
270 return;
271 }
272 log.warning(String.format(
273 "%s => NONE network transition, waiting for new network... retry #%d",
274 networkInfo.getTypeName(), i
275 ));
276 newNetworkInfo = NetworkUtils.getConnectedNetworkInfo(context);
277 if (newNetworkInfo != null)
278 break;
279 }
280 }
281
282 if (isSameNetworkType(networkInfo, newNetworkInfo)) {
283 log.info("No actual network change... ignoring event!");
284 } else {
285 try {
286 onNetworkTypeChange(networkInfo, newNetworkInfo);
287 } catch (RouterException ex) {
288 handleRouterExceptionOnNetworkTypeChange(ex);
289 }
290 }
291 }
292
293 protected boolean isSameNetworkType(NetworkInfo network1, NetworkInfo network2) {
294 if (network1 == null && network2 == null)
295 return true;
296 if (network1 == null || network2 == null)
297 return false;
298 return network1.getType() == network2.getType();
299 }
300
301 protected void displayIntentInfo(Intent intent) {
302 boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
303 String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
304 boolean isFailover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
305
306 NetworkInfo currentNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
307 NetworkInfo otherNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
308
309 log.info("Connectivity change detected...");
310 log.info("EXTRA_NO_CONNECTIVITY: " + noConnectivity);
311 log.info("EXTRA_REASON: " + reason);
312 log.info("EXTRA_IS_FAILOVER: " + isFailover);
313 log.info("EXTRA_NETWORK_INFO: " + (currentNetworkInfo == null ? "none" : currentNetworkInfo));
314 log.info("EXTRA_OTHER_NETWORK_INFO: " + (otherNetworkInfo == null ? "none" : otherNetworkInfo));
315 log.info("EXTRA_EXTRA_INFO: " + intent.getStringExtra(ConnectivityManager.EXTRA_EXTRA_INFO));
316 }
317
318 }
319
320 }