I configured ESP8266-01 as an access point. After connecting to ESP wifi network as a client, on-click events of the android app try to send data using AsyncTask which uses a socket to send data to ESP88266 (access point). by on-click events, I can send led/on or led/off commands. hence led will toggle when I press two buttons. I used a toast in public void onPostExecute(final String Data) in AsyncTask to determine what data is sent back by the server(ESP) to the android app as its client. I have expected to receive a kind of JSON response containing "on" or "off" as acknowledge since ESP Sends the response to the client(client.println(s);) when I click on buttons I can turn led on or off but received data on public void onPostExecute(final String Data) section of the app always contains null.ESP default access point IP address is 192.168.4.1 then using a browser I can send 192.168.4.1/led/on to turn led on and the browser immediately shows{"data":{"message":"success","value":"off"}}as JSON response but I need to have an acknowledgment for the designed android app.
How can I get any kind of acknowledgment from ESP in my android app?
Any help is appreciated.
here are ESP code from Arduino IDE and MainActivity code of the android app.
ESP code:
#include<ESP8266WiFi.h>
// WiFi Definitions
const char* ssid = "DigitalCalendar";
const char* password = "Esp8266Test"; // has to be longer than 7 chars
const char* value = "";
int ledPin = 2; // GPIO 2
WiFiServer server(80);
void setup() {
Serial.begin(9600);
delay(10);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH); // turn on
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password, 1, false);
server.begin();
}
void loop() {
// Check of client has connected
WiFiClient client = server.available();
if(!client) {
return;
}
// Read the request line
String request = client.readStringUntil('\r');
Serial.print(request+'\r');
// Match request
if(request.indexOf("/led/on") != -1) {
digitalWrite(ledPin, HIGH);
value = "on";
} else if (request.indexOf("/led/off") != -1) {
digitalWrite(ledPin, LOW);
value = "off";
}
client.flush();
// JSON response
String s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: application/json\r\n\r\n";
s += "{\"data\":{\"message\":\"success\",\"value\":\"";
s += value;
s += "\"}}\r\n";
s += "\n";
// Send the response to the client
client.println(s);
delay(1);
//Serial.println("Client disconnected");
// The client will actually be disconnected when the function returns and the client object is destroyed
}
MAIN ACTIVITY code:
public class MainActivity extends AppCompatActivity {
private static final int LOCATION = 1;
Button btn1,btn2;
String command;
String networkSSID = "Esp8266TestNet";
String networkPass = "Esp8266Test";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=findViewById(R.id.btn1);
btn2=findViewById(R.id.btn2);
//------------------------------------------------------
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
command="/led/on\r";
send_request(command);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
command="/led/off\r";
send_request(command);
}
});
}
public void send_request(String message) {
send_request sr = new send_request();
sr.execute(message);
}
class send_request extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... message) {
try {
/*note : ip address must be in Quotation mark*/
/*note : port doesn't need to be inside the Quotation mark*/
Socket s = new Socket(/*ip address :*/"192.168.4.1",/*port :*/ 80);
PrintWriter printWriter = new PrintWriter(s.getOutputStream());
printWriter.write(message[0]);
printWriter.flush();
printWriter.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public void onPostExecute(final String Data) {
/*Data is what you receive from your server*/
Log.e("my_Data","Data is : " + Data);
Toast.makeText(MainActivity.this, Data, Toast.LENGTH_SHORT).show();
}
}
protected void onStart() {
super.onStart();
//Assume you want to read the SSID when the activity is started
tryToReadSSID();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == LOCATION){
//User allowed the location and you can read it now
tryToReadSSID();
}
}
private String tryToReadSSID() {
String ssid="no ssid";
//If requested permission isn't Granted yet
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//Request permission from user
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION);
}else{//Permission already granted
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if(wifiInfo.getSupplicantState() == SupplicantState.COMPLETED){
ssid = wifiInfo.getSSID();//Here you can access your SSID
}
}
return ssid;
}
}
I am trying that opening Wifi hotspot in android,When I run below code it runs successfully for Api 28 I can open Wifi hotspot without getting errror but When I run it in Api 25 for Android 7.1 device it gets below errors, it says get WRITE_SETTINGS permission,but When I tested for Api 28 it doesn't necessary for running application,Why can I get this errros and How can I run it for android Api 25
Getting Errors
W/System.err: java.lang.NoSuchMethodException: setWifiApEnabled [class android.net.wifi.WifiConfiguration, boolean]
at java.lang.Class.getMethod(Class.java:1981)
at java.lang.Class.getMethod(Class.java:1637)
at com.kocsistem.pixageoneandroid.utils.Utils.configApState(Utils.java:1126)
at com.kocsistem.pixageoneandroid.utils.Utils.openHotspot(Utils.java:1095)
at com.kocsistem.pixageoneandroid.network.broadcast.NetworkChangeReceiver$2.run(NetworkChangeReceiver.java:120)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Open Hotspot code
public static void openHotspot(Context context,boolean enable){
WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
assert manager != null;
try {
manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
#SuppressLint("SetTextI18n")
#Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
Log.i("Wifi Hotspot is on now , reservation is : %s", reservation.toString());
mReservation = reservation;
WifiManager.LocalOnlyHotspotReservation mReservation = reservation;
String key = mReservation.getWifiConfiguration().preSharedKey;
Log.i("key:",key);
String ussid = mReservation.getWifiConfiguration().SSID;
Log.i("ussid:",ussid);
}
#Override
public void onStopped() {
super.onStopped();
Log.i("onStopped: ","");
}
#Override
public void onFailed(int reason) {
super.onFailed(reason);
Log.i("onFailed: ","");
}
}, new Handler());
}catch (Exception e){
e.printStackTrace();
}
}else{
//for Api<26
configApState(context);
}
}
check whether wifi hotspot on or off
public static boolean isApOn(Context context) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
try {
Method method = wifimanager.getClass().getDeclaredMethod("isWifiAp Enabled");
method.setAccessible(true);
return (Boolean) method.invoke(wifimanager);
}
catch (Throwable ignored) {}
return false;
}
toggle wifi hotspot on or off
public static boolean configApState(Context context) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
// if WiFi is on, turn it off
if(isApOn(context)) {
wifimanager.setWifiEnabled(false);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled ", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, !isApOn(context));
return true;
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}
this code works for Android Api 26 (Oreo) and above , its not gonna work with nougat (api 25)
there is another way to do that , you have to get method called "setWifiApEnabled" Check this peace of code
PS: you have to convert the code from c# to java and dont forget to grant the write settings permission ...
private bool ActivateTethering(string ssid, string password)
{
var myConfiguration = new WifiConfiguration();
WifiManager wifimanager = (WifiManager)Context.GetSystemService(Context.WifiService);
myConfiguration.Ssid = ssid;
myConfiguration.PreSharedKey = password;
myConfiguration.AllowedAuthAlgorithms.Set((int)AuthAlgorithmType.Shared);
myConfiguration.AllowedProtocols.Set((int)ProtocolType.Rsn);
myConfiguration.AllowedProtocols.Set((int)ProtocolType.Wpa);
myConfiguration.AllowedKeyManagement.Set((int)KeyManagementType.WpaPsk);
var enableWifi = wifimanager.Class.GetDeclaredMethods();
try
{
bool setWifiConfig = false;
foreach (var method in enableWifi)
{
if (method.Name.Equals("setWifiApEnabled"))
{
setWifiConfig = (bool)method.Invoke(wifimanager, myConfiguration, true);
break;
}
}
}
catch (InvocationTargetException e)
{
Console.WriteLine(e.Data.ToString());
}
return setWifiConfig ;
}
I am working on a mobile chat application, last few days I started facing issues with connection (my case is first time my connection works fine but when my app got disconnected (by loosing net connection or wifi turned off or poor network) then my app is reconnected but not able to send messages but at the same time app can receive message): For reconnection I am using reconnectionmanager
I am using smack4.1 library.
Error Details: Client is not or no longer connected
Thanks
my connection and reconnection code is -
XMPPTCPConnectionConfiguration.Builder connConfig = XMPPTCPConnectionConfiguration
.builder();
connConfig
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
connConfig.setUsernameAndPassword(user, pass);
connConfig.setServiceName(SERVICE_NAME);
connConfig.setHost(SERVER_HOST);
connConfig.setPort(SERVER_PORT);
connConfig.setDebuggerEnabled(true);
connConfig.setConnectTimeout(25000);
XMPPTCPConnectionConfiguration configuration = connConfig.build();
connection = new XMPPTCPConnection(configuration);
connection.setUseStreamManagement(true);
connection.setUseStreamManagementResumption(true);
connection.setReplyToUnknownIq(true);
connection.setPacketReplyTimeout(25000);
ReconnectionManager manager = ReconnectionManager.getInstanceFor(connection);
manager.setFixedDelay(10);
ReconnectionManager.setDefaultReconnectionPolicy (ReconnectionManager.ReconnectionPolicy.FIXED_DELAY);
manager.enableAutomaticReconnection();
ReconnectionManager.setEnabledPerDefault(true);
connection.addConnectionListener(new ConnectionListener() {
#Override
public void connected(XMPPConnection xmppConnection) {
IsConnected = true;
}
#Override
public void authenticated(XMPPConnection xmppConnection, boolean bt) {}
#Override
public void connectionClosed() {
IsConnected = false;
}
#Override
public void connectionClosedOnError(Exception e) {
IsConnected = false;
}
#Override
public void reconnectionSuccessful() {
IsConnected = true;
}
#Override
public void reconnectingIn(int i) {
}
#Override
public void reconnectionFailed(Exception e) {
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
For sending message to user
connection.sendStanza(messsageObj);
I am trying to sent message from android client to Mac OS X over bluetooth.
I am using bluecove 2.0.1 Java bluetooth library on Mac OS X Snow Leopard.
Code for Server:
public class EchoServer2 {
private static final String UUID_STRING = "00001101-0000-1000-8000-00805F9B34FB"; // 32 hex digits
private static final String SERVICE_NAME = "echoserver";
private LocalDevice mLocalDevice;
public EchoServer2() {
try {
mLocalDevice = LocalDevice.getLocalDevice();
} catch(IOException e) {
System.err.print("Error connection to bluetooth");
}
}
public void start() throws IOException {
StreamConnectionNotifier connectionNotifier =
(StreamConnectionNotifier) Connector.open(
"btspp://localhost:" + UUID_STRING +
";name=" + SERVICE_NAME + ";authenticate=false");
System.out.println("Bluetooth Address: " + mLocalDevice.getBluetoothAddress());
System.out.println("Waiting for a connection...");
StreamConnection streamConnection = connectionNotifier.acceptAndOpen();
System.out.println("Found a new device.");
RemoteDevice device = RemoteDevice.getRemoteDevice(streamConnection);
System.out.println("New Device connected: " + device.getFriendlyName(false).toString());
DataInputStream is = streamConnection.openDataInputStream();
byte[] bytes = new byte[1024];
int r;
while((r = is.read(bytes)) > 0) {
System.out.println(new String(bytes, 0, r));
}
}
}
Code for Android client:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
EditText editText;
TextView textView;
String send_msg;
String rcv_msg;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 32 hex digits
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
editText = (EditText) findViewById(R.id.edit_msg);
textView = (TextView) findViewById(R.id.rcv_msg);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if(adapter == null) {
textView.append("Bluetooth NOT Supported!");
return;
}
// Request user to turn ON Bluetooth
if(!adapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, RESULT_OK);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void onClick(View view) {
Log.d(TAG, "onClick");
new SendMessageToServer().execute(send_msg);
}
private class SendMessageToServer extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... msg) {
Log.d(TAG, "doInBackground");
BluetoothSocket clientSocket = null;
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable();
// Client knows the server MAC address
BluetoothDevice mmDevice = mBluetoothAdapter.getRemoteDevice("00:25:00:C3:1C:FE");
Log.d(TAG, "got hold of remote device");
Log.d(TAG, "remote device: " + mmDevice.getName().toString());
try {
// UUID string same used by server
clientSocket = mmDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
Log.d(TAG, "bluetooth socket created");
mBluetoothAdapter.cancelDiscovery(); // Cancel, discovery slows connection
clientSocket.connect();
Log.d(TAG, "connected to server");
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
out.writeUTF(msg[0]); // Send message to server
Log.d(TAG, "Message Successfully sent to server");
return in.readUTF(); // Read response from server
} catch (Exception e) {
Log.d(TAG, "Error creating bluetooth socket");
Log.d(TAG, e.getMessage());
return "";
}
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "onPostExecute");
rcv_msg = result;
textView.setText(rcv_msg);
}
}
}
I am not able to connect to server even though the UUID are same both for client and server.
Android throws an exception: Service Discovery failed.
However I am able to print the name of remote device (client) on the server. Hence acceptAndOpen() is unable to accept the socket connection.
Please help me in understanding as to why I am unable to clientSocket.connect(); on android ?
Im gonna take a guess and say it has something to do with the UUID numbers you used. They depend solely on the type of device you use. So make sure you look those up and that they are correct for the android device. When i was doing android this stumped me for a long time.
UUID is not something you set.
Here is a link
How can I get the UUID of my Android phone in an application?
Or this
Android - Get Bluetooth UUID for this device
If that is not it.
Did discovery fail on both ends? can you see the device on either end? Which side can you print the name?
You might want to take a look at google's bluetooth sample program. And use that to get you started.
How to use 3G Connection in Android Application instead of Wi-fi?
I want to connect a 3G connection, is there any sample code to connect to 3G instead of Wi-fi?
/**
* Enable mobile connection for a specific address
* #param context a Context (application or activity)
* #param address the address to enable
* #return true for success, else false
*/
private boolean forceMobileConnectionForAddress(Context context, String address) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == connectivityManager) {
Log.debug(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
//check if mobile connection is available and connected
State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.debug(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state);
if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) {
return true;
}
//activate mobile connection in addition to other connection already activated
int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
Log.debug(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);
//-1 means errors
// 0 means already enabled
// 1 means enabled
// other values can be returned, because this method is vendor specific
if (-1 == resultInt) {
Log.error(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems");
return false;
}
if (0 == resultInt) {
Log.debug(TAG_LOG, "No need to perform additional network settings");
return true;
}
//find the host name to route
String hostName = StringUtil.extractAddressFromUrl(address);
Log.debug(TAG_LOG, "Source address: " + address);
Log.debug(TAG_LOG, "Destination host address to route: " + hostName);
if (TextUtils.isEmpty(hostName)) hostName = address;
//create a route for the specified address
int hostAddress = lookupHost(hostName);
if (-1 == hostAddress) {
Log.error(TAG_LOG, "Wrong host address transformation, result was -1");
return false;
}
//wait some time needed to connection manager for waking up
try {
for (int counter=0; counter<30; counter++) {
State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (0 == checkState.compareTo(State.CONNECTED))
break;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
//nothing to do
}
boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
Log.debug(TAG_LOG, "requestRouteToHost result: " + resultBool);
if (!resultBool)
Log.error(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false");
return resultBool;
}
And this for calculate host address:
/**
* This method extracts from address the hostname
* #param url eg. http://some.where.com:8080/sync
* #return some.where.com
*/
public static String extractAddressFromUrl(String url) {
String urlToProcess = null;
//find protocol
int protocolEndIndex = url.indexOf("://");
if(protocolEndIndex>0) {
urlToProcess = url.substring(protocolEndIndex + 3);
} else {
urlToProcess = url;
}
// If we have port number in the address we strip everything
// after the port number
int pos = urlToProcess.indexOf(':');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have resource location in the address then we strip
// everything after the '/'
pos = urlToProcess.indexOf('/');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have ? in the address then we strip
// everything after the '?'
pos = urlToProcess.indexOf('?');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
return urlToProcess;
}
/**
* Transform host name in int value used by {#link ConnectivityManager.requestRouteToHost}
* method
*
* #param hostname
* #return -1 if the host doesn't exists, elsewhere its translation
* to an integer
*/
private static int lookupHost(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
And following permission must be added to AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
It works only with android 2.2 and above, tested on both Nexus One and on LG Optimus, other phones I don't know because some method of ConnectivityMananger are vendor-specific.
After 15-20 seconds of inactivity, mobile network is automatically disconnected.
The T-Mobile 'My Account" app does this, if you are connected to a WiFi connection it tells you that their program will not work over WiFi and then asks the user if they want to turn off the WiFi connection. If you choose "No" then the application exits, if you choose "Yes" then the app turns off your WiFi connection and then continues with starting up.
I think this is a good model to follow, it will ensure that your app is not being ran over WiFi and allows the user to decide if they want to turn off WiFi or not. An improvement on this model would be to turn wifi back on when the user navigates away from your app.
I haven't tested the following code, but it looks like it should work (modified from here)
use the following permissions in your manifest
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
and here is some actual code to turn wifi on/off
private WifiManager wifiManager;
#Override
public void onCreate(Bundle icicle)
{
....................
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
if(wifiManager.isWifiEnabled())
{
wifiManager.setWifiEnabled(false);
}
else
{
wifiManager.setWifiEnabled(true);
}
}
If you do not want to go down that route it looks like you might be able to tell the phone that you would prefer to use the mobile data network rather than the wifi network.
The Android ConnectivityManager offers a function setNetworkPreference. This function is not really documented as you can tell if you click the link. I would paly around with it though because the constants that are defined seem to hint that you can set this to either TYPE_MOBILE or TYPE_WIFI and there is a DEFAULT_NETWORK_PREFERENCE constant as well that is defined as being 0x00000001 which is the same as TYPE_WIFI. So try getting access to a ConnectivityManager by calling
Context.getSystemService(Context.CONNECTIVITY_SERVICE);
and then try using the setNetworkPreference() function.
It doesn't appear to require any permissions in the manifest but it might require the CHANGE_NETWORK_STATE permission or something along those lines.
If you do sue the setNetworkPreference function it would probably be best to also set the Network Preference back to its original values (received from getNetworkPreference)
I hope this helps.
I think that is not possible from Java. The system shuts down all mobile network based communication if connected to a wireless network. I think that you aren't allowed to start a 3G connection from you program.
Here is the code that works on API 21+ (Lollipop, Marshmallow..).
I prefer to use OkHttp with Network.getSocketFactory(), but Network.openURLConnection() also works fine.
private void doTest()
{
display("Requesting CELLULAR network connectivity...");
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
connectivityManager.requestNetwork(request, new ConnectivityManager.NetworkCallback()
{
/**
* Called when the framework connects and has declared a new network ready for use.
* This callback may be called more than once if the {#link Network} that is
* satisfying the request changes.
*
* This method will be called on non-UI thread, so beware not to use any UI updates directly.
*
* #param network The {#link Network} of the satisfying network.
*/
#Override
public void onAvailable(final Network network)
{
display("Got available network: " + network.toString());
try
{
final InetAddress address = network.getByName("navalclash.com");
display("Resolved host2ip: " + address.getHostName() + " -> " + address.getHostAddress());
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
display("Do request test page from remote http server...");
if(okHttpClient == null)
{
okHttpClient = new OkHttpClient.Builder().socketFactory(network.getSocketFactory()).build();
}
Request request = new Request.Builder()
.url("http://navalclash.com")
.build();
try (Response response = okHttpClient.newCall(request).execute())
{
display("RESULT:\n" + response.body().string());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
});
}
Inspired by code in this ticket and using some parts of it, here is service that establishes hipri mobile and keeps it running.
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicBoolean;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.os.IBinder;
import android.util.Log;
public class HipriService extends Service {
private AtomicBoolean enabledMobile = new AtomicBoolean(false);
public boolean enableMobileConnection() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == cm) {
Log.d(TAG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
/*
* Don't do anything if we are connecting. On the other hands re-new
* connection if we are connected.
*/
State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG, "TYPE_MOBILE_HIPRI network state: " + state);
if (0 == state.compareTo(State.CONNECTING))
return true;
/*
* Re-activate mobile connection in addition to other connection already
* activated
*/
int resultInt = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
//Log.d(TAG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);
//-1 means errors
// 0 means already enabled
// 1 means enabled
// other values can be returned, because this method is vendor specific
if (-1 == resultInt) {
Log.e(TAG, "Wrong result of startUsingNetworkFeature, maybe problems");
return false;
}
if (0 == resultInt) {
Log.d(TAG, "No need to perform additional network settings");
return true;
}
return requestRouteToHost(this, Uploader.ServerAddress);
}
private Thread pingerThread = null;
private void startMobileConnection() {
enabledMobile.set(true);
pingerThread = new Thread(new Runnable() {
#Override
public void run() {
while (enabledMobile.get()) {
/*
* Renew mobile connection. No routing setup is needed. This
* should be moved to 3g monitoring service one day.
*/
enableMobileConnection();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// do nothing
}
}
}
});
pingerThread.start();
}
private void stopMobileConnection() {
enabledMobile.set(false);
disableMobileConnection();
pingerThread.interrupt();
pingerThread = null;
}
public void disableMobileConnection() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
}
public final static int inetAddressToInt(InetAddress inetAddress) {
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24) | ((addrBytes[2] & 0xff) << 16) | ((addrBytes[1] & 0xff) << 8)
| (addrBytes[0] & 0xff);
return addr;
}
public final static InetAddress lookupHost(String hostname) {
try {
return InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return null;
}
}
private boolean requestRouteToHost(Context context, String hostname) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == cm) {
Log.d(TAG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
/* Wait some time needed to connection manager for waking up */
try {
for (int counter = 0; enabledMobile.get() && counter < 30; counter++) {
State checkState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.i(TAG, "Waiting for mobile data on. State " + checkState);
if (0 == checkState.compareTo(State.CONNECTED))
break;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
//nothing to do
}
if (!enabledMobile.get()) {
Log.d(TAG, "Mobile data is turned off while waiting for routing.");
return false;
}
State checkState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (0 != checkState.compareTo(State.CONNECTED)) {
Log.e(TAG, "Mobile data is still turned off after 30 sec of waiting.");
return false;
}
Log.i(TAG, "Adding routing for " + hostname);
InetAddress inetAddress = lookupHost(hostname);
if (inetAddress == null) {
Log.e(TAG, "Failed to resolve " + hostname);
return false;
}
int hostAddress = inetAddressToInt(inetAddress);
boolean resultBool = cm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
Log.d(TAG, "requestRouteToHost result: " + resultBool);
if (!resultBool)
Log.e(TAG, "Wrong requestRouteToHost result: expected true, but was false");
return resultBool;
}
#Override
public void onCreate() {
super.onCreate();
startMobileConnection();
}
#Override
public void onDestroy() {
stopMobileConnection();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Here is how I start/stop it when needed. Note that it also gets locks on cpu and wifi so that it may run when the phone sleeps (screen only). Wifi is needed because my app is kind of bridge between wifi and mobile connections. You may not need it.
public void startMobileData() {
if (!enabledMobile.get()) {
enabledMobile.set(true);
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "Wifi Wakelock");
wifiLock.acquire();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
partialLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "3G Wakelock");
partialLock.acquire();
startService(new Intent(this, HipriService.class));
}
}
public void stopMobileData() {
if (enabledMobile.get()) {
enabledMobile.set(false);
Log.i(TAG, "Disabled mobile data");
stopService(new Intent(this, HipriService.class));
if (partialLock != null) {
partialLock.release();
partialLock = null;
}
if (wifiLock != null) {
wifiLock.release();
wifiLock = null;
}
}
}
Don't forget to add service to you manifest file.
Use connection manager and set network preference as you want.
for example:
dataManager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
dataManager.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
This aplication activate 3G and Wifi connection, Giving preference to 3G!!
Very useful http://www.redrails.com.br/2012/02/wireless-analyzer-for-android/
#umka
i think, app can only reach to those hosts through HIPRI which it has requested, may be for other hosts(whose routes are not requested) is using the default network(MOBILE or WIFI).
On calling stopUsingNetworkFeature(), It will check -- is there any other app is using this network, if yes, then it will ignore your request to down this network feature.
one of the main purpose of HIPRI network is that - if wifi is on and an app wants to use mobile netwrok(3G)to reach the particular host, it can reach through HIPRI network.
There is a missing piece of code on #Northern Captain answer, the DNS lookup code.
Here is a working code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.d("NetworkDns", "Requesting CELLULAR network connectivity...");
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
connectivityManager.requestNetwork(request, new ConnectivityManager.NetworkCallback()
{
#Override
public void onAvailable(final Network network)
{
Log.d("NetworkDns", "Got available network: " + network.toString());
try
{
final InetAddress address = network.getByName("www.website.com");
Log.d("NetworkDns", "Resolved host2ip: " + address.getHostName() + " -> " + address.getHostAddress());
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
Log.d("NetworkDns", "Do request test page from remote http server...");
OkHttpClient okHttpClient = null;
if(okHttpClient == null)
{
okHttpClient = new OkHttpClient.Builder()
.socketFactory(network.getSocketFactory())
.dns(new Dns() {
#Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
if (network != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
List<InetAddress> addresses = Arrays.asList(network.getAllByName(hostname));
Log.d("NetworkDns", "List : " + addresses);
return addresses;
}
return SYSTEM.lookup(hostname);
}
}).build();
}
Request request = new Request.Builder()
.url("http://www.website.com")
.build();
try (Response response = okHttpClient.newCall(request).execute())
{
Log.d("NetworkDns", "RESULT:\n" + response.body().string());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
});
}