/* * NetworkUtils.java * * Copyright 2007 NHN Corp. All rights Reserved. * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.navercorp.utilset.network; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.nio.channels.SocketChannel; import java.nio.channels.UnresolvedAddressException; import java.util.ArrayList; import java.util.Enumeration; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.os.Handler; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Log; /** * This class provides network related methods In order to use this class, some * permissions such as READ_PHONE_STATE, ACCESS_NETWORK_STATE are required * * @author jaemin.woo */ public class NetworkMonitor { private static final String PHONE_STATER_PREFS = "PHONE_STATER_PREFS"; private static final String KEY_ROAMING_ON = "KEY_ROAMING_ON"; private static final String TAG = "NetworkUtils"; private static NetworkMonitor instance = null; private static boolean isWifiConnectedPrevious = false; private static final int TYPE_MOBILE = 0; private static final int TYPE_WIFI = 1; private static final int TYPE_MOBILE_MMS = 2; private static final int TYPE_MOBILE_SUPL = 3; private static final int TYPE_MOBILE_DUN = 4; private static final int TYPE_MOBILE_HIPRI = 5; private static final int TYPE_WIMAX = 6; private static final int TYPE_BLUETOOTH = 7; private static final int TYPE_DUMMY = 8; private static final int TYPE_ETHERNET = 9; /** * * @param context * Context to be used to get network information.<br> * To avoid memory leak, pass Application Context as argument */ public static NetworkMonitor getInstance(Context context) { if (instance == null) { instance = new NetworkMonitor(context); } return instance; } public static void destroy() { if (instance == null) { return; } instance.unregisterConnectivityReceiver(); instance.clearPhoneCalledListener(); instance.clearWifiStateChangedListener(); instance.clearNetworkConnectedListener(); instance = null; } public interface NetworkStateChangedListener { public void onNetworkStateChanged(); }; public interface NetworkConnectedListener { public void onNetworkConnected(); }; public interface PhoneCalledListener { public void onPhoneCallStateChanged(int state); } private static final int STATE_NONE = -1; private int state = STATE_NONE; private Context context; private BroadcastReceiver connectivityReceiver = null; private ArrayList<NetworkStateChangedListener> listeners; private ArrayList<NetworkConnectedListener> connectedListeners; private ArrayList<PhoneCalledListener> callListeners; private Handler handler; private Runnable networkChangedRunnable; private Runnable networkConnectedRunable; private ConnectivityManager connMan; private TelephonyManager telMgr; private PhoneStateListener phoneStateListener = null; private NetworkMonitor(Context context) { this.context = context; handler = new Handler(); listeners = new ArrayList<NetworkStateChangedListener>(); connectedListeners = new ArrayList<NetworkConnectedListener>(); callListeners = new ArrayList<NetworkMonitor.PhoneCalledListener>(); networkChangedRunnable = new Runnable() { @Override public void run() { synchronized (NetworkMonitor.this) { if (listeners == null) { return; } for (NetworkStateChangedListener l : listeners) { l.onNetworkStateChanged(); } } } }; networkConnectedRunable = new Runnable() { @Override public void run() { synchronized (NetworkMonitor.this) { if (connectedListeners == null) { return; } for (NetworkConnectedListener l : connectedListeners) { l.onNetworkConnected(); } } } }; connectivityReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { if (state == STATE_NONE) { initNetworkState(context); } else { setNetworkState(context); } handleNetworkChanged(); } } }; registerConnectivityReceiver(); telMgr = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); telMgr.listen(new PhoneStateListener() { public void onCallStateChanged(int state, String incomingNumber) { handleOnCallStateChanged(state); } }, PhoneStateListener.LISTEN_CALL_STATE); setWifiConnectedPreviously(isWifiConnected()); } private void handleOnCallStateChanged(final int state) { handler.post(new Runnable() { @Override public void run() { synchronized (NetworkMonitor.this) { if (callListeners == null) { return; } for (PhoneCalledListener l : callListeners) { l.onPhoneCallStateChanged(state); } } } }); } /** * Adds Phone Call Listener<br> * This function is called when the device has a phone call * * @param listener * Listener which implements IPhoneCalledListener * @return true if already that listener is registered; false otherwise */ public boolean addPhoneCalledListener(PhoneCalledListener listener) { synchronized (this) { if (callListeners.contains(listener)) { return true; } return callListeners.add(listener); } } /** * Removes Phone Call Listener<br> * * @param listener * Listener to be removed * @return true if it succeeds to remove listener; false otherwise; */ public boolean removePhoneCalledListener(PhoneCalledListener listener) { synchronized (this) { if (callListeners.size() == 0) { return false; } return callListeners.remove(listener); } } private void clearPhoneCalledListener() { synchronized (this) { callListeners.clear(); } } private void handleNetworkChanged() { handler.post(networkChangedRunnable); } private void handleNetworkConnected() { handler.post(networkConnectedRunable); } /** * Registers receiver to be notified of broadcast event when network * connection changes */ private void registerConnectivityReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(connectivityReceiver, intentFilter); } /** * Removes receiver to be notified broadcast event */ private void unregisterConnectivityReceiver() { try { context.unregisterReceiver(connectivityReceiver); } catch (Exception e) { Log.w(TAG, "unregisterForWifiBroadcasts - exception."); } } /** * Adds WifiStateChangedListener<br> * This function is called when the device has a phone call * * @param listener * Listener which implements IPhoneCalledListener * @return true if already that listener is registered; false otherwise */ public boolean addWifiStateChangedListener( NetworkStateChangedListener listener) { synchronized (this) { if (listeners.contains(listener)) { return true; } return listeners.add(listener); } } /** * Removes WifiStateChangedListener<br> * * @param listener * Listener to be removed * @return true if it succeeds to remove listener; false otherwise */ public boolean removeWifiStateChangedListener( NetworkStateChangedListener listener) { synchronized (this) { if (listeners.size() == 0) { return false; } return listeners.remove(listener); } } private void clearWifiStateChangedListener() { synchronized (this) { listeners.clear(); } } /** * Registers Network Connection Listener<br> * Once registered, connection listeners can be alerted when the device * comes to have network connection * * @param listener * Listener which implements INetworkConnectedListener * @return true if already that listener is registered; false otherwise */ public boolean addNetworkConnectedListener( NetworkConnectedListener listener) { synchronized (this) { if (connectedListeners.contains(listener)) { return true; } return connectedListeners.add(listener); } } /** * Removes Phone Call Listener * * @param listener * Listener to be removed * @return true if it succeeds to remove listener; false otherwise */ public boolean removeNetworkConnectedListener( NetworkConnectedListener listener) { synchronized (this) { if (connectedListeners.size() == 0) { return false; } return connectedListeners.remove(listener); } } private void clearNetworkConnectedListener() { synchronized (this) { connectedListeners.clear(); } } /** * Returns WiFi connection state<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if WiFi is connected; false otherwise */ public boolean isWifiConnected() { try { if (connMan == null) { connMan = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); } NetworkInfo wifiNetInfo = connMan.getNetworkInfo(TYPE_WIFI); NetworkInfo wimaxNetInfo = connMan.getNetworkInfo(TYPE_WIMAX); if (wifiNetInfo == null && wimaxNetInfo == null) { Log.e(TAG, "wifiNetworkInfo is null."); return false; } if (wifiNetInfo != null && wifiNetInfo.isConnected()) { return true; } if (wimaxNetInfo != null && wimaxNetInfo.isConnected()) { return true; } } catch (Exception e) { Log.e(TAG, "Exception during isWifiConnected(). - " + e.getLocalizedMessage()); } return false; } /** * Checks if WiFi is turned on<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if WiFi is turned on; false otherwise */ public boolean isWifiEnabled() { WifiManager wm = (WifiManager) context .getSystemService(Context.WIFI_SERVICE); if (wm == null) { return false; } return wm.isWifiEnabled(); } /** * Check if Mobile network is connected<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if Mobile network has connection; false otherwise */ public boolean isMobileConnected() { if (connMan == null) { connMan = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); } NetworkInfo mobileNetworkInfo = connMan.getNetworkInfo(TYPE_MOBILE); if (mobileNetworkInfo == null) { return false; } return mobileNetworkInfo.isConnected(); } /** * Checks if Mobile Network is turned on<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if Mobile Network is turned on; false otherwise */ public State getMobileState() { if (connMan == null) { connMan = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); } NetworkInfo mobileNetworkInfo = connMan.getNetworkInfo(TYPE_MOBILE); if (mobileNetworkInfo == null) { return State.UNKNOWN; } return mobileNetworkInfo.getState(); } /** * Returns WiFi State Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE * permissions<br> * * @return State */ public State getWifiState() { if (connMan == null) { connMan = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); } NetworkInfo wifiNetworkInfo = connMan.getNetworkInfo(TYPE_WIFI); if (wifiNetworkInfo == null) { return State.UNKNOWN; } return wifiNetworkInfo.getState(); } /** * Tells if network is currently connected<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if connected; false otherwise */ public boolean isNetworkConnected() { try { if (connMan == null) { connMan = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); } NetworkInfo niMobile = connMan.getNetworkInfo(TYPE_MOBILE); NetworkInfo niWifi = connMan.getNetworkInfo(TYPE_WIFI); NetworkInfo niMms = connMan.getNetworkInfo(TYPE_MOBILE_MMS); NetworkInfo niSupl = connMan.getNetworkInfo(TYPE_MOBILE_SUPL); NetworkInfo niDun = connMan.getNetworkInfo(TYPE_MOBILE_DUN); NetworkInfo niHipri = connMan.getNetworkInfo(TYPE_MOBILE_HIPRI); NetworkInfo niWimax = connMan.getNetworkInfo(TYPE_WIMAX); NetworkInfo niBlueTooth = connMan.getNetworkInfo(TYPE_BLUETOOTH); NetworkInfo niDummy = connMan.getNetworkInfo(TYPE_DUMMY); NetworkInfo niEthernet = connMan.getNetworkInfo(TYPE_ETHERNET); if ((niMobile != null && niMobile.isConnected()) || (niWifi != null && niWifi.isConnected()) || (niMms != null && niMms.isConnected()) || (niSupl != null && niSupl.isConnected()) || (niDun != null && niDun.isConnected()) || (niHipri != null && niHipri.isConnected()) || (niWimax != null && niWimax.isConnected()) || (niBlueTooth != null && niBlueTooth.isConnected()) || (niDummy != null && niDummy.isConnected()) || (niEthernet != null && niEthernet.isConnected())) { return true; } return false; } catch (Exception e) { Log.e(TAG, "Exception during isMobileConnected(). - " + e.getLocalizedMessage()); } return false; } /** * Checks if airplane mode is on<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return true if airplane mode is on; false otherwise */ private static final int JELLY_BEAN_MR1 = 17; private static final String AIRPLANE_MODE_ON = "airplane_mode_on"; public boolean isAirplaneModeOn() { // Commented Build.VERSION_CODES and Settings.Global class // because Maven-Android-Plugin does not seem to support API Level 17 // and above. // As such, unable to build through Maven. if (Build.VERSION.SDK_INT >= /* Build.VERSION_CODES. */JELLY_BEAN_MR1) { return Settings.System.getInt(context.getContentResolver(), AIRPLANE_MODE_ON, 0) != 0; } return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; } /** * Returns SIM state<br> * Requires ACCESS_NETWORK_SATE, READ_PHONE_STATE permissions<br> * * @return SIM State (Refer DEV Guide, TelephonyManager) */ public int getSimState() { TelephonyManager telMgr = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); final int simState = telMgr.getSimState(); return simState; } public void listenRoamingState() { if (phoneStateListener == null) { phoneStateListener = new PhoneStateListener() { @Override public void onServiceStateChanged(ServiceState serviceState) { super.onServiceStateChanged(serviceState); final int state = serviceState.getState(); if (state == ServiceState.STATE_IN_SERVICE || state == ServiceState.STATE_POWER_OFF) { final boolean roamingState = serviceState .getRoaming(); if (roamingState != isRoamingOn()) { setRoamingOn(roamingState); } } } }; } TelephonyManager telMgr = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); telMgr.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); } public boolean isRoamingOn() { SharedPreferences prefs = context.getSharedPreferences( PHONE_STATER_PREFS, 0); return prefs.getBoolean(KEY_ROAMING_ON, false); } private void setRoamingOn(boolean bRoamingOn) { SharedPreferences.Editor prefs = context.getSharedPreferences( PHONE_STATER_PREFS, 0).edit(); prefs.putBoolean(KEY_ROAMING_ON, bRoamingOn); prefs.commit(); } public void setWifiConnectedPreviously(boolean isWifiConnected) { isWifiConnectedPrevious = isWifiConnected; } public boolean getWifiConnectedPreviously() { return isWifiConnectedPrevious; } private void setNetworkState(Context context) { if (state == STATE_NONE) { return; } ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = cm.getNetworkInfo(state); if (info != null && isNetworkDisconnected(info.getState())) { Log.d("NetworkUtils", "disconnected(state : " + state + ")"); state = STATE_NONE; } } private boolean isNetworkDisconnected(State state) { switch (state) { case DISCONNECTED: case DISCONNECTING: return true; default: return false; } } private void initNetworkState(Context context) { ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo niMobile = cm.getNetworkInfo(TYPE_MOBILE); NetworkInfo niWifi = cm.getNetworkInfo(TYPE_WIFI); NetworkInfo niMms = cm.getNetworkInfo(TYPE_MOBILE_MMS); NetworkInfo niSupl = cm.getNetworkInfo(TYPE_MOBILE_SUPL); NetworkInfo niDun = cm.getNetworkInfo(TYPE_MOBILE_DUN); NetworkInfo niHipri = cm.getNetworkInfo(TYPE_MOBILE_HIPRI); NetworkInfo niWimax = cm.getNetworkInfo(TYPE_WIMAX); NetworkInfo niBlueTooth = cm.getNetworkInfo(TYPE_BLUETOOTH); NetworkInfo niDummy = cm.getNetworkInfo(TYPE_DUMMY); NetworkInfo niEthernet = cm.getNetworkInfo(TYPE_ETHERNET); if (niWifi != null && niWifi.getState() == State.CONNECTED) { state = TYPE_WIFI; handleNetworkConnected(); } else if (niMobile != null && niMobile.getState() == State.CONNECTED) { state = TYPE_MOBILE; handleNetworkConnected(); } else if (niBlueTooth != null && niBlueTooth.getState() == State.CONNECTED) { state = TYPE_BLUETOOTH; handleNetworkConnected(); } else if (niMms != null && niMms.getState() == State.CONNECTED) { state = TYPE_MOBILE_MMS; handleNetworkConnected(); } else if (niSupl != null && niSupl.getState() == State.CONNECTED) { state = TYPE_MOBILE_SUPL; handleNetworkConnected(); } else if (niDun != null && niDun.getState() == State.CONNECTED) { state = TYPE_MOBILE_DUN; handleNetworkConnected(); } else if (niHipri != null && niHipri.getState() == State.CONNECTED) { state = TYPE_MOBILE_HIPRI; handleNetworkConnected(); } else if (niWimax != null && niWimax.getState() == State.CONNECTED) { state = TYPE_WIMAX; handleNetworkConnected(); } else if (niDummy != null && niDummy.getState() == State.CONNECTED) { state = TYPE_DUMMY; handleNetworkConnected(); } else if (niEthernet != null && niEthernet.getState() == State.CONNECTED) { state = TYPE_ETHERNET; handleNetworkConnected(); } } /** * Returns IP Address<br> * Requires READ_PHONE_STATE, ACCESS_WIFI_STATE and INTERNET permissions<br> * * @param ipv6 * Option to choose IP address type * @return IP address made up of IPv6 if parameter ipv6 is true or IPv4 if * parameter ipv6 is false; null if it do not have IP address * @throws RuntimeException * when it fails due to poor network condition */ public String getIpAddress(boolean ipv6) { try { for (Enumeration<NetworkInterface> networkInterfaces = NetworkInterface .getNetworkInterfaces(); networkInterfaces .hasMoreElements();) { NetworkInterface networkInterface = networkInterfaces .nextElement(); for (Enumeration<InetAddress> addresses = networkInterface .getInetAddresses(); addresses.hasMoreElements();) { InetAddress inetAddress = addresses.nextElement(); if (inetAddress.isLoopbackAddress()) { continue; } if (ipv6 && inetAddress instanceof Inet6Address) { return inetAddress.getHostAddress(); } else if (ipv6 == false && inetAddress instanceof Inet4Address) { return inetAddress.getHostAddress(); } } } } catch (SocketException e) { throw new RuntimeException(e); } return null; } /** * Returns MAC Address of WiFi Adapter<br> * Requires READ_PHONE_STATE, ACCESS_NETWORK_STATE and ACCESS_WIFI_STATE * permissions<br> * * @return String representing MAC Address of WiFi Adapter; Empty String in * some cases such as No WiFi Adapter is installed or WiFi is turned * off. */ public String getWifiMacAddress() { WifiManager wifiMan = (WifiManager) context .getSystemService(Context.WIFI_SERVICE); if (wifiMan != null) { WifiInfo wifiInf = wifiMan.getConnectionInfo(); return wifiInf.getMacAddress(); } return ""; } /** * Turns on WiFi Adapter<br> * * Requires READ_PHONE_STATE, ACCESS_NETWORK_STATE and CHANGE_WIFI_STATE * permissions<br> * * @param context */ public void setWifiEnabled(Context context) { WifiManager wifiMan = (WifiManager) context .getSystemService(Context.WIFI_SERVICE); wifiMan.setWifiEnabled(true); } /** * Turns off WiFi Adapter<br> * * Requires READ_PHONE_STATE, ACCESS_NETWORK_STATE and CHANGE_WIFI_STATE * permissions<br> * * @param context */ public void setWifiDisabled(Context context) { WifiManager wifiMan = (WifiManager) context .getSystemService(Context.WIFI_SERVICE); wifiMan.setWifiEnabled(false); } /** * Checks if currently connected Access Point is either rogue or incapable * of routing packet * * @param ipAddress * Any valid IP addresses will work to check if the device is * connected to properly working AP * @param port * Port number bound with ipAddress parameter * @return true if currently connected AP is not working normally; false * otherwise */ public boolean isWifiFake(String ipAddress, int port) { SocketChannel socketChannel = null; try { socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress(ipAddress, port)); } catch (IOException e) { Log.d(TAG, "Current Wifi is stupid!!! by IOException"); return true; } catch (UnresolvedAddressException e) { Log.d(TAG, "Current Wifi is stupid!!! by InetSocketAddress"); return true; } finally { if (socketChannel != null) try { socketChannel.close(); } catch (IOException e) { Log.d(TAG, "Error occured while closing SocketChannel"); } } return false; } }