diff -r 2a9601315dfc -r 98ccebc37403 javauis/eswt_qt/com.nokia.swt.extensions/extensions/org/eclipse/swt/internal/extension/NetworkStatus.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/eswt_qt/com.nokia.swt.extensions/extensions/org/eclipse/swt/internal/extension/NetworkStatus.java Fri May 14 15:47:24 2010 +0300 @@ -0,0 +1,423 @@ +/******************************************************************************* + * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Nokia Corporation - initial implementation + *******************************************************************************/ +package org.eclipse.swt.internal.extension; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Internal_PackageSupport; +import org.eclipse.swt.widgets.Listener; + +/** + * This class provides notifications that can be used to determine which type of + * network connections are active at any given moment. + */ +public final class NetworkStatus { + + /** + * A notification state flag that is raised when there are any active + * Ethernet data connections. + */ + public static final int DATA_ETHERNET = 0x00000001; + + /** + * A notification state flag that is raised when there are any active WLAN + * data connections. + */ + public static final int DATA_WLAN = 0x00000002; + + /** + * A notification state flag that is raised when there are any active CSD, + * GPRS, HSCSD, EDGE or cdmaOne data connections. + */ + public static final int DATA_2G = 0x00000004; + + /** + * A notification state flag that is raised when there are any active CDMA + * data connections. + */ + public static final int DATA_CDMA2000 = 0x00000008; + + /** + * A notification state flag that is raised when there are any active + * W-CDMA/UMTS data connections. + */ + public static final int DATA_WCDMA = 0x00000010; + + /** + * A notification state flag that is raised when there are any active High + * Speed Packet Access data connections. + */ + public static final int DATA_HSPA = 0x00000020; + + /** + * A notification state flag that is raised when there are any active + * Bluetooth data connections. + */ + public static final int DATA_BLUETOOTH = 0x00000040; + + /** + * A notification state flag that is raised when there are any active WiMAX + * data connections. + */ + public static final int DATA_WIMAX = 0x00000080; + + /** + * A notification state flag that is raised when there are any active voice + * calls. + */ + public static final int VOICE_CALL = 0x00000100; + + // This flag is set for any other active types than the ones above. + // No events are sent for this type of active connections. + private static final int UNKNOWN = 0x80000000; + + // The notified states of the connection types + private static int notifiedStates; + + // Singleton instance + private static NetworkStatus instance; + + // References to the listeners of the clients + private static NetworkStatusListener[] listeners; + + // QNetworkConfigurationManager and XQCallInfo handles. + // Can be 0 if required native parts not compiled in. + private static int qNetworkConfigurationManagerHandle; + private static int xqCallInfoHandle; + + // QNetworkConfiguration objects for active connections + private static int activeConfigHandles[]; + + // The dispose listener that is added to Display + private static Listener disposeListener; + + private NetworkStatus() { + xqCallInfoHandle = OS.XQCallInfo_create(); + qNetworkConfigurationManagerHandle = OS.QNetworkConfigurationManager_new(0); + hookEvents(); + addDisposeListener(); + handleNetworkConfigurationChange(); + handleCallInformationChanged(); + } + + private static void addDisposeListener() { + Display display = Internal_PackageSupport.getDisplayInstance(); + disposeListener = new Listener() { + public void handleEvent(Event event) { + destroy(); + } + }; + display.addListener(SWT.Dispose, disposeListener); + } + + private static void removeDisposeListener() { + if(disposeListener != null) { + Display display = Internal_PackageSupport.getDisplayInstance(); + if(display != null && !display.isDisposed()) { + display.removeListener(SWT.Dispose, disposeListener); + disposeListener = null; + } + } + } + + private static void checkThread() { + Display display = Internal_PackageSupport.getDisplayInstance(); + if(display == null) { + throw new RuntimeException("Display doesn't exist"); + } + if(!display.getThread().equals(Thread.currentThread())) { + throw new RuntimeException("Not the UI thread"); + } + } + + private static NetworkStatus instance() { + if(instance == null) { + instance = new NetworkStatus(); + } + return instance; + } + + private static boolean hasListeners() { + if(listeners == null) return false; + for(int i = 0; i < listeners.length; ++i) { + if(listeners[i] != null) { + return true; + } + } + return false; + } + + private static void destroy() { + destroyActiveConfigs(); + if(qNetworkConfigurationManagerHandle != 0) { + org.eclipse.swt.internal.qt.QObjectDeleteWrapper.deleteSafely( + qNetworkConfigurationManagerHandle); + qNetworkConfigurationManagerHandle = 0; + } + if(xqCallInfoHandle != 0) { + org.eclipse.swt.internal.qt.QObjectDeleteWrapper.deleteSafely( + xqCallInfoHandle); + xqCallInfoHandle = 0; + } + listeners = null; + instance = null; + } + + /** + * Adds the listener to the collection of listeners who will be notified of + * the network status changes. Can only be called by the eSWT UI thread. If + * there are active connections at the time of adding a listener the + * listener will be notified. Adding the first listener will automatically + * allocate the required native resources and removing the last listener + * will automatically free them. This class will hold a strong reference to + * the listener object preventing it from getting garbage collected until + * the listener is removed. + * + * @param listener + * the listener which should be notified when the event occurs + * + * @exception IllegalArgumentException + * + * + * @exception RuntimeException + * + * + * @see NetworkStatusListener + * @see #removeListener(NetworkStatusListener) + */ + public static void addListener(NetworkStatusListener listener) { + if (listener == null) throw new IllegalArgumentException(); + checkThread(); + instance(); + hook(listener); + if(notifiedStates != 0) { + final NetworkStatusListener asyncNofityListener = listener; + final int asyncNotifyStates = notifiedStates; + Internal_PackageSupport.getDisplayInstance().asyncExec(new Runnable() { + public void run() { + asyncNofityListener.stateChanged(asyncNotifyStates); + } + }); + } + } + + /** + * Removes the listener from the collection of listeners who will be + * notified of the network status changes. Can only be called by the eSWT UI + * thread. Removing the listener will release the reference held by this + * class to the listener object. When all the listeners have been removed + * the native resources allocated by this class are no longer needed and are + * automatically freed. + * + * @param listener + * the listener which should no longer be notified when the event + * occurs + * + * @exception IllegalArgumentException + * + * + * @exception RuntimeException + * + * + * @see NetworkStatusListener + * @see #addListener(NetworkStatusListener) + */ + public static void removeListener(NetworkStatusListener listener) { + if (listener == null) throw new IllegalArgumentException(); + checkThread(); + unhook(listener); + if(!hasListeners()) { + destroy(); + removeDisposeListener(); + } + } + + // Connect the signals + private void hookEvents() { + // Packet data connections + if(qNetworkConfigurationManagerHandle != 0) { + int signalProxy = org.eclipse.swt.internal.qt.OS.SignalHandler_new( + qNetworkConfigurationManagerHandle, this, OS.QSIGNAL_NETWORKCONFIGURATIONCHANGED); + org.eclipse.swt.internal.qt.OS.QObject_connectOrThrow( + qNetworkConfigurationManagerHandle, + "configurationAdded(const QNetworkConfiguration&)", + signalProxy, "widgetSignal()", + org.eclipse.swt.internal.qt.OS.QT_AUTOCONNECTION); + org.eclipse.swt.internal.qt.OS.QObject_connectOrThrow( + qNetworkConfigurationManagerHandle, + "configurationChanged(const QNetworkConfiguration&)", + signalProxy, "widgetSignal()", + org.eclipse.swt.internal.qt.OS.QT_AUTOCONNECTION); + org.eclipse.swt.internal.qt.OS.QObject_connectOrThrow( + qNetworkConfigurationManagerHandle, + "configurationRemoved(const QNetworkConfiguration&)", + signalProxy, "widgetSignal()", + org.eclipse.swt.internal.qt.OS.QT_AUTOCONNECTION); + } + + // Voice calls + if(xqCallInfoHandle != 0) { + int signalProxy = org.eclipse.swt.internal.qt.OS.SignalHandler_new( + xqCallInfoHandle, this, OS.QSIGNAL_CALLINFORMATIONCHANGED); + org.eclipse.swt.internal.qt.OS.QObject_connectOrThrow( + xqCallInfoHandle, + "callInformationChanged()", + signalProxy, "widgetSignal()", + org.eclipse.swt.internal.qt.OS.QT_AUTOCONNECTION); + } + } + + // Connected signals come here + boolean eventProcess(int widgetHandle, int eventType, int time, + int arg1, int arg2, int arg3, int arg4, int arg5, String arg6) { + switch(eventType) { + case OS.QSIGNAL_NETWORKCONFIGURATIONCHANGED: + handleNetworkConfigurationChange(); + break; + case OS.QSIGNAL_CALLINFORMATIONCHANGED: + handleCallInformationChanged(); + break; + default: + break; + } + return false; + } + + private static void destroyActiveConfigs() { + // Free the QNetworkConfiguration objects + if(activeConfigHandles != null) { + for(int i = 0; i < activeConfigHandles.length; ++i) { + OS.QNetworkConfiguration_delete(activeConfigHandles[i]); + activeConfigHandles[i] = 0; + } + activeConfigHandles = null; + } + } + + private static void updateActiveConfigs() { + destroyActiveConfigs(); + // Get all the currently active configurations + if(qNetworkConfigurationManagerHandle != 0) { + activeConfigHandles = OS.QNetworkConfigurationManager_allConfigurations( + qNetworkConfigurationManagerHandle, OS.QNETWORKCONFIGURATION_ACTIVE); + } + } + + private static void handleNetworkConfigurationChange() { + updateActiveConfigs(); + + // Find out the new states of all connection types + int newStates = 0; + newStates |= (notifiedStates & VOICE_CALL); // Voice call state didn't change + for(int i = 0; i < activeConfigHandles.length; ++i) { + int activeFlag = bearerNameToConnectionFlag( + OS.QNetworkConfiguration_bearerName(activeConfigHandles[i])); + if(activeFlag == UNKNOWN) continue; + newStates |= activeFlag; + } + + notifyChangedStates(newStates); + } + + private static void handleCallInformationChanged() { + if(xqCallInfoHandle != 0) { + int newStates = notifiedStates; + if(OS.XQCallInfo_swt_hasCalls(xqCallInfoHandle)) { + newStates |= VOICE_CALL; + } else { + newStates &= ~VOICE_CALL; + } + + notifyChangedStates(newStates); + } + } + + private static void notifyChangedStates(int newStates) { + if(newStates != notifiedStates) { + notifyListeners(newStates); + } + } + + private static void notifyListeners(int state) { + if(listeners != null) { + for(int i = 0; i < listeners.length; ++i) { + if(listeners[i] == null) break; + listeners[i].stateChanged(state); + } + } + notifiedStates = state; + } + + private static int bearerNameToConnectionFlag(String bearerName) { + if(bearerName.equalsIgnoreCase("WCDMA")) { + return DATA_WCDMA; + } else if(bearerName.equalsIgnoreCase("HSPA")) { + return DATA_HSPA; + } else if(bearerName.equalsIgnoreCase("2G")) { + return DATA_2G; + } else if(bearerName.equalsIgnoreCase("WLAN")) { + return DATA_WLAN; + } else if(bearerName.equalsIgnoreCase("Bluetooth")) { + return DATA_BLUETOOTH; + } else if(bearerName.equalsIgnoreCase("CDMA2000")) { + return DATA_CDMA2000; + } else if(bearerName.equalsIgnoreCase("WiMAX")) { + return DATA_WIMAX; + } else if(bearerName.equalsIgnoreCase("Ethernet")) { + return DATA_ETHERNET; + } + return UNKNOWN; + } + + private static void hook(NetworkStatusListener listener) { + if (listeners == null) listeners = new NetworkStatusListener[1]; + int length = listeners.length, index = length - 1; + while (index >= 0) { + if (listeners [index] != null) break; + --index; + } + index++; + if (index == length) { + NetworkStatusListener[] newListeners = new NetworkStatusListener[length + 1]; + System.arraycopy (listeners, 0, newListeners, 0, length); + listeners = newListeners; + } + listeners [index] = listener; + } + + private static void unhook(NetworkStatusListener listener) { + if (listeners == null) return; + for (int i = 0; i < listeners.length; i++) { + if (listeners [i] == listener) { + remove (i); + return; + } + } + } + + private static void remove (int index) { + int end = listeners.length - 1; + System.arraycopy (listeners, index + 1, listeners, index, end - index); + index = end; + listeners [index] = null; + } +}