/**
* Filename: InternetConnectionManager.java (in org.repin.android.net)
* This file is part of the Redpin project.
*
* Redpin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Redpin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Redpin. If not, see <http://www.gnu.org/licenses/>.
*
* (c) Copyright ETH Zurich, Arno Fiva, Philipp Bolliger, 2010, ALL RIGHTS RESERVED.
*
* www.redpin.org
*/
package org.redpin.android.net;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.redpin.android.ApplicationContext;
import org.redpin.android.R;
import org.redpin.android.ui.MapViewActivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
/**
* The {@link InternetConnectionManager} provides information about the
* connectivity to the Redpin server. It does so by checking the devices current
* network state but also contacting the server directly.
*
* @author Arno Fiva (fivaa@student.ethz.ch)
*/
public class InternetConnectionManager extends Service {
public static String CONNECTIVITY_ACTION = "org.redpin.android.net.CONNECTIVITY_CHANGED";
public static int ONLINE_FLAG = 1;
public static int TIMEOUT = 30;
private NotificationManager mNM;
private ConnectivityChecker mChecker = null;
private boolean isCheckRequested = false;
private boolean hasNotifiedOnlineState = true; //prevent initial notification
private boolean hasNotifiedOfflineState = false;
private boolean isServerAvailable = false;
@Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
registerReceiver(mNotifier, new IntentFilter(CONNECTIVITY_ACTION));
/* Hook ourselves up to ConnectivityManager to get network state changes */
registerReceiver(mConnectivity, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
checkConnectivity();
}
@Override
public void onDestroy() {
unregisterReceiver(mNotifier);
unregisterReceiver(mConnectivity);
mNM.cancel(R.string.app_name);
super.onDestroy();
}
/**
* Tell {@link InternetConnectionManager} to check the connectivity now.
*/
public void checkConnectivity() {
if (mChecker == null) {
mChecker = new ConnectivityChecker();
mChecker.execute((Void[]) null);
} else {
isCheckRequested = true;
}
}
public boolean isOnline() {
return isServerAvailable;
}
/**
* @see Service#onBind(Intent)
* @return {@link LocalBinder}
*/
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* @see Binder
*
*/
public class LocalBinder extends Binder {
public InternetConnectionManager getService() {
return InternetConnectionManager.this;
}
}
private final LocalBinder mBinder = new LocalBinder();
/**
* {@link BroadcastReceiver} for network status changes on the device
*/
private BroadcastReceiver mConnectivity = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
/*
* Only initiate a new check if we are not simply trying a different
* network
*/
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER,
false))
return;
checkConnectivity();
}
};
/**
* {@link BroadcastReceiver} for our own {@link CONNECTIVITY_ACTION} action
* in order to display a notification in the UI.
*/
private BroadcastReceiver mNotifier = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getBooleanExtra("isOnline", false)) {
if (!hasNotifiedOnlineState) {
showNotification(R.string.connection_online);
hasNotifiedOnlineState = true;
}
hasNotifiedOnlineState = false;
} else {
if (!hasNotifiedOfflineState) {
showNotification(R.string.connection_offline);
hasNotifiedOfflineState = true;
}
hasNotifiedOfflineState = false;
}
mChecker = null;
if (isCheckRequested) {
isCheckRequested = false;
checkConnectivity();
}
}
/**
* Display message with id {@link redId} in the notification manager.
*
* @param resId
*/
private void showNotification(int resId) {
CharSequence text = getText(resId);
Context context = getApplicationContext();
Notification notification = new Notification(R.drawable.icon, text,
System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MapViewActivity.class), 0);
notification.setLatestEventInfo(context,
getText(R.string.app_name), text, contentIntent);
mNM.notify(R.string.app_name, notification);
}
};
/**
* {@link AsyncTask} responsible for explicitly checking the connection to
* the Redpin server by simply opening a socket to it and closing it again.
*
*/
private class ConnectivityChecker extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
Socket socket = null;
boolean online = false;
try {
socket = new Socket();
socket.bind(null);
InetSocketAddress address = new InetSocketAddress(
ApplicationContext.serverIP, Integer.parseInt(ApplicationContext.serverPort));
socket.connect(address, TIMEOUT * 1000);
online = socket.isConnected();
socket.close();
} catch (IOException e) {
// Nothing to do since we are just interested in the
// availability of the server
}
Intent intent = new Intent(CONNECTIVITY_ACTION);
if (online) {
intent.setFlags(ONLINE_FLAG);
intent.putExtra("isOnline", true);
}
isServerAvailable = online;
sendBroadcast(intent);
return null;
}
};
}