--- /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 Tue Aug 31 15:09:22 2010 +0300
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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 Display getDisplay() {
+ Display display;
+ display = Internal_PackageSupport.getInternalDisplayInstance();
+ if(display == null) {
+ display = Internal_PackageSupport.getDisplayInstance();
+ }
+ return display;
+ }
+
+ private static void addDisposeListener() {
+ disposeListener = new Listener() {
+ public void handleEvent(Event event) {
+ destroy();
+ }
+ };
+ getDisplay().addListener(SWT.Dispose, disposeListener);
+ }
+
+ private static void removeDisposeListener() {
+ if(disposeListener != null) {
+ Display display = getDisplay();
+ if(display != null && !display.isDisposed()) {
+ display.removeListener(SWT.Dispose, disposeListener);
+ disposeListener = null;
+ }
+ }
+ }
+
+ private static void checkThread() {
+ Display display = getDisplay();
+ 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
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception RuntimeException
+ * <ul>
+ * <li>If eSWT Display doesn't exist</li>
+ * <li>If called in a non-UI thread</li>
+ * </ul>
+ *
+ * @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;
+ getDisplay().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
+ * <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception RuntimeException
+ * <ul>
+ * <li>If eSWT Display doesn't exist</li>
+ * <li>If called in a non-UI thread</li>
+ * </ul>
+ *
+ * @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.SignalForwarder_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.SignalForwarder_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;
+ }
+}