I have got a service which runs a thread. The thread save some data in a file (in the sdcard). When Android goes to sleep, I need that the service and the thread continue running. I tried it with a PARTIAL_WAKE_LOCK, but it doesn't work; the thread stops while Android is sleeping. Other locks like FULL_WAKE_LOCK works, but I need to use PARTIAL_WAKE_LOCK because, in the future, in that thread I will read from a serial port and I don't care the screen turn off.
I don't know if I have got some mistake in the code, or if I don't understand the PARTIAL_WAKE_LOCK. Somebody can tell me why my solution doesn't wrok?
This is part of the code of the main activity, where the service is stareted:
public void onClick(View v) {
if (SerialPortService.WAKELOCK == null) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
SerialPortService.WAKELOCK = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, SerialPortService.WL_TAG);
SerialPortService.WAKELOCK.acquire();
startService(new Intent(getApplicationContext(), SerialPortService.class));
}
}
This is the code of the service:
public class SerialPortService extends Service {
public static String WL_TAG = "serial_port_wl_tag";
public static PowerManager.WakeLock WAKELOCK = null;
private BufferedWriter out = null;
private ReadThread readThread;
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate() {
super.onCreate();
try {
File root = Environment.getExternalStorageDirectory();
if (root.canWrite()){
File dataFile = new File(root, "batterytest.txt");
FileWriter dataFileWritter = new FileWriter(dataFile);
out = new BufferedWriter(dataFileWritter);
}
} catch (IOException ioe) {
Log.d("TEST", "Could not open file " + ioe.getMessage());
}
readThread = new ReadThread();
readThread.start();
}
public void onDestroy() {
if (readThread != null) readThread.interrupt();
WAKELOCK.release();
WAKELOCK = null;
try {
out.close();
} catch (IOException ioe) {
Log.d("TEST", "Could not close file " + ioe.getMessage());
}
super.onDestroy();
}
private class ReadThread extends Thread {
public void run() {
super.run();
while (!isInterrupted()) {
try {
Thread.sleep(5000);
if (out != null) {
Calendar now = Calendar.getInstance();
out.write(now.getTime().toString());
out.newLine();
} catch (IOException ioe) {
Log.d("TEST", "Could not read file " + ioe.getMessage());}
return;
} catch (InterruptedException e) {
return;
}
}
}
}
}
Well, I will answer my question. My code is ok. I've discovered few minutes ago that the problem is the implementation of the PowerManager in the Eken M009S tablets, (a chinese tablet), the device where I've made the tests. In other devices, like in Samsung's cell phones, the PARTIAL_WAKE_LOCK works perfectly.
Related
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 want to write different NDEF messages inside a while() loop.
LAST EDIT: It seems that the microcontroller can't process data so fast, so my problem cannot be solved.
//ndef.connect();
ndef.writeNdefMessage(message);
//ndef.close();
My write() method, simplified, without all try/catch
So, at first loop it works correctly, but next ones don't. But after a number of loops it works again for one more time. This repeats.
stop = 0;
while(stop < 1000)
{
write();
stop++
}
write() is working correctly for one loop.
EDIT: I replaced while() with a timer:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
write();
}
}, 2000);
But this is too slow... I need to write at least 5 times per second.
If I set timer period less than 2000 it doesn't work, works same as while()
EDIT2: I measured how fast a message is transmitted and received. It seems it takes about 55ms to send a message, and about 7ms to receive. This is what I want, but if I set my timer to repeat after 100ms, for example, I have this error from writeNDEFmessage() :
java.io.IOException: Tag is not ndef . So if I loop 10 times writeNDEFmessage() it works fine at first loop but I receive exception at the following 9.
EDIT3:
onNewIntent() :
#Override
protected void onNewIntent(Intent intent)
{
try {
if(intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED) ||
intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)||
intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED))
{
detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(detectedTag != lastDetectedTag)
{
lastDetectedTag = detectedTag;
setIntent(intent);
}
}
} catch (Exception e)
{
Log.e("", "onIntent >>> "+e.getMessage());
}
}
This is assigned to a button:
public void testWrite()
{
final Timer timer = new Timer();
try {
ndef = Ndef.get(detectedTag);
ndef.connect();
} catch (IOException e) {
Log.e("", "Cannot connect");
e.printStackTrace();
}
timer.schedule(new TimerTask() {
#Override
public void run() {
transmit.writeTag(message), ndef)
}, 0, 200);
}
and writeTag():
public boolean writeTag(String str, Ndef ndef) {
try {
message = getNdefMessage(str);
}
catch (Exception e)
{
toast("Message error");
}
int size = message.toByteArray().length;
try {
if (ndef != null) {
if(!ndef.isConnected())
{
ndef.connect();
Log.e("", ""+ndef.toString());
}
if (!ndef.isWritable()) {
return false;
}
if (ndef.getMaxSize() < size) {
toast("Tag capacity is " + ndef.getMaxSize() + " bytes, message is " + size + " bytes.");
return false;
}
try{
ndef.writeNdefMessage(message);
}
catch(IOException e){
toast("error send");
Log.e("IOException", e + "-+-");
return false;
}
return true;
}
}
catch (Exception e) {
toast("Failed to write tag");
}
return false;
}
transmit is an object from Transmit class, in which writeTag() is defined
onCreate():
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
transmit = new Transmit(this);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
textView.setText("");
detectedTag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
lastDetectedTag = detectedTag;
pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(this, getClass()).
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
readTagFilters = new IntentFilter[]{tagDetected,filter2};
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
if (mNfcAdapter == null) {
// Stop here, we definitely need NFC
finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
}
buttonListener(testButton);
}
From the Ndef docs for the close() method: "Disable I/O operations to the tag from this TagTechnology object, and release resources."
So I think when you call close() the internal TagTechnology is released. If you call connect on the same ndef it's a "stale" object. Try creating a new Ndef object each time by passing it the Tag object.
Edit: Or else just don't call close() until you're actually finished. You will still need to call connect() the first time. Additionally I'd always call isConnected() first to ensure the tag is present and connected.
Is there any way to directly communicate with a WallpaperService from an Activity? It doesn't look like I can use the normal service communication classes because the onBind method is declared final in the WallpaperService class I'm extending. Worth noting that I'm referring to my WallpaperService not any.
Any workarounds if this isn't possible?
My solution was to use local sockets. I created an instance of a LocalServerSocket in the constructor of my wallpaper's Engine. Here's a quick implementation. Server runs on a separate thread and is directly tied to the lifecycle of MyEngine. The thread will stop when continueSocket is set to false. This happens onDestroy. Problem is that LocalServerSocket.accept() blocks until there's something to do. The workaround is to send a message to our own server so it will run through the loop again and check continueSocket (which is now false), closing the server. Check the closeSocketServer method. I have it running in onDestroy in the example but you might want to use it elsewhere like onSurfaceDestroyed and add your own sanity checks.
public class MyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new MyEngine();
}
private class MyEngine extends Engine {
private boolean continueSocket = true;
MyEngine() {
new Thread() {
#Override
public void run() {
try {
LocalServerSocket server = new LocalServerSocket("MyAddress");
Log.d("SERVER READY", "Server is ready.");
while(continueSocket) {
LocalSocket receiver = server.accept();
if(receiver != null) {
InputStream input = receiver.getInputStream();
byte[] data = IOUtils.toByteArray(input);
Log.d("GOT DATA", new String(data));
}
}
server.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
}
}.start();
}
#Override
public void onDestroy() {
closeSocketServer();
super.onDestroy();
}
private void closeSocketServer() {
continueSocket = false;
try {
LocalSocket socket = new LocalSocket();
socket.connect(new LocalSocketAddress("MyAddress"));
socket.getOutputStream().write(new byte[0]);
socket.getOutputStream().close();
socket.close();
} catch (IOException ex) {
//
}
}
}
}
And in my Activity it can be as simple as this...
try {
LocalSocket sender = new LocalSocket();
sender.connect(new LocalSocketAddress("MyAddress"));
String data = "Hello world!";
Log.d("SENT DATA", data);
sender.getOutputStream().write(data.getBytes());
sender.getOutputStream().close();
sender.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
Logcat ends up looking like this:
D/SERVER READY﹕ Server is ready. (when the wallpaper starts up)
D/SENT DATA﹕ Hello world! (when the activity sends data)
D/GOT DATA﹕ Hello world! (when the wallpaper gets the data)
In your WallpaperService onCreateEngine:
IntentFilter intentFilter = new IntentFilter("your.package.your.action");
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver(mRenderer);
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(mReceiver, intentFilter);
In mRenderer's class:
public void receiveCommand(int i) {
Log.d("got", String.valueOf(i));
}
Receiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
private final MyRenderer _mRenderer;
public MyBroadcastReceiver(MyRenderer mRenderer) {
_mRenderer = mRenderer;
}
#Override
public void onReceive(Context context, Intent intent) {
_mRenderer.receiveCommand(intent.getExtra("msg", -1));
}
}
Now call from activity:
Intent in = new Intent();
in.setAction("your.package.your.action");
in.setExtra("msg", 42);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(in);
I am starting a service from activity.The problem here is the service gets started started but the activity is not getting displayed.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(this, ServerActivity1.class));
}
In the service I am opening a socket via a simple function like this by using a timer.The service gets started as I am able to see in logs but the view(R.layout.main) never gets displayed and after some time the force close pop is displayed.
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "sasa", Toast.LENGTH_SHORT).show();
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
read();
}
}, 0,50000);
Log.i("NoServer","Started1");
read();
}
#Override
public void onDestroy() {
}
#Override
public void onStart(Intent intent, int startid) {
Log.i("Home","Listening on IP: " + SERVERIP+"\n");
}
public void read()
{
SERVERIP = getLocalIpAddress();
Log.i("Home","Listening on IP: " + SERVERIP+"\n");
if (SERVERIP != null) {
Log.i("Home","Listening on IP: " + SERVERIP+"\n");
}
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
Socket client;
Log.i("Home","Listening on IP: " + SERVERIP+"\n");
try {
client = serverSocket.accept();
Log.i("Home","Listening on IP: " + SERVERIP+"\n");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while ((line = in.readLine()) != null) {
serverSocket.close();
read();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Its because your UI thread (main) is being shared by service unless you define your service in a separate process in manifest. If you start your service in activity's onResume method, till then your service would be visible but still may cause ANR depending on the time (max 5 secs) it takes to complete requests in service.
Its better to put all the socket stuff (or any expensive calls) of your service in a separate thread. In that case, your app will not hang or crash due to ANR.
You should use ThreadHandler and Handler to execute Messages and/or Runnables in a separate thread inside Service.
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.