I am working with android wifi direct demo application. After installation in my device I noticed that it is not working as expected.
I am confused, does my device support wifi direct or special hardware feature required for wifi direct? My device is local walton brand and API level 16. After reading android documentation i know that Wi-Fi Direct added in API level 14 doesn't need a wireless access point.
My other question is if in a place where no wifi zone is created using wifi direct two or more device communicate with each other. in summing my problem, i need to know if my device not support wifi direct what i do to run wifi demo. Thanks in advance.
you should check in this way, because some devices do not support WiFi direct but still keep the WifiP2pManager code in framework.
private boolean isWifiDirectSupported(Context ctx) {
PackageManager pm = ctx.getPackageManager();
FeatureInfo[] features = pm.getSystemAvailableFeatures();
for (FeatureInfo info : features) {
if (info != null && info.name != null && info.name.equalsIgnoreCase("android.hardware.wifi.direct")) {
return true;
}
}
return false;
}
In addition to StoneLam's answer, which is probably the most robust, a quicker-and-dirtier method would be to go ahead and call WifiP2pManager.discoverPeers() as you would if WiFi Direct were supported. The latter takes an ActionListener with an onFailure() callback. The failure reason passed to onFailure(int reason) can be P2P_UNSUPPORTED, which would answer your question: the device doesn't support WiFi Direct.
A call to onSuccess() would mean the device does support WiFi Direct. A call to onFailure() with other failure reasons would probably be inconclusive as to the device's capabilities.
Android 4.0 and later support Wi-Fi Direct. However, some of 4.x devices does not support Wi-Fi Direct because of it's WiFi driver
you can check your device using the code below
mManager.discoverPeers(mChannel, new ActionListener() {
#Override
public void onSuccess() {
//onSuccess
}
#Override
public void onFailure(int reason) {
//onFailure
}
});
If your device support Wi-Fi Direct, onSuccess will be called after a moment. Otherwise, onFailure will be called.
Above API 21 you can directly use isP2pSupported () from WifiManager class.
For lower Api's you can use PackageManager class,
if(getPackageManager().hasSystemFeature("android.hardware.wifi.direct"))
//Wifi direct available
Checking if Wifi P2P is supported:
In code: If you cannot get the system service, it's not supported
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Without code: Check whether the option is in the Settings app (Under Wifi)
As per your second question: yes, devices connected via wifi direct communicate without any existing wifi network.
Related
I wrote an app that is triggering a Sony qx smartphone attachable camera over wifi. However I need to transfer the images off the phone over another local network in real time. Since the wifi card is being used for qx connection I need to be able to use ethernet over usb for transferring images off the phone. Http requests will be used to trigger the camera and send the images off the phone.
Is it possible in one android app on a phone with two network interfaces setup to specify for certain http requests to use one network interface and for others to use another network interface ? Does this need to be done through routing tables, not java?
The phone I'm using is a rooted nexus 6p.
Update:
Currently, I was able to get an Ethernet adapter working with the device (Nexus 6P). The device is connected to a local network over Ethernet. When the Wi-Fi interface is off, I can ping all devices on the local network the device is connected to over Ethernet. However, I am unable to access the web servers (Not using DNS) of any of the devices on that network (which I know they are running), i.e. Http via a browser app. The nexus 6p is connected to the network over Ethernet via a Ubiquiti Station. This seems to be a routing issue.
I can tether(usb interface) and use Wi-Fi in one app, so that leads me to believe it is possible to use Ethernet and Wi-Fi.
Update2:
After more testing, it seems to be that it is a permissions issue. Since when I ping the network the device is connected to over Ethernet without first running su in the terminal the network doesn't exist. However, when I run su then ping, I can ping the network. Thus it seems my app needs to get superuser permission before accessing Ethernet. I've granted it superuser access, but nothing has changed. I read that simply running su isn't enough from one of the comments in this post. This is because su just spawns a root shell that dies. This also explains why I couldn't access any of the web servers on this network via a browser app. Is it possible to grant my app access to the Ethernet interface when making HTTP calls like give HttpURLConnection root access, if that makes any sense (running su doesn't work)? There seems to definitely be a solution since HttpURLConnection can make calls over the USB tethering interface (Nexus 6P calls it rndis0) fine.
Update 3:
I found online here , that I can make my app a System app (thought this might grant the app eth0 access). I just moved my app to /system/app and then rebooted. However, this didn't seem to give the app anymore privileges (thus not solving the problem) , or there is something else required to make the app system than just copying it to /system/app.
Update 4:
So I was able to get Ethernet working on every app without root permissions! It seemed to be that it only works over DHCP and does not like static connections, which I was using. It works with Wi-Fi enabled, however, I cannot contact any of the devices on the Wi-Fi network when Ethernet is enabled. Is there a way around this? Does it have to do with setting two default gateways?
Since you were programming in Nexus 6P, you can try to use the new API added in ConnectivityManager to select the ethernet as your preferred network connection for your process.
Since I can't build the similar environment like yours, I am not sure if it works. It's just a suggested solution, totally not tested and verified.
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
Network etherNetwork = null;
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if (networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {
etherNetwork = network;
}
}
Network boundNetwork = connectivityManager.getBoundNetworkForProcess();
if (boundNetwork != null) {
NetworkInfo boundNetworkInfo = connectivityManager.getNetworkInfo(boundNetwork);
if (boundNetworkInfo.getType() != ConnectivityManager.TYPE_ETHERNET) {
if (etherNetwork != null) {
connectivityManager.bindProcessToNetwork(etherNetwork);
}
}
}
Just to give a little more explanation on how this finally got solved.
Utilizing #alijandro's answer I was able to switch back and forth between Ethernet and Wi-Fi in one app. For some reason for the Ethernet to work it required the network gateway to supply DHCP address, not static. Then since the bindProcessToNetwork, used in #alijandro's answer is per-process, I decided to split communications with the QX camera into a Service that runs in a separate Process. The main Application (another process) would post images over Ethernet to a local network. I was successfully able to contact the devices on the local network via HTTP over Ethernet while simultaneously triggering the QX over Wi-Fi. Currently, I used Messenger to communicate using IPC to tell the QX triggering Service what methods to call.
Most of android tv boxes can use wifi and ethernet together. In my device, i can enable ethernet from this path ---
Settings -> More ... > Ethernet ---
But your device wont have a menu like that as i understand. So you should make an app to do that. This application needs to access some system specific resources so your device needs to be rooted or application needs to signed with system signature.
Also this topic can help you link
There is an easy way to do this that will answer the OP's original question about how to do this with a single application (not two separate app processes) using ConnectivityManager.requestNetwork().
The docs for ConnectivityManager.requestNetwork() allude to this:
... For example, an application could use this method to obtain a
connected cellular network even if the device currently has a data
connection over Ethernet. This may cause the cellular radio to consume
additional power. Or, an application could inform the system that it
wants a network supporting sending MMSes and have the system let it
know about the currently best MMS-supporting network through the
provided NetworkCallback. ...
For OP's scenario of using Wi-Fi for some traffic and ethernet for other traffic one only needs to call ConnectivityManager.requestNetwork() twice with two separate requests. One for TRANSPORT_WIFI and one for TRANSPORT_ETHERNET. The operative item here is we need a way to uniquely identify these networks. For OP's scenario, we can use transport type.
final NetworkRequest requestForWifi =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
final NetworkRequest requestForEthernet =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build();
final ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkCallback networkCallbackWifi = new NetworkCallback() {
#Override
void onAvailable(Network network) {
// Triggers when this network is available so you can bind to it.
}
#Override
void onLost(Network network) {
// Triggers when this network is lost.
}
};
final NetworkCallback networkCallbackEthernet = new NetworkCallback() {
#Override
void onAvailable(Network network) {
// Triggers when this network is available so you can bind to it.
}
#Override
void onLost(Network network) {
// Triggers when this network is lost.
}
};
connectivityManager.requestNetwork(requestForWifi, networkCallbackWifi);
connectivityManager.requestNetwork(requestForEthernet, networkCallbackEthernet);
Then, once the callbacks trigger, you can then in the pertinent code (e.g. OP's code for transferring images), listen for onAvailable(Network network) and use the provided Network with Network.OpenConnection() to connect to an HTTP server using that network.
This would allow you to connect to two separate Networks from the same application.
I need to get the list of devices (and possible details of them as well) that are connected to the Wi-Fi which is I have connected to. I don't need to connect and chat with any of them. I'm going through this link http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html#fetch.
Is wifi p2p connection works for my requirement? How do I get the list of connected devices on the device with no Wifi-Direct feature? Do my app needs to be installed on other devices in order to use wifi p2p connection? I have tried this https://github.com/rorist/android-network-discovery but it is force closing on launch of app. I've seen same kind of apps on playstore like Fing. How did they do this?
Please help me. Thanks in advance.
manager=(WifiP2pManager)getSystemService(WIFI_P2P_SERVICE);
channel=manager.initialize(this, Looper.getMainLooper(),null);
When PEERS CHANGE.. call..
manager.requestPeers(channel, new WifiP2pManager.PeerListListener() {
#Override
public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {
Log.e("peer num", "" + wifiP2pDeviceList.getDeviceList().size());
devices.clear();
devices.addAll(wifiP2pDeviceList.getDeviceList());
for(WifiP2pDevice device:wifiP2pDeviceList.getDeviceList()){
//Log.e("device ",device.toString());
dnames.clear();
daddresses.clear();
dnames.add(device.deviceName);
daddresses.add(device.deviceAddress);
}
}
});
I want to connect my tablet to my phone using WiFi direct in order to send some data like pictures etc from my phone to tablet.
But I do not want my phone to discover it first i.e I don't wanted to use discoverPeers() method of WiFiP2pManger.
How can I achieve this goal?
In your phone, use createGroups(). This makes your phone become the groupOwner. Then call discoverPeers() in your tablet, it will find your phone without your phone calling discoverPeers().
In your phone:
wifiP2pManager = (WifiP2pManager) context.getSystemService(context.WIFI_P2P_SERVICE);
channel=wifiP2pManager.initialize(context,context.getMainLooper(),null);
wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.i(TAG,"Creating p2p group");
}
#Override
public void onFailure(int i) {
Log.i(TAG,"Creating group failed, error code:"+i);
}
});
In your tablet, discover peers, request peers and connect peers as normal
In order to establish a WiFi Direct connection both phones should be running WiFi Direct discovery. In other words, they will see each other when they are both scanning for WiFi direct connections at the same time. This is because the way WiFi Direct works is that when phones are scanning for WiFi Direct connections, they will negotiate with the other peers for the role of Access Point or Slave device. Hence both need to call discoverPeers() to become discoverable themselves and find nearby devices.
In your use case you could even build your application using wifi hotspot
This solution doesn't work. In Android both need to be on discovery mode in order to connect.
As of Android 4.1, your device can detect if it's connected to a mobile hotspot (given that the mobile hotspot is also running Android 4.1 or higher). Also, you have the option to flag networks as mobile hotspots (under Settings / Data Usage / Overflow menu / Mobile Hotspots).
But how do I detect this as a -user- I meant developer? It's not stored in the WifiConfiguration, so where is it?
Some context: I want to build a simple tool for Android that checks if you are connected to a network that you or Android has flagged as a mobile hotspot. If so, it will check if no other (non-hotspot) networks are available. If so, it should connect to these other networks since those should be much faster and have no data cap. Why? Because my phones and tablets connect to (mobile) hotspots quite often, even when a better network is available.
Here is some pseudo code of what I'm looking for:
// Check if android has detected mobile hotspot
WifiManager wifiMgr = getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiMgr .getConnectionInfo();
boolean isMobileHotspot = wifiInfo.isMobileHotspot;
UPDATE Jul 3rd 2014
Okay so Matiash' answer is good but ConnectivityManager.isActiveNetworkMetered() will only return the value for the current network. I do need that, so it helped me along, but it bring me to the next part in my tool/app:
IF the device is connected to a mobile hotspot (or a 'metered network' as Android calls it) I want to check if any of the nearby access points is a better option. So I need to know whether any of the known AP's (WifiManager.getConfiguredNetworks()) is also flagged as such before I connect to it...
I have a List<ScanResult> and a List<WifiConfiguration>, looks like neither of them has this information.
Which bring me back to my initial question: Is there a way to retrieve the Mobile Hotspots (as configured by Android and/or user) under Data Usage? And this time I mean ALL of them.
UPDATE Jul 7th 2014
I've posted a feature request in the AOSP Issue Tracker for access (readonly) to the NetworkPolicyManager. Plz vote on it here: https://code.google.com/p/android/issues/detail?id=73206&thanks=73206&ts=1404719243
You can access this information by calling ConnectivityManager.isActiveNetworkMetered().
This will return whether the active connection is a hotspot (as defined in Data Usage -> Mobile Hotspots).
About the second part, I'm sorry but I don't think that's possible. The flag is not public, and even if you get the object that could be used to retrieve it (android.net.NetworkPolicyManager) by reflection:
Object npm = Class.forName("android.net.NetworkPolicyManager").getDeclaredMethod("from", Context.class).invoke(null, this);
Object policies = npm.getClass().getDeclaredMethod("getNetworkPolicies").invoke(npm);
calling getNetworkPolicies() requires the MANAGE_NETWORK_POLICY permission, which cannot be obtained by non-system apps, because it has a "signature" protection level.
I hope to be proved incorrect though. :) Maybe looking at the source code of the Android activity that manages this information (https://github.com/android/platform_packages_apps_settings/blob/master/src/com/android/settings/net/DataUsageMeteredSettings.java), in particular the buildWifiPref() method, will provide some clue.
I do not know if what you want is possible but you can check whether your device is connected to a network by checking the ip.
You can use the tool below to see if you has ip, and shalt know if he is connected to a network or not.
public static Boolean check_connection(final Context _context)
{
boolean connected;
ConnectivityManager conectivtyManager = (ConnectivityManager) _context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conectivtyManager.getActiveNetworkInfo() != null
&& conectivtyManager.getActiveNetworkInfo().isAvailable()
&& conectivtyManager.getActiveNetworkInfo().isConnected())
{
connected = true;
} else
{
connected = false;
}
return connected;
}
//Check if hotspot tethering is enabled
try {
ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isMobileData = connectivityManager.isActiveNetworkMetered();
if(isMobileData) {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface networkInterface : interfaces) {
if (networkInterface.getName().equals("ap0")) {
//Tethering is enabled
SendHotspotEnabledHandler sendHotspotEnabledHandler = new SendHotspotEnabledHandler(new WeakReference<Context>(SendInstalledAppsService.this));
sendHotspotEnabledHandler.execute();
break;
}
}
}
} catch (SocketException e) {
}
I am analysing Android JellyBean 4.3 source code.I could find the varialbe p2p_supported in HAL layer for Wi-Fi Direct support. In the below code snippet from wifi_ath.c
int wifi_start_supplicant(int p2p_supported)
{
if (p2p_supported)
{
strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
strcpy(supplicant_prop_name, P2P_PROP_NAME); // for P2P support
.......................
}
else {
strcpy(supplicant_name, SUPPLICANT_NAME);
strcpy(supplicant_prop_name, SUPP_PROP_NAME); //for station support
}
The values of the macros are:
P2P_SUPPLICANT_NAME = p2p_supplicant ,P2P_PROP_NAME= init.svc.p2p_supplicant
SUPPLICANT_NAME=wpa_supplicant ,SUPP_PROP_NAME=init.svc.wpa_supplicant
Even while connecting in station mode the if part is getting executed and I could not make the WiFi up. Where in the code exactly p2p_supported variable is enabled and disabled so that both the P2P and Wi-Fi works smoothly?
From Jelly Bean(4.1) you only need to turn WiFi on to use WiFi Direct functionality, though using both together depends upon whether your chip supports it.(For that see this SO question)