/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.android_scripting.facade; import android.app.Service; import android.app.usage.NetworkStats; import android.app.usage.NetworkStats.Bucket; import android.app.usage.NetworkStatsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; import android.net.StringNetworkSpecifier; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; import com.google.common.io.ByteStreams; import com.googlecode.android_scripting.FileUtils; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.facade.wifi.WifiAwareManagerFacade; import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.rpc.Rpc; import com.googlecode.android_scripting.rpc.RpcOptional; import com.googlecode.android_scripting.rpc.RpcParameter; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; /** * Access ConnectivityManager functions. */ public class ConnectivityManagerFacade extends RpcReceiver { public static int AIRPLANE_MODE_OFF = 0; public static int AIRPLANE_MODE_ON = 1; public static int DATA_ROAMING_ON = 1; private static HashMap<Long, Network> sNetworkHashMap = new HashMap<Long, Network>(); class ConnectivityReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { Log.e("ConnectivityReceiver received non-connectivity action!"); return; } Bundle b = intent.getExtras(); if (b == null) { Log.e("ConnectivityReceiver failed to receive extras!"); return; } int netType = b.getInt(ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE); if (netType == ConnectivityManager.TYPE_NONE) { Log.i("ConnectivityReceiver received change to TYPE_NONE."); return; } /* * Technically there is a race condition here, but retrieving the NetworkInfo from the * bundle is deprecated. See ConnectivityManager.EXTRA_NETWORK_INFO */ for (NetworkInfo info : mManager.getAllNetworkInfo()) { if (info.getType() == netType) { mEventFacade.postEvent(ConnectivityConstants.EventConnectivityChanged, info); } } } } class PacketKeepaliveReceiver extends PacketKeepaliveCallback { public static final int EVENT_INVALID = -1; public static final int EVENT_NONE = 0; public static final int EVENT_STARTED = 1 << 0; public static final int EVENT_STOPPED = 1 << 1; public static final int EVENT_ERROR = 1 << 2; public static final int EVENT_ALL = EVENT_STARTED | EVENT_STOPPED | EVENT_ERROR; private int mEvents; public String mId; public PacketKeepalive mPacketKeepalive; public PacketKeepaliveReceiver(int events) { super(); mEvents = events; mId = this.toString(); } public void startListeningForEvents(int events) { mEvents |= events & EVENT_ALL; } public void stopListeningForEvents(int events) { mEvents &= ~(events & EVENT_ALL); } @Override public void onStarted() { Log.d("PacketKeepaliveCallback on start!"); if ((mEvents & EVENT_STARTED) == EVENT_STARTED) { mEventFacade.postEvent( ConnectivityConstants.EventPacketKeepaliveCallback, new ConnectivityEvents.PacketKeepaliveEvent( mId, getPacketKeepaliveReceiverEventString(EVENT_STARTED))); } } @Override public void onStopped() { Log.d("PacketKeepaliveCallback on stop!"); if ((mEvents & EVENT_STOPPED) == EVENT_STOPPED) { mEventFacade.postEvent( ConnectivityConstants.EventPacketKeepaliveCallback, new ConnectivityEvents.PacketKeepaliveEvent( mId, getPacketKeepaliveReceiverEventString(EVENT_STOPPED))); } } @Override public void onError(int error) { Log.d("PacketKeepaliveCallback on error! - code:" + error); if ((mEvents & EVENT_ERROR) == EVENT_ERROR) { mEventFacade.postEvent( ConnectivityConstants.EventPacketKeepaliveCallback, new ConnectivityEvents.PacketKeepaliveEvent( mId, getPacketKeepaliveReceiverEventString(EVENT_ERROR))); } } } class NetworkCallback extends ConnectivityManager.NetworkCallback { public static final int EVENT_INVALID = -1; public static final int EVENT_NONE = 0; public static final int EVENT_PRECHECK = 1 << 0; public static final int EVENT_AVAILABLE = 1 << 1; public static final int EVENT_LOSING = 1 << 2; public static final int EVENT_LOST = 1 << 3; public static final int EVENT_UNAVAILABLE = 1 << 4; public static final int EVENT_CAPABILITIES_CHANGED = 1 << 5; public static final int EVENT_SUSPENDED = 1 << 6; public static final int EVENT_RESUMED = 1 << 7; public static final int EVENT_LINK_PROPERTIES_CHANGED = 1 << 8; public static final int EVENT_ALL = EVENT_PRECHECK | EVENT_AVAILABLE | EVENT_LOSING | EVENT_LOST | EVENT_UNAVAILABLE | EVENT_CAPABILITIES_CHANGED | EVENT_SUSPENDED | EVENT_RESUMED | EVENT_LINK_PROPERTIES_CHANGED; private int mEvents; public String mId; private long mCreateTimestamp; public NetworkCallback(int events) { super(); mEvents = events; mId = this.toString(); mCreateTimestamp = System.currentTimeMillis(); } public void startListeningForEvents(int events) { mEvents |= events & EVENT_ALL; } public void stopListeningForEvents(int events) { mEvents &= ~(events & EVENT_ALL); } @Override public void onPreCheck(Network network) { Log.d("NetworkCallback onPreCheck"); if ((mEvents & EVENT_PRECHECK) == EVENT_PRECHECK) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_PRECHECK), mCreateTimestamp)); } } @Override public void onAvailable(Network network) { Log.d("NetworkCallback onAvailable"); if ((mEvents & EVENT_AVAILABLE) == EVENT_AVAILABLE) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_AVAILABLE), mCreateTimestamp)); } } @Override public void onLosing(Network network, int maxMsToLive) { Log.d("NetworkCallback onLosing"); if ((mEvents & EVENT_LOSING) == EVENT_LOSING) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventOnLosing( mId, getNetworkCallbackEventString(EVENT_LOSING), mCreateTimestamp, maxMsToLive)); } } @Override public void onLost(Network network) { Log.d("NetworkCallback onLost"); if ((mEvents & EVENT_LOST) == EVENT_LOST) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_LOST), mCreateTimestamp)); } } @Override public void onUnavailable() { Log.d("NetworkCallback onUnavailable"); if ((mEvents & EVENT_UNAVAILABLE) == EVENT_UNAVAILABLE) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_UNAVAILABLE), mCreateTimestamp)); } } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { Log.d("NetworkCallback onCapabilitiesChanged. RSSI:" + networkCapabilities.getSignalStrength()); if ((mEvents & EVENT_CAPABILITIES_CHANGED) == EVENT_CAPABILITIES_CHANGED) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventOnCapabilitiesChanged( mId, getNetworkCallbackEventString(EVENT_CAPABILITIES_CHANGED), mCreateTimestamp, networkCapabilities.getSignalStrength())); } } @Override public void onNetworkSuspended(Network network) { Log.d("NetworkCallback onNetworkSuspended"); if ((mEvents & EVENT_SUSPENDED) == EVENT_SUSPENDED) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_SUSPENDED), mCreateTimestamp)); } } @Override public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { Log.d("NetworkCallback onLinkPropertiesChanged"); if ((mEvents & EVENT_LINK_PROPERTIES_CHANGED) == EVENT_LINK_PROPERTIES_CHANGED) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventOnLinkPropertiesChanged(mId, getNetworkCallbackEventString(EVENT_LINK_PROPERTIES_CHANGED), mCreateTimestamp, linkProperties.getInterfaceName())); } } @Override public void onNetworkResumed(Network network) { Log.d("NetworkCallback onNetworkResumed"); if ((mEvents & EVENT_RESUMED) == EVENT_RESUMED) { mEventFacade.postEvent( ConnectivityConstants.EventNetworkCallback, new ConnectivityEvents.NetworkCallbackEventBase( mId, getNetworkCallbackEventString(EVENT_RESUMED), mCreateTimestamp)); } } } private static int getNetworkCallbackEvent(String event) { switch (event) { case ConnectivityConstants.NetworkCallbackPreCheck: return NetworkCallback.EVENT_PRECHECK; case ConnectivityConstants.NetworkCallbackAvailable: return NetworkCallback.EVENT_AVAILABLE; case ConnectivityConstants.NetworkCallbackLosing: return NetworkCallback.EVENT_LOSING; case ConnectivityConstants.NetworkCallbackLost: return NetworkCallback.EVENT_LOST; case ConnectivityConstants.NetworkCallbackUnavailable: return NetworkCallback.EVENT_UNAVAILABLE; case ConnectivityConstants.NetworkCallbackCapabilitiesChanged: return NetworkCallback.EVENT_CAPABILITIES_CHANGED; case ConnectivityConstants.NetworkCallbackSuspended: return NetworkCallback.EVENT_SUSPENDED; case ConnectivityConstants.NetworkCallbackResumed: return NetworkCallback.EVENT_RESUMED; case ConnectivityConstants.NetworkCallbackLinkPropertiesChanged: return NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED; } return NetworkCallback.EVENT_INVALID; } private static String getNetworkCallbackEventString(int event) { switch (event) { case NetworkCallback.EVENT_PRECHECK: return ConnectivityConstants.NetworkCallbackPreCheck; case NetworkCallback.EVENT_AVAILABLE: return ConnectivityConstants.NetworkCallbackAvailable; case NetworkCallback.EVENT_LOSING: return ConnectivityConstants.NetworkCallbackLosing; case NetworkCallback.EVENT_LOST: return ConnectivityConstants.NetworkCallbackLost; case NetworkCallback.EVENT_UNAVAILABLE: return ConnectivityConstants.NetworkCallbackUnavailable; case NetworkCallback.EVENT_CAPABILITIES_CHANGED: return ConnectivityConstants.NetworkCallbackCapabilitiesChanged; case NetworkCallback.EVENT_SUSPENDED: return ConnectivityConstants.NetworkCallbackSuspended; case NetworkCallback.EVENT_RESUMED: return ConnectivityConstants.NetworkCallbackResumed; case NetworkCallback.EVENT_LINK_PROPERTIES_CHANGED: return ConnectivityConstants.NetworkCallbackLinkPropertiesChanged; } return ConnectivityConstants.NetworkCallbackInvalid; } private static int getPacketKeepaliveReceiverEvent(String event) { switch (event) { case ConnectivityConstants.PacketKeepaliveCallbackStarted: return PacketKeepaliveReceiver.EVENT_STARTED; case ConnectivityConstants.PacketKeepaliveCallbackStopped: return PacketKeepaliveReceiver.EVENT_STOPPED; case ConnectivityConstants.PacketKeepaliveCallbackError: return PacketKeepaliveReceiver.EVENT_ERROR; } return PacketKeepaliveReceiver.EVENT_INVALID; } private static String getPacketKeepaliveReceiverEventString(int event) { switch (event) { case PacketKeepaliveReceiver.EVENT_STARTED: return ConnectivityConstants.PacketKeepaliveCallbackStarted; case PacketKeepaliveReceiver.EVENT_STOPPED: return ConnectivityConstants.PacketKeepaliveCallbackStopped; case PacketKeepaliveReceiver.EVENT_ERROR: return ConnectivityConstants.PacketKeepaliveCallbackError; } return ConnectivityConstants.PacketKeepaliveCallbackInvalid; } /** * Callbacks used in ConnectivityManager to confirm tethering has started/failed. */ class OnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback { @Override public void onTetheringStarted() { mEventFacade.postEvent(ConnectivityConstants.TetheringStartedCallback, null); } @Override public void onTetheringFailed() { mEventFacade.postEvent(ConnectivityConstants.TetheringFailedCallback, null); } } private final ConnectivityManager mManager; private NetworkPolicyManager mNetPolicyManager; private NetworkStatsManager mNetStatsManager; private final Service mService; private final Context mContext; private final ConnectivityReceiver mConnectivityReceiver; private final EventFacade mEventFacade; private PacketKeepalive mPacketKeepalive; private NetworkCallback mNetworkCallback; private static HashMap<String, PacketKeepaliveReceiver> mPacketKeepaliveReceiverMap = new HashMap<String, PacketKeepaliveReceiver>(); private static HashMap<String, NetworkCallback> mNetworkCallbackMap = new HashMap<String, NetworkCallback>(); private boolean mTrackingConnectivityStateChange; public ConnectivityManagerFacade(FacadeManager manager) { super(manager); mService = manager.getService(); mContext = mService.getBaseContext(); mManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE); mNetPolicyManager = NetworkPolicyManager.from(mContext); mNetStatsManager = (NetworkStatsManager) mService.getSystemService(Context.NETWORK_STATS_SERVICE); mEventFacade = manager.getReceiver(EventFacade.class); mConnectivityReceiver = new ConnectivityReceiver(); mTrackingConnectivityStateChange = false; } @Rpc(description = "Listen for connectivity changes") public void connectivityStartTrackingConnectivityStateChange() { if (!mTrackingConnectivityStateChange) { mTrackingConnectivityStateChange = true; mContext.registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); } } @Rpc(description = "start natt keep alive") public String connectivityStartNattKeepalive(Integer intervalSeconds, String srcAddrString, Integer srcPort, String dstAddrString) throws UnknownHostException { try { Network mNetwork = mManager.getActiveNetwork(); InetAddress srcAddr = InetAddress.getByName(srcAddrString); InetAddress dstAddr = InetAddress.getByName(dstAddrString); Log.d("startNattKeepalive srcAddr:" + srcAddr.getHostAddress()); Log.d("startNattKeepalive dstAddr:" + dstAddr.getHostAddress()); Log.d("startNattKeepalive srcPort:" + srcPort); Log.d("startNattKeepalive intervalSeconds:" + intervalSeconds); PacketKeepaliveReceiver mPacketKeepaliveReceiver = new PacketKeepaliveReceiver( PacketKeepaliveReceiver.EVENT_ALL); mPacketKeepalive = mManager.startNattKeepalive(mNetwork, (int) intervalSeconds, mPacketKeepaliveReceiver, srcAddr, (int) srcPort, dstAddr); if (mPacketKeepalive != null) { mPacketKeepaliveReceiver.mPacketKeepalive = mPacketKeepalive; String key = mPacketKeepaliveReceiver.mId; mPacketKeepaliveReceiverMap.put(key, mPacketKeepaliveReceiver); return key; } else { Log.e("startNattKeepalive fail, startNattKeepalive return null"); return null; } } catch (UnknownHostException e) { Log.e("startNattKeepalive UnknownHostException"); return null; } } @Rpc(description = "stop natt keep alive") public Boolean connectivityStopNattKeepalive(String key) { PacketKeepaliveReceiver mPacketKeepaliveReceiver = mPacketKeepaliveReceiverMap.get(key); if (mPacketKeepaliveReceiver != null) { mPacketKeepaliveReceiverMap.remove(key); mPacketKeepaliveReceiver.mPacketKeepalive.stop(); return true; } else { return false; } } @Rpc(description = "start listening for NattKeepalive Event") public Boolean connectivityNattKeepaliveStartListeningForEvent(String key, String eventString) { PacketKeepaliveReceiver mPacketKeepaliveReceiver = mPacketKeepaliveReceiverMap.get(key); if (mPacketKeepaliveReceiver != null) { int event = getPacketKeepaliveReceiverEvent(eventString); if (event == PacketKeepaliveReceiver.EVENT_INVALID) { return false; } mPacketKeepaliveReceiver.startListeningForEvents(event); return true; } else { return false; } } @Rpc(description = "stop listening for NattKeepalive Event") public Boolean connectivityNattKeepaliveStopListeningForEvent(String key, String eventString) { PacketKeepaliveReceiver mPacketKeepaliveReceiver = mPacketKeepaliveReceiverMap.get(key); if (mPacketKeepaliveReceiver != null) { int event = getPacketKeepaliveReceiverEvent(eventString); if (event == PacketKeepaliveReceiver.EVENT_INVALID) { return false; } mPacketKeepaliveReceiver.stopListeningForEvents(event); return true; } else { return false; } } @Rpc(description = "start listening for NetworkCallback Event") public Boolean connectivityNetworkCallbackStartListeningForEvent(String key, String eventString) { NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key); if (mNetworkCallback != null) { int event = getNetworkCallbackEvent(eventString); if (event == NetworkCallback.EVENT_INVALID) { return false; } mNetworkCallback.startListeningForEvents(event); return true; } else { return false; } } @Rpc(description = "stop listening for NetworkCallback Event") public Boolean connectivityNetworkCallbackStopListeningForEvent(String key, String eventString) { NetworkCallback mNetworkCallback = mNetworkCallbackMap.get(key); if (mNetworkCallback != null) { int event = getNetworkCallbackEvent(eventString); if (event == NetworkCallback.EVENT_INVALID) { return false; } mNetworkCallback.stopListeningForEvents(event); return true; } else { return false; } } @Rpc(description = "Set Rssi Threshold Monitor") public String connectivitySetRssiThresholdMonitor(Integer rssi) { Log.d("SL4A:setRssiThresholdMonitor rssi = " + rssi); NetworkRequest.Builder builder = new NetworkRequest.Builder(); builder.setSignalStrength((int) rssi); builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); NetworkRequest networkRequest = builder.build(); mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); mManager.registerNetworkCallback(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); return key; } @Rpc(description = "Stop Rssi Threshold Monitor") public Boolean connectivityStopRssiThresholdMonitor(String key) { Log.d("SL4A:stopRssiThresholdMonitor key = " + key); return connectivityUnregisterNetworkCallback(key); } private NetworkRequest buildNetworkRequestFromJson(JSONObject configJson) throws JSONException { NetworkRequest.Builder builder = new NetworkRequest.Builder(); if (configJson.has("ClearCapabilities")) { /* the 'ClearCapabilities' property does not have a value (that we use). Its presence is used to clear the capabilities of the constructed network request (which is constructed with some default capabilities already present). */ Log.d("build ClearCapabilities"); builder.clearCapabilities(); } if (configJson.has("TransportType")) { Log.d("build TransportType" + configJson.getInt("TransportType")); builder.addTransportType(configJson.getInt("TransportType")); } if (configJson.has("SignalStrength")) { Log.d("build SignalStrength" + configJson.getInt("SignalStrength")); builder.setSignalStrength(configJson.getInt("SignalStrength")); } if (configJson.has("Capability")) { JSONArray capabilities = configJson.getJSONArray("Capability"); for (int i = 0; i < capabilities.length(); i++) { Log.d("build Capability" + capabilities.getInt(i)); builder.addCapability(capabilities.getInt(i)); } } if (configJson.has("LinkUpstreamBandwidthKbps")) { Log.d("build LinkUpstreamBandwidthKbps" + configJson.getInt( "LinkUpstreamBandwidthKbps")); builder.setLinkUpstreamBandwidthKbps(configJson.getInt( "LinkUpstreamBandwidthKbps")); } if (configJson.has("LinkDownstreamBandwidthKbps")) { Log.d("build LinkDownstreamBandwidthKbps" + configJson.getInt( "LinkDownstreamBandwidthKbps")); builder.setLinkDownstreamBandwidthKbps(configJson.getInt( "LinkDownstreamBandwidthKbps")); } if (configJson.has("NetworkSpecifier")) { Log.d("build NetworkSpecifier" + configJson.getString("NetworkSpecifier")); builder.setNetworkSpecifier(configJson.getString( "NetworkSpecifier")); } NetworkRequest networkRequest = builder.build(); return networkRequest; } @Rpc(description = "register a network callback") public String connectivityRegisterNetworkCallback(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); mManager.registerNetworkCallback(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); return key; } @Rpc(description = "unregister a network callback") public Boolean connectivityUnregisterNetworkCallback(@RpcParameter(name = "key") String key) { mNetworkCallback = mNetworkCallbackMap.get(key); if (mNetworkCallback != null) { mNetworkCallbackMap.remove(key); mManager.unregisterNetworkCallback(mNetworkCallback); return true; } else { return false; } } @Rpc(description = "request a network") public String connectivityRequestNetwork(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); mManager.requestNetwork(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); return key; } @Rpc(description = "Request a Wi-Fi Aware network") public String connectivityRequestWifiAwareNetwork(@RpcParameter(name = "configJson") JSONObject configJson) throws JSONException { NetworkRequest networkRequest = buildNetworkRequestFromJson(configJson); if (networkRequest.networkCapabilities.getNetworkSpecifier() instanceof StringNetworkSpecifier) { String ns = ((StringNetworkSpecifier) networkRequest.networkCapabilities .getNetworkSpecifier()).specifier; JSONObject j = new JSONObject(ns); networkRequest.networkCapabilities.setNetworkSpecifier( WifiAwareManagerFacade.getNetworkSpecifier(j)); } mNetworkCallback = new NetworkCallback(NetworkCallback.EVENT_ALL); mManager.requestNetwork(networkRequest, mNetworkCallback); String key = mNetworkCallback.mId; mNetworkCallbackMap.put(key, mNetworkCallback); return key; } @Rpc(description = "Stop listening for connectivity changes") public void connectivityStopTrackingConnectivityStateChange() { if (mTrackingConnectivityStateChange) { mTrackingConnectivityStateChange = false; mContext.unregisterReceiver(mConnectivityReceiver); } } @Rpc(description = "Get the extra information about the network state provided by lower network layers.") public String connectivityNetworkGetActiveConnectionExtraInfo() { NetworkInfo current = mManager.getActiveNetworkInfo(); if (current == null) { Log.d("No network is active at the moment."); return null; } return current.getExtraInfo(); } @Rpc(description = "Return the subtype name of the current network, null if not connected") public String connectivityNetworkGetActiveConnectionSubtypeName() { NetworkInfo current = mManager.getActiveNetworkInfo(); if (current == null) { Log.d("No network is active at the moment."); return null; } return current.getSubtypeName(); } @Rpc(description = "Return a human-readable name describe the type of the network, e.g. WIFI") public String connectivityNetworkGetActiveConnectionTypeName() { NetworkInfo current = mManager.getActiveNetworkInfo(); if (current == null) { Log.d("No network is active at the moment."); return null; } return current.getTypeName(); } @Rpc(description = "Get connection status information about all network types supported by the device.") public NetworkInfo[] connectivityNetworkGetAllInfo() { return mManager.getAllNetworkInfo(); } @Rpc(description = "Check whether the active network is connected to the Internet.") public Boolean connectivityNetworkIsConnected() { NetworkInfo current = mManager.getActiveNetworkInfo(); if (current == null) { Log.d("No network is active at the moment."); return false; } return current.isConnected(); } @Rpc(description = "Checks the airplane mode setting.", returns = "True if airplane mode is enabled.") public Boolean connectivityCheckAirplaneMode() { try { return Settings.Global.getInt(mService.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON) == AIRPLANE_MODE_ON; } catch (Settings.SettingNotFoundException e) { Log.e("Settings.Global.AIRPLANE_MODE_ON not found!"); return false; } } @Rpc(description = "Toggles airplane mode on and off.", returns = "True if airplane mode is enabled.") public void connectivityToggleAirplaneMode(@RpcParameter(name = "enabled") @RpcOptional Boolean enabled) { if (enabled == null) { enabled = !connectivityCheckAirplaneMode(); } mManager.setAirplaneMode(enabled); } /** * Check global data roaming setting. * @return True if roaming is enabled; false otherwise. */ @Rpc(description = "Checks data roaming mode setting.", returns = "True if data roaming mode is enabled.") public Boolean connectivityCheckDataRoamingMode() { try { return Settings.Global.getInt(mService.getContentResolver(), Settings.Global.DATA_ROAMING) == DATA_ROAMING_ON; } catch (Settings.SettingNotFoundException e) { Log.e("Settings.Global.DATA_ROAMING not found!"); return false; } } /** * Enable or disable data roaming. * @param roaming 1: Enable data roaming; 0: Disable data roaming. * @return True for setting roaming mode successfully; false otherwise. */ @Rpc(description = "Set Data Roaming Enabled or Disabled") public boolean connectivitySetDataRoaming( @RpcParameter(name = "roaming") Integer roaming) { Log.d("connectivitySetDataRoaming by SubscriptionManager"); return Settings.Global.putInt(mService.getContentResolver(), Settings.Global.DATA_ROAMING, roaming); } @Rpc(description = "Check if tethering supported or not.", returns = "True if tethering is supported.") public boolean connectivityIsTetheringSupported() { return mManager.isTetheringSupported(); } @Rpc(description = "Call to start tethering with a provisioning check if needed") public void connectivityStartTethering(@RpcParameter(name = "type") Integer type, @RpcParameter(name = "showProvisioningUi") Boolean showProvisioningUi) { Log.d("startTethering for type: " + type + " showProvUi: " + showProvisioningUi); OnStartTetheringCallback tetherCallback = new OnStartTetheringCallback(); mManager.startTethering(type, showProvisioningUi, tetherCallback); } @Rpc(description = "Call to stop tethering") public void connectivityStopTethering(@RpcParameter(name = "type") Integer type) { Log.d("stopTethering for type: " + type); mManager.stopTethering(type); } private Enumeration<InetAddress> getInetAddrsForInterface(String ifaceName) { NetworkInterface iface = null; try { iface = NetworkInterface.getByName(ifaceName); } catch (SocketException e) { return null; } if (iface == null) return null; return iface.getInetAddresses(); } @Rpc(description = "Returns the link local IPv6 address of the interface.") public String connectivityGetLinkLocalIpv6Address(@RpcParameter(name = "ifaceName") String ifaceName) { Inet6Address inet6Address = null; Enumeration<InetAddress> inetAddresses = getInetAddrsForInterface(ifaceName); if (inetAddresses == null) { return null; } while (inetAddresses.hasMoreElements()) { InetAddress addr = inetAddresses.nextElement(); if (addr instanceof Inet6Address) { if (((Inet6Address) addr).isLinkLocalAddress()) { inet6Address = (Inet6Address) addr; break; } } } if (inet6Address == null) { return null; } return inet6Address.getHostAddress(); } @Rpc(description = "Return IPv4 address of an interface") public List<String> connectivityGetIPv4Addresses( @RpcParameter(name = "ifaceName") String ifaceName) { Enumeration<InetAddress> inetAddresses = getInetAddrsForInterface(ifaceName); if (inetAddresses == null) return null; List<String> inetAddrs = new ArrayList<String>(); while (inetAddresses.hasMoreElements()) { InetAddress addr = inetAddresses.nextElement(); if (addr instanceof Inet4Address) { Inet4Address inet4Address = (Inet4Address) addr; inetAddrs.add(inet4Address.getHostAddress()); } } return inetAddrs; } @Rpc(description = "Return IPv6 addrs of an interface except link local") public List<String> connectivityGetIPv6Addresses( @RpcParameter(name = "ifaceName") String ifaceName) { Enumeration<InetAddress> inetAddresses = getInetAddrsForInterface(ifaceName); if (inetAddresses == null) return null; List<String> inetAddrs = new ArrayList<String>(); while (inetAddresses.hasMoreElements()) { InetAddress addr = inetAddresses.nextElement(); if (addr instanceof Inet6Address) { if (((Inet6Address) addr).isLinkLocalAddress()) continue; Inet6Address inet6Address = (Inet6Address) addr; inetAddrs.add(inet6Address.getHostAddress()); } } return inetAddrs; } @Rpc(description = "Returns active link properties") public LinkProperties connectivityGetActiveLinkProperties() { return mManager.getActiveLinkProperties(); } @Rpc(description = "Returns all IP addresses of the active link") public List<InetAddress> connectivityGetAllAddressesOfActiveLink() { LinkProperties linkProp = mManager.getActiveLinkProperties(); return linkProp.getAllAddresses(); } @Rpc(description = "Check if active link has default IPv6 route") public boolean connectivityHasIPv6DefaultRoute() { LinkProperties linkProp = mManager.getActiveLinkProperties(); return linkProp.hasIPv6DefaultRoute(); } @Rpc(description = "Factory reset of network policies") public void connectivityFactoryResetNetworkPolicies(String subscriberId) { mNetPolicyManager.factoryReset(subscriberId); } /** * Method to set data warning limit on the device. */ @Rpc(description = "Set data warning limit for subscriber ID") public void connectivitySetDataWarningLimit(String subscriberId, Long dataLimit) { NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies(); for (int i = 0; i < allPolicies.length; i++) { String subId = allPolicies[i].template.getSubscriberId(); if (subId != null && subId.equals(subscriberId)) { allPolicies[i].warningBytes = dataLimit.longValue(); break; } } mNetPolicyManager.setNetworkPolicies(allPolicies); } /** * Method to set data usage limit on the device. */ @Rpc(description = "Set data usage limit for subscriber ID") public void connectivitySetDataUsageLimit(String subscriberId, Long dataLimit) { NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies(); for (int i = 0; i < allPolicies.length; i++) { String subId = allPolicies[i].template.getSubscriberId(); if (subId != null && subId.equals(subscriberId)) { allPolicies[i].limitBytes = dataLimit.longValue(); break; } } mNetPolicyManager.setNetworkPolicies(allPolicies); } /** * Method to get data usage limit on the device. */ @Rpc(description = "Get data usage limit for subscriber ID") public long connectivityGetDataUsageLimit(String subscriberId) { NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies(); for (int i = 0; i < allPolicies.length; i++) { String subId = allPolicies[i].template.getSubscriberId(); if (subId != null && subId.equals(subscriberId)) return allPolicies[i].limitBytes; } return -1; } /** * Method to get data warning limit on the device */ @Rpc(description = "Get data warning limit for subscriber ID") public long connectivityGetDataWarningLimit(String subscriberId) { NetworkPolicy[] allPolicies = mNetPolicyManager.getNetworkPolicies(); for (int i = 0; i < allPolicies.length; i++) { String subId = allPolicies[i].template.getSubscriberId(); if (subId != null && subId.equals(subscriberId)) return allPolicies[i].warningBytes; } return -1; } @Rpc(description = "Get network stats for device") public long connectivityQuerySummaryForDevice(Integer connType, String subscriberId, Long startTime, Long endTime) throws SecurityException, RemoteException { Bucket bucket = mNetStatsManager.querySummaryForDevice( connType, subscriberId, startTime, endTime); return bucket.getTxBytes() + bucket.getRxBytes(); } @Rpc(description = "Get network stats for device - Rx bytes") public long connectivityQuerySummaryForDeviceRxBytes(Integer connType, String subscriberId, Long startTime, Long endTime) throws SecurityException, RemoteException { Bucket bucket = mNetStatsManager.querySummaryForDevice( connType, subscriberId, startTime, endTime); return bucket.getRxBytes(); } @Rpc(description = "Get network stats for UID") public long connectivityQueryDetailsForUid(Integer connType, String subscriberId, Long startTime, Long endTime, Integer uid) throws SecurityException, RemoteException { long totalData = 0; NetworkStats netStats = mNetStatsManager.queryDetailsForUid( connType, subscriberId, startTime, endTime, uid); Bucket bucket = new Bucket(); while(netStats.hasNextBucket() && netStats.getNextBucket(bucket)) { totalData += bucket.getTxBytes() + bucket.getRxBytes(); } netStats.close(); return totalData; } @Rpc(description = "Get network stats for UID - Rx bytes") public long connectivityQueryDetailsForUidRxBytes(Integer connType, String subscriberId, Long startTime, Long endTime, Integer uid) throws SecurityException, RemoteException { long rxBytes = 0; NetworkStats netStats = mNetStatsManager.queryDetailsForUid( connType, subscriberId, startTime, endTime, uid); Bucket bucket = new Bucket(); while(netStats.hasNextBucket() && netStats.getNextBucket(bucket)) { rxBytes += bucket.getRxBytes(); } netStats.close(); return rxBytes; } @Rpc(description = "Returns all interfaces on the android deivce") public List<NetworkInterface> connectivityGetNetworkInterfaces() { List<NetworkInterface> interfaces = null; try { interfaces = Collections.list( NetworkInterface.getNetworkInterfaces()); } catch (SocketException e) { return null; }; return interfaces; } /** * Get multipath preference for a given network. * @param networkId : network id of wifi or cell network * @return Integer value of multipath preference */ @Rpc(description = "Return Multipath preference for a given network") public Integer connectivityGetMultipathPreferenceForNetwork(Long networkId) { Network network = sNetworkHashMap.get(networkId.longValue()); return mManager.getMultipathPreference(network); } /** * Return HashMap key for Network object. * @return long value of Network object key */ @Rpc(description = "Return key to active network stored in a hash map") public long connectivityGetActiveNetwork() { Network network = mManager.getActiveNetwork(); long id = network.getNetworkHandle(); sNetworkHashMap.put(id, network); return id; } /** * Get mutlipath preference for active network. * @return Integer value of multipath preference */ @Rpc(description = "Return Multipath preference for active network") public Integer connectivityGetMultipathPreference() { Network network = mManager.getActiveNetwork(); return mManager.getMultipathPreference(network); } /** * Download file of a given url using Network#openConnection call. * @param networkId : network id of wifi or cell network * @param urlString : url in String format */ @Rpc(description = "Download file on a given network with Network#openConnection") public void connectivityNetworkOpenConnection(Long networkId, String urlString) { Network network = sNetworkHashMap.get(networkId.longValue()); try { URL url = new URL(urlString); URLConnection urlConnection = network.openConnection(url); File outFile = FileUtils.getExternalDownload(); int lastIdx = urlString.lastIndexOf('/'); String filename = urlString.substring(lastIdx + 1); Log.d("Using name from url: " + filename); outFile = new File(outFile, filename); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); OutputStream output = new FileOutputStream(outFile); ByteStreams.copy(in, output); } catch (IOException e) { Log.e("Failed to download file: " + e.toString()); } } @Override public void shutdown() { connectivityStopTrackingConnectivityStateChange(); } }