I have this code in Android Service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!isCurrentlyRunning()) {
currentlyRunning = true;
ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
connectivityManager.registerNetworkCallback(
builder.build(),
new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Log.d(TAG, "Start UpdateService after connectivity up");
try {
if (!UpdateService.isCurrentlyRunning()) {
if (Properties.DEBUG)
Log.d(TAG, "UpdateService is not running, try to start");
UpdateService.startService(getApplicationContext());
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
#Override
public void onLost(Network network) {
Log.d(TAG, "Stop UpdateService after connectivity lost");
try {
if (UpdateService.isCurrentlyRunning()) {
if (Properties.DEBUG)
Log.d(TAG, "UpdateService is running, sometimes need to redesigned stop service");
UpdateService.stopService(getApplicationContext());
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
);
}
return START_STICKY;
}
It would be all fine, but device is connected over DHCP and when onAvailable function is executed, its still not available DNS resolving.
How is the best way to wait (and check it during this waiting) for DNS resolver? I am thinking about for loop and sleep (and trying to connect for some web page during this loop), but during this sleeping is sleeping whole service and this solution I dont like it.
Thank you
D
Related
In order to get notified when the device connects/disconnects from internet, I took the following approach:
ConnectivityManager connectivityManager = activity.getSystemService(ConnectivityManager.class);
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(#NonNull Network network) {
super.onAvailable(network);
try {
activity.runOnUiThread(() -> {
tvNoInternet.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
MiscellaneousUtils.hideView(tvNoInternet, View.GONE);
}
});
behaviour.onConnected();
// behaviour is an interface named NetworkConnectionBehaviour (check the following snippet for its implementation)
});
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
#Override
public void onLost(#NonNull Network network) {
super.onLost(network);
try {
activity.runOnUiThread(() -> {
if (isInternetConnected(activity)) {
// check internet connection status because onLost() is called
// after onAvailable() when the device automatically switches
// internet connection from cellular to wifi
return;
}
tvNoInternet.animate().alpha(1f).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
MiscellaneousUtils.showView(tvNoInternet);
}
});
behaviour.onDisconnected();
});
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
};
try {
NetworkRequest networkRequest = getNetworkRequest();
// implementation of getNetworkRequest() is added in next snippet
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
} catch (Exception e) {
Toast.makeText(activity, "Unexpected interruption! please try again later", Toast.LENGTH_SHORT).show();
}
Interface NetowrkConnectionBehaviour:
public interface NetworkConnectionBehaviour {
void onConnected();
void onDisconnected();
}
Implementation of getNetworkRequest():
public static NetworkRequest getNetworkRequest() {
return new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
}
This approach is working in all physical devices and emulator of android studio.
However, if someone runs the app on Bluestacks 5 emulator, the callbacks of ConnectivityManager aren't called at all. And it does not produce any exception either.
Am I missing something here? Is there a different way to use ConnectivityManager for BlueStacks?
NOTE: It shows same behaviour for gameloop emulator too.
The solution is to remove transport types: TRANSPORT_WIFI and TRANSPORT_CELLULAR since the BlueStacks 5 Emulator does not recognize its connection to be one of those transport types.
The capability NET_CAPABILITY_INTERNET will ensure that the connection is working and has access to the internet as per docs:
Indicates that this network should be able to reach the internet.
The code for the NetworkRequest now should be as follows:
public static NetworkRequest getNetworkRequest() {
return new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
}
I know how to turn on/off wifi hot spot using reflection in android using below method.
private static boolean changeWifiHotspotState(Context context,boolean enable) {
try {
WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method method = manager.getClass().getDeclaredMethod("setWifiApEnabled", WifiConfiguration.class,
Boolean.TYPE);
method.setAccessible(true);
WifiConfiguration configuration = enable ? getWifiApConfiguration(manager) : null;
boolean isSuccess = (Boolean) method.invoke(manager, configuration, enable);
return isSuccess;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
But the above method is not working Android 8.0(Oreo).
When I execute above method in Android 8.0, I am getting below statement in logcat.
com.gck.dummy W/WifiManager: com.gck.dummy attempted call to setWifiApEnabled: enabled = true
Is there any other way to on/off hotspot on android 8.0
I thought the LocalOnlyHotspot route was the way to, but as #edsappfactory.com said in the comments - it only gives closed network, no internet access.
In Oreo hot-spotting/tethering moved to ConnectionManager, and its annotated #SystemApi, so (nominally) inaccessible.
As part of something else I was doing, I made an app and put it on github here. It uses reflection to get at the function and DexMaker to generate a subclass of ConnectionManager.OnStartTetheringCallback (which is also inaccessible).
Think it all works okay - bit rough around the edges, so please feel free to make better!
Relevant bits of code are in:
MyOreoWifiManager and;
CallbackMaker
I lost patience trying to get my DexMaker-generated callback to fire the MyOnStartTetheringCallback so all that code is in disarray and commented out.
Finally I got the solution.
Android 8.0, they provided public api to turn on/off hotspot. WifiManager
Below is the code to turn on hotspot
private WifiManager.LocalOnlyHotspotReservation mReservation;
#RequiresApi(api = Build.VERSION_CODES.O)
private void turnOnHotspot() {
WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
#Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
Log.d(TAG, "Wifi Hotspot is on now");
mReservation = reservation;
}
#Override
public void onStopped() {
super.onStopped();
Log.d(TAG, "onStopped: ");
}
#Override
public void onFailed(int reason) {
super.onFailed(reason);
Log.d(TAG, "onFailed: ");
}
}, new Handler());
}
private void turnOffHotspot() {
if (mReservation != null) {
mReservation.close();
}
}
onStarted(WifiManager.LocalOnlyHotspotReservation reservation) method will be called if hotspot is turned on.. Using WifiManager.LocalOnlyHotspotReservation reference you call close() method to turn off hotspot.
Note:
To turn on hotspot, the Location(GPS) should be enabled in the device. Otherwise, it will throw SecurityException
As per Jon suggestion, I got another way to enable WifiHotSpot in Android Oreo and above.
public boolean enableTetheringNew(MyTetheringCallback callback) {
File outputDir = mContext.getCodeCacheDir();
try {
proxy = ProxyBuilder.forClass(classOnStartTetheringCallback())
.dexCache(outputDir).handler(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "onTetheringStarted":
callback.onTetheringStarted();
break;
case "onTetheringFailed":
callback.onTetheringFailed();
break;
default:
ProxyBuilder.callSuper(proxy, method, args);
}
return null;
}
}).build();
} catch (IOException e) {
e.printStackTrace();
}
ConnectivityManager manager = (ConnectivityManager) mContext.getApplicationContext().getSystemService(ConnectivityManager.class);
Method method = null;
try {
method = manager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, classOnStartTetheringCallback(), Handler.class);
if (method == null) {
Log.e(TAG, "startTetheringMethod is null");
} else {
method.invoke(manager, TETHERING_WIFI, false, proxy, null);
}
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
private Class classOnStartTetheringCallback() {
try {
return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
I have an application which communicates with a Bluetooth Low Energy Glucometer.
Currently my application is working OK on Android 4.4.4, but fails on 5.1.1
Debugging I've found that the writeDescriptor() method fails when executed more than once...
With the debugger I stepped into the writeDescriptor() method and found that it fails on this line:
public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
...
synchronized(mDeviceBusy) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
(BluetoothGatt.java:1029)
I've tried to wait for the onDescriptorWrite() callback but it is never called, and I've also tried waiting (100 ms, 500ms and 2s) to do the second write, in order to see if the mDeviceBusy variable was cleared... Both attempts failed...
I googled the issue and could not find anything on it, the closest thing was this unanswered question: Android SensorTag: writeDescriptor failed
Note: I can attach my code if necessary, but it is very simple and similar to the code on this post: Android BLE notifications for Glucose
I found the problem... In my code I had defined the onDescriptorWrite() callback incorrectly. After fixing this I managed to receive callbacks when writing the descriptor succeeded.
With that solved, the solution I found is to make BTLE operations blocking by creating a class in charge of sequencing the operations.
The class I created is pretty simple, a BlockingQueue on a separate thread to enqueue incoming operations.
BTLE operations are enqueued by calling writeDescriptor(), writeCharacteristic() methods,a separate thread starts executing the operations when free, and the gattCallback informs the thread when operations have been completed, in order to proceed with the next operation.
Queue class:
public BtleAsynchronousOperationThread(SensorAbstract sensor, BluetoothGatt gatt) {
log("Creating Btle Operation thread");
this.gatt = gatt;
this.sensor = sensor;
}
public void enable() {
log("Enabling btle command thread");
queueReadySemaphore.release();
}
public void writeDescriptor(BluetoothGattDescriptor descriptor) throws BTCommunicationException {
BtleAsynchronousCommand command = new BtleAsynchronousCommand(descriptor);
try {
queue.put(command);
} catch (InterruptedException e) {
throw new BTCommunicationException("Error while writing the descriptor");
}
}
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) throws BTCommunicationException {
BtleAsynchronousCommand command = new BtleAsynchronousCommand(
BtleAsynchronousCommand.CommandType.WRITE_CHARACTERISTIC, characteristic);
try {
queue.put(command);
} catch (InterruptedException e) {
throw new BTCommunicationException("Error while writing the characteristic");
}
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) throws BTCommunicationException {
BtleAsynchronousCommand command = new BtleAsynchronousCommand(
BtleAsynchronousCommand.CommandType.READ_CHARACTERISTIC, characteristic);
try {
queue.put(command);
} catch (InterruptedException e) {
throw new BTCommunicationException("Error while reading the characteristic");
}
}
public void cancel() {
this.interrupt();
}
public void writeCompleted() {
queueReadySemaphore.release();
}
#Override
public void run() {
BtleAsynchronousCommand command;
try {
while (!(Thread.currentThread().isInterrupted())) {
queueReadySemaphore.acquire();
log("Waiting for BTLE command");
command = queue.take();
switch (command.getCommandType()) {
case WRITE_DESCRIPTOR:
log("Starting to write descriptor:" + command.getDescriptor().getUuid());
if (!gatt.writeDescriptor(command.getDescriptor())) {
throw new BTCommunicationException("Error while writing the descriptor");
}
break;
case WRITE_CHARACTERISTIC:
log("Starting to write characteristic:" + command.getCharacteristic().getUuid());
if (!gatt.writeCharacteristic(command.getCharacteristic())) {
throw new BTCommunicationException("Error while writing the characteristic");
}
break;
case READ_CHARACTERISTIC:
log("Starting to read characteristic:" + command.getCharacteristic().getUuid());
if (!gatt.readCharacteristic(command.getCharacteristic())) {
throw new BTCommunicationException("Error while writing the characteristic");
}
break;
default:
log("Unknown command received");
break;
}
}
} catch (InterruptedException e) {
log("Btle thread interrupted, closing.");
} catch (BTCommunicationException e) {
log("Error while reading:" + e.getMessage());
sensor.retry();
}
gatt = null;
queue = null;
queueReadySemaphore = null;
Thread.currentThread().interrupt();
}
}
When defining the BluetoothCallback:
mGattCallback = new BluetoothGattCallback() {
//Other methods can be defined around here, such as
//onConnectionStateChange(), etc
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
onSensorCharacteristicChangedInner(gatt, characteristic);
}
#Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status){
log("onDescriptorWrite:"+descriptor.getUuid()+ " status:"+status);
btleCommunicationThread.writeCompleted();
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
log("onCharacteristicWrite:"+characteristic.getUuid()+ " status:"+status);
btleCommunicationThread.writeCompleted();
}
I've create an application, VPN service, which will block internet packets. Everything is working fine but now I want to stop this VPN service on a button click event so that packets are not blocked anymore.
I've tried to use stopService(name); and stopSelf();
but nothing happened. What am I doing wrong?
public class VpnServiceCls extends VpnService {
private Thread b;
private ParcelFileDescriptor c;
private PendingIntent a;
Builder builder = new Builder();
private static final String TAG = "VpnService";
#Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.d(TAG, "you are in jghbgjyhb");
if (b != null) {
Log.d(TAG, "you are in destroy2");
b.interrupt();
}
}
public void StopMyVPN()
{
Log.d(TAG, "you are in jghbgjyhb 898");
stopSelf();
if (b != null) {
Log.d(TAG, "you are in destroy");
b.interrupt();
}
b.stop();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
b= new Thread(new Runnable() {
#Override
public void run() {
try{
//here is my logic which is working fine
}
}
catch(Exception e)
{
Log.d(TAG, "you are out "+e.toString());
}
}
});//start the service
b.start();
return START_STICKY;
}
}
on button click i am calling StopMyVPN() function but notting happen
you must close and set null interface of vpn .mInterface is vpn interface.
public void StopMyVPN() {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
isRunning = false;
} catch (Exception e) {
}
stopSelf();
}
you could Bind Activity to your service for calling StopMyVPN.
I also struggled with this issue. At the end I found that my problem was caused by parcelFileDescriptor which I was not closing, and that kept my service from destroy.
private fun stop(){
try {
parcelFileDescriptor.close()
} catch (ex: IOException) {
Log.e(TAG,"parcelFileDescriptor.close()", ex)
}
stopForeground(true)
stopSelf()
}
In a typical android service you can call stopSelf(); but in this case as it is VpnService, same should work only when you closed the interfaces.
So in VpnService when you build a Tun by doing establish() and get the interface. Now if you want to shutdown your VPN tunnel, then you need to first close this interface and then you need to stop all the threads that you have started, and then you are free to call stopSelf() and it should work.
I'm writing an sample app to create a Server on Android and a client to connect to PC. I put the serversocket in a thread of a service. Everything goes perfectly, until a few minutes after the screen goes off. This may be Android kill my server, I tried to put a full wake lock to my code and it wont kill anymore, however, I DO want the screen go off as usual.
Here is my code:
public class MessageListener extends Service {
private ServerSocket serverSocket;
#Override
public void onCreate() {
Log.v("Test", "Create service");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PowerManager.WakeLock wl=null;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
startServer();
if(wl!=null) wl.release();
return START_STICKY;
}
private Runnable thread = new Runnable() {
#Override
public synchronized void run() {
try {
serverSocket = new ServerSocket(Integer.parseInt(5000));
ObjectInputStream in = null;
while (true) {
Socket client = serverSocket.accept();
Log.v("TCP", "S: Receiving...");
try {
in = new ObjectInputStream(client.getInputStream());
DataInController data = new DataInController(
getApplicationContext());
data.processDataIn(in.readObject(), client);
} catch (ClassNotFoundException e) {
System.out.println("TCP S: Error in PC Server Listener");
e.printStackTrace();
} finally {
client.close();
}
}
} catch (IOException e) {
}
}
};
private Thread serverThread;
private synchronized void startServer() {
if (serverThread == null) {
serverThread = new Thread(thread);
serverThread.start();
}
}
private synchronized void stopServer() {
if(serverThread!=null){
Thread t=serverThread;
serverThread=null;
t.interrupt();
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v("TCP", "Killing Service!!!!!!!!!!!!!!!!!!!!!!!");
if (serverSocket != null) {
try {
serverSocket.close();
stopServer();
Log.v("TCP", "Closed server socket");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Two things that worked for us:
Wi-Fi lock
Set the Wi-Fi sleep policy to never. Some devices will power down the Wi-Fi radio without this setting, even when a program has a lock on the Wi-Fi radio.
I found the problem. That is the router lost the connection to Android. I've tried to ping it and it said "unreachable", after re connect to wifi, it works, but after a while, it comes again
Also try to keep WakeLock. Doing both works for me.