Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,14 @@
import com.codename1.io.FileSystemStorage;
import com.codename1.io.Log;
import com.codename1.io.NetworkManager;
import com.codename1.io.NetworkTypePlatform;
import com.codename1.io.Preferences;
import com.codename1.io.Storage;
import com.codename1.io.Util;
import com.codename1.io.bonjour.BonjourPlatform;
import com.codename1.io.usb.UsbPlatform;
import com.codename1.io.wifi.WifiDirectPlatform;
import com.codename1.io.wifi.WifiPlatform;
import com.codename1.io.tar.TarEntry;
import com.codename1.io.tar.TarInputStream;
import com.codename1.l10n.L10NManager;
Expand Down Expand Up @@ -6376,6 +6381,104 @@ public boolean isVPNActive() {
return false;
}

// ---------------------------------------------------------------------
// Deeper-network connectivity platform accessors.
//
// Each create*Platform() factory returns a narrow abstract class that
// the public-facing APIs in com.codename1.io.{wifi,bonjour,usb} ask for
// via Display.getInstance().getXxxPlatform(). Platform ports override
// the factory they care about; everything else falls through to the
// default no-op implementations. Keeping these as small factories
// (instead of dozens of methods on this class) lets each port ship its
// platform-specific code in a dedicated class and keeps this base
// implementation modular.
// ---------------------------------------------------------------------

private WifiPlatform wifiPlatform;
private WifiDirectPlatform wifiDirectPlatform;
private BonjourPlatform bonjourPlatform;
private UsbPlatform usbPlatform;
private NetworkTypePlatform networkTypePlatform;

public final WifiPlatform getWifiPlatform() {
if (wifiPlatform == null) {
WifiPlatform p = createWifiPlatform();
wifiPlatform = p != null ? p : new WifiPlatform();
}
return wifiPlatform;
}

/// Platform ports override to return their WiFi implementation. The
/// default returns `null`, which the caller turns into the
/// unsupported stub built into `WifiPlatform`.
protected WifiPlatform createWifiPlatform() {
return null;
}

public final WifiDirectPlatform getWifiDirectPlatform() {
if (wifiDirectPlatform == null) {
WifiDirectPlatform p = createWifiDirectPlatform();
wifiDirectPlatform = p != null ? p : new WifiDirectPlatform();
}
return wifiDirectPlatform;
}

protected WifiDirectPlatform createWifiDirectPlatform() {
return null;
}

public final BonjourPlatform getBonjourPlatform() {
if (bonjourPlatform == null) {
BonjourPlatform p = createBonjourPlatform();
bonjourPlatform = p != null ? p : new BonjourPlatform();
}
return bonjourPlatform;
}

protected BonjourPlatform createBonjourPlatform() {
return null;
}

public final UsbPlatform getUsbPlatform() {
if (usbPlatform == null) {
UsbPlatform p = createUsbPlatform();
usbPlatform = p != null ? p : new UsbPlatform();
}
return usbPlatform;
}

protected UsbPlatform createUsbPlatform() {
return null;
}

public final NetworkTypePlatform getNetworkTypePlatform() {
if (networkTypePlatform == null) {
NetworkTypePlatform p = createNetworkTypePlatform();
networkTypePlatform = p != null ? p : new LegacyAccessPointNetworkType(this);
}
return networkTypePlatform;
}

protected NetworkTypePlatform createNetworkTypePlatform() {
return null;
}

/// Fallback `NetworkTypePlatform` for ports that haven't been updated
/// to provide their own. Bridges to the legacy access-point API so
/// `NetworkManager.getCurrentNetworkType()` still distinguishes
/// "online" from "offline" when an AP is configured.
private static final class LegacyAccessPointNetworkType extends NetworkTypePlatform {
private final CodenameOneImplementation impl;
LegacyAccessPointNetworkType(CodenameOneImplementation impl) {
this.impl = impl;
}
@Override public int getCurrentNetworkType() {
return impl.isAPSupported() && impl.getCurrentAccessPoint() != null
? NetworkManager.NETWORK_TYPE_OTHER
: NetworkManager.NETWORK_TYPE_NONE;
}
}

/// For some reason the standard code for writing UTF8 output in a server request
/// doesn't work as expected on SE/CDC stacks.
///
Expand Down
116 changes: 116 additions & 0 deletions CodenameOne/src/com/codename1/io/NetworkManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,26 @@ public final class NetworkManager {
/// Indicates a corporate routing server access point type (e.g. BIS etc.)
public static final int ACCESS_POINT_TYPE_CORPORATE = 6;

/// Active network type reported by `getCurrentNetworkType()` /
/// `NetworkTypeListener`: no usable connectivity.
public static final int NETWORK_TYPE_NONE = 0;
/// Active network type: WiFi / 802.11 / WLAN.
public static final int NETWORK_TYPE_WIFI = 1;
/// Active network type: cellular data (2G/3G/4G/5G).
public static final int NETWORK_TYPE_CELLULAR = 2;
/// Active network type: wired Ethernet.
public static final int NETWORK_TYPE_ETHERNET = 3;
/// Active network type: short-range Bluetooth PAN.
public static final int NETWORK_TYPE_BLUETOOTH = 4;
/// Active network type reported by the platform but not classified into
/// one of the named buckets above.
public static final int NETWORK_TYPE_OTHER = 5;

private static final Object LOCK = new Object();
private static final NetworkManager INSTANCE = new NetworkManager();
private EventDispatcher networkTypeListeners;
private int lastNetworkType = -1;
private boolean lastVpnActive;
private static String autoDetectURL = "https://www.google.com/";
private final Vector pending = new Vector();
private final Hashtable threadAssignements = new Hashtable();
Expand Down Expand Up @@ -845,6 +863,104 @@ public boolean isVPNActive() {
return Util.getImplementation().isVPNActive();
}

/// Returns the device's currently active network type, one of the
/// `NETWORK_TYPE_*` constants. Returns `NETWORK_TYPE_NONE` when there is
/// no connectivity. Distinct from `getAPType` which describes a configured
/// access point rather than the active data path.
public int getCurrentNetworkType() {
return Display.getInstance()
.getNetworkTypePlatform().getCurrentNetworkType();
}

/// Fast best-effort connectivity check. Returns `false` only when the
/// platform reports `NETWORK_TYPE_NONE`; all other states (WiFi,
/// cellular, ethernet, VPN-only, or "other") return `true`. Avoids the
/// HTTP probe that `getInstance().assignToThread(...)` performs against
/// `autoDetectURL` so the check is suitable to call from the EDT.
///
/// Apps that need a stronger "can I reach my server" guarantee should
/// still fire a real `ConnectionRequest`; this method only reports
/// whether the device has *any* usable network interface up.
public boolean isConnected() {
return getCurrentNetworkType() != NETWORK_TYPE_NONE;
}

/// Registers `l` to be notified when the device's active network type
/// changes (WiFi <-> Cellular <-> None <-> ...). The listener is invoked
/// on the EDT. Safe to call multiple times with the same listener; only
/// the first registration takes effect.
///
/// On platforms where network change events are unavailable the listener
/// is still installed but never fires; `getCurrentNetworkType()` should
/// be polled instead.
public void addNetworkTypeListener(NetworkTypeListener l) {
synchronized (LOCK) {
if (networkTypeListeners == null) {
networkTypeListeners = new EventDispatcher();
networkTypeListeners.setBlocking(false);
Display.getInstance()
.getNetworkTypePlatform().install(this);
lastNetworkType = getCurrentNetworkType();
lastVpnActive = isVPNActive();
}
if (!containsListener(networkTypeListeners, l)) {
networkTypeListeners.addListener(l);
}
}
}

/// Removes a listener previously registered with
/// `addNetworkTypeListener(NetworkTypeListener)`. If the last listener is
/// removed the platform watcher is torn down too.
public void removeNetworkTypeListener(NetworkTypeListener l) {
synchronized (LOCK) {
if (networkTypeListeners == null) {
return;
}
networkTypeListeners.removeListener(l);
Collection v = networkTypeListeners.getListenerCollection();
if (v == null || v.isEmpty()) {
Display.getInstance()
.getNetworkTypePlatform().uninstall(this);
networkTypeListeners = null;
}
}
}

private boolean containsListener(EventDispatcher d, Object l) {
Collection v = d.getListenerCollection();
return v != null && v.contains(l);
}

/// Internal: invoked by platform implementations to deliver a network
/// type change event. Public so platform code in other packages can call
/// it; not intended for application use.
public void fireNetworkTypeChange(int newType, boolean vpnActive) {
EventDispatcher d;
int oldType;
boolean fire;
synchronized (LOCK) {
d = networkTypeListeners;
oldType = lastNetworkType;
fire = d != null && (oldType != newType || lastVpnActive != vpnActive);
lastNetworkType = newType;
lastVpnActive = vpnActive;
}
if (fire) {
Collection listeners = d.getListenerCollection();
if (listeners == null) {
return;
}
Object[] arr = listeners.toArray();
for (Object o : arr) {
if (o instanceof NetworkTypeListener) {
((NetworkTypeListener) o)
.onNetworkTypeChanged(oldType, newType, vpnActive);
}
}
}
}

class NetworkThread implements Runnable {
boolean stopped = false;
private ConnectionRequest currentRequest;
Expand Down
28 changes: 28 additions & 0 deletions CodenameOne/src/com/codename1/io/NetworkTypeListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2008, 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Codename One in the LICENSE file that accompanied this code.
*/
package com.codename1.io;

/// Receives notifications when the device's active network changes type
/// (WiFi <-> Cellular <-> Ethernet <-> None <-> VPN). Register with
/// `NetworkManager.addNetworkTypeListener(NetworkTypeListener)`.
///
/// Implementations are invoked on the EDT.
public interface NetworkTypeListener {
/// Called when the platform transitions between network classes.
///
/// #### Parameters
///
/// - `oldType`: one of `NetworkManager.NETWORK_TYPE_*`
/// - `newType`: one of `NetworkManager.NETWORK_TYPE_*`
/// - `vpnActive`: `true` if the platform reports a VPN tunnel on top of
/// the active network. May be `false` on platforms where VPN detection
/// is unsupported (see `NetworkManager.isVPNDetectionSupported()`).
void onNetworkTypeChanged(int oldType, int newType, boolean vpnActive);
}
37 changes: 37 additions & 0 deletions CodenameOne/src/com/codename1/io/NetworkTypePlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2008, 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Codename One in the LICENSE file that accompanied this code.
*/
package com.codename1.io;

/// Platform-supplied implementation of the network-type tracking API.
/// `NetworkManager.getCurrentNetworkType()`,
/// `NetworkManager.addNetworkTypeListener(...)` and the matching remover
/// all dispatch through this.
///
/// Part of the framework's service-provider interface, not intended for
/// application use.
public class NetworkTypePlatform {
/// One of the `NetworkManager.NETWORK_TYPE_*` constants. Default
/// returns `NETWORK_TYPE_OTHER` when an access point is configured so
/// stub platforms still indicate "some connectivity present".
public int getCurrentNetworkType() {
return NetworkManager.NETWORK_TYPE_NONE;
}

/// Subscribe to platform network transitions. The platform must call
/// `target.fireNetworkTypeChange(newType, vpnActive)` whenever the
/// active network changes. Default is a no-op for platforms that
/// can't observe transitions.
public void install(NetworkManager target) {
}

/// Tear down the watcher installed by `install`. Default no-op.
public void uninstall(NetworkManager target) {
}
}
Loading
Loading