// Copyright (c) Microsoft Corporation. All rights reserved.
// Portions derived from React Native:
// Copyright (c) 2015-present, Facebook, Inc.
// Licensed under the MIT License.
using Newtonsoft.Json.Linq;
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using Windows.Networking.Connectivity;
namespace ReactNativeCommunity.NetInfo
{
///
/// Module that monitors and provides information about the connectivity
/// state of the device.
///
public class RNCNetInfoModule : ReactContextNativeModuleBase, ILifecycleEventListener
{
// These constants need to match the strings defined in types.ts
private const string CONNECTION_TYPE_CELLULAR = "cellular";
private const string CONNECTION_TYPE_ETHERNET = "ethernet";
private const string CONNECTION_TYPE_NONE = "none";
private const string CONNECTION_TYPE_UNKNOWN = "unknown";
private const string CONNECTION_TYPE_WIFI = "wifi";
private const string CONNECTION_TYPE_OTHER = "other";
private const string CELLULAR_GENERATION_2G = "2g";
private const string CELLULAR_GENERATION_3G = "3g";
private const string CELLULAR_GENERATION_4G = "4g";
private const string CELLULAR_GENERATION_NONE = null;
private const string CELLULAR_GENERATION_UNKNOWN = null;
private readonly INetworkInformation _networkInfo;
///
/// Instantiates the .
///
/// The React context.
public RNCNetInfoModule(ReactContext reactContext)
: this(new DefaultNetworkInformation(), reactContext)
{
}
///
/// Instantiates the .
///
/// The network information.
/// The React context.
public RNCNetInfoModule(INetworkInformation networkInfo, ReactContext reactContext)
: base(reactContext)
{
_networkInfo = networkInfo;
}
///
/// Gets the name of the native module.
///
public override string Name
{
get
{
return "RNCNetInfo";
}
}
///
/// Gets the current connectivity state of the app.
///
/// The interface from which to obtain the information (not currently supported)
/// A promise to resolve the request.
[ReactMethod]
public void getCurrentState(String requestedInterface, IPromise promise)
{
promise.Resolve(CreateConnectivityEventMap());
}
///
/// Called when the application host is destroyed.
///
public void OnDestroy()
{
}
///
/// Called when the application host is resumed.
///
public void OnResume()
{
_networkInfo.Start();
_networkInfo.NetworkStatusChanged += OnStatusChanged;
}
///
/// Called when the application host is suspended.
///
public void OnSuspend()
{
_networkInfo.NetworkStatusChanged -= OnStatusChanged;
_networkInfo.Stop();
}
///
/// Called when the React instance is initialized.
///
public override void Initialize()
{
Context.AddLifecycleEventListener(this);
}
private JObject CreateConnectivityEventMap()
{
var eventMap = new JObject();
// Add the connection type information
var type = GetConnectivityType();
eventMap.Add("type", type);
// Add the connection state information
var isConnected = GetIsConnected();
eventMap.Add("isConnected", isConnected);
// Add the details, if there are any
JObject details = null;
if (isConnected)
{
details = new JObject();
var isConnectionExpensive = GetIsConnectionExpensive();
details.Add("isConnectionExpensive", isConnectionExpensive);
if (type == CONNECTION_TYPE_CELLULAR)
{
var cellularGeneration = GetCellularGeneration();
details.Add("cellularGeneration", cellularGeneration);
}
}
eventMap.Add("details", details);
return eventMap;
}
private string GetConnectivityType()
{
var profile = _networkInfo.GetInternetConnectionProfile();
if (profile == null)
{
return CONNECTION_TYPE_NONE;
}
switch (profile.ConnectionType)
{
case NetworkConnectionType.Unknown:
return CONNECTION_TYPE_UNKNOWN;
case NetworkConnectionType.None:
return CONNECTION_TYPE_NONE;
case NetworkConnectionType.Cellular:
return CONNECTION_TYPE_CELLULAR;
case NetworkConnectionType.Ethernet:
return CONNECTION_TYPE_ETHERNET;
case NetworkConnectionType.Wifi:
return CONNECTION_TYPE_WIFI;
case NetworkConnectionType.Other:
return CONNECTION_TYPE_OTHER;
default:
return CONNECTION_TYPE_UNKNOWN;
}
}
private string GetCellularGeneration()
{
var profile = _networkInfo.GetInternetConnectionProfile();
if (profile == null)
{
return CELLULAR_GENERATION_NONE;
}
switch (profile.CellularGeneration)
{
case CellularGeneration.Unknown:
return CELLULAR_GENERATION_UNKNOWN;
case CellularGeneration.None:
return CELLULAR_GENERATION_NONE;
case CellularGeneration.Generation2:
return CELLULAR_GENERATION_2G;
case CellularGeneration.Generation3:
return CELLULAR_GENERATION_3G;
case CellularGeneration.Generation4:
return CELLULAR_GENERATION_4G;
default:
return CELLULAR_GENERATION_UNKNOWN;
}
}
private bool GetIsConnected()
{
var profile = _networkInfo.GetInternetConnectionProfile();
return profile != null && profile.ConnectivityLevel != NetworkConnectivityLevel.None;
}
private bool GetIsConnectionExpensive()
{
var profile = _networkInfo.GetInternetConnectionProfile();
if (profile == null)
{
return false;
}
var connectionCost = profile.ConnectionCost;
return connectionCost == NetworkCostType.Fixed || connectionCost == NetworkCostType.Variable;
}
private void OnStatusChanged(object ignored)
{
var connectivity = CreateConnectivityEventMap();
Context.GetJavaScriptModule()
.emit("netInfo.networkStatusDidChange", CreateConnectivityEventMap());
}
}
}