TDG
TDG

Reputation: 6171

Foreground service that stops running

I'm having a problem with an app I'm writing. The app should record the network's data - lac, cell Id and receiving power into a file, whenever one of it changes. To continue recording while the app is not in focus or while the device sleeps, I used foregound service. As soon as the screen goes off, my service stops recording. The recording resumes when the screen is on.

Here's my code: For calling the service -

i = new Intent(this, WriteToFileService.class);
startService(i);

The code from the service -

private PhoneStateListener MyServiceListener;
private TelephonyManager tm;
private int lac ,cellId, signal;
private String phoneState;
private File outFile;
private final static int myID = 10;
//PowerManager.WakeLock wl;

@Override
public int onStartCommand(Intent senderIntent, int flags, int startId) {
    Intent localIntent = new Intent(this, MainActivity.class);
    localIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent pendIntent = PendingIntent.getActivity(this, 0, localIntent, 0);
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setTicker("Starting to record data").setContentTitle("NetInfo").setContentText("Recording data").setWhen(System.currentTimeMillis())
            .setAutoCancel(false).setOngoing(true).setContentIntent(pendIntent).setSmallIcon(R.drawable.hexagon);   //.setPriority(Notification.PRIORITY_HIGH)
    Notification notification = builder.build();
    notification.flags |= Notification.FLAG_NO_CLEAR;       
    startForeground(myID, notification);
    //PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    //wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
    //wl.acquire();

    outFile = new File(getApplicationContext().getFilesDir(), senderIntent.getStringExtra("name"));
    tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    MyServiceListener = new PhoneStateListener() {
        @Override
        public void onCellLocationChanged(CellLocation location){
            super.onCellLocationChanged(location);
            if ((tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_HSDPA) || (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS)) {
                GsmCellLocation MyLocation = (GsmCellLocation)tm.getCellLocation();
                lac = MyLocation.getLac();
                cellId = MyLocation.getCid();
            }
            if (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_CDMA) {
                CdmaCellLocation MyLocation = (CdmaCellLocation)tm.getCellLocation();
                lac = 0;
                cellId = MyLocation.getBaseStationId();
            }
            WriteDataToFile(lac, cellId, signal, phoneState);
        }

        @Override
        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
            super.onSignalStrengthsChanged(signalStrength);
            signal = 2 * signalStrength.getGsmSignalStrength() - 113;   
            WriteDataToFile(lac, cellId, signal, phoneState);
        }

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            switch (state) {
            case TelephonyManager.CALL_STATE_IDLE:
                phoneState = "Idle";
                break;
            case TelephonyManager.CALL_STATE_RINGING:
                phoneState = "Ringing";
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                phoneState = "On-going call";
                break;
            default:
                phoneState = "";
                break;
            }
            WriteDataToFile(lac, cellId, signal, phoneState);
        }
    };
    tm.listen(MyServiceListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS | PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_CALL_STATE);
    return Service.START_STICKY;
  }

private void WriteDataToFile(int lac, int cellId, int signal, String phoneState)
{

    try {
        FileWriter fw = new FileWriter(outFile.getAbsolutePath(), true);
        BufferedWriter bw = new BufferedWriter(fw);         
        bw.append(new SimpleDateFormat("ddMMyyyy_HHmmss").format(Calendar.getInstance().getTime()) + " ");
        bw.append(String.valueOf(lac) + " ");
        bw.append(String.valueOf(cellId) + " ");
        bw.append(String.valueOf(signal) + " ");
        bw.append(phoneState + "\n");           
        bw.close();
    } catch (IOException e) {
        Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
    }
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onDestroy() {
    Toast.makeText(getApplicationContext(), "stopped recording", Toast.LENGTH_LONG).show();
    tm.listen(MyServiceListener, PhoneStateListener.LISTEN_NONE);
    //wl.release();
    stopForeground(true);

And of-course that OnDestroy() ends with stopForeground(true); I've added at some stage a message to the file when the service is being destroyed, but it occured only once - when I ended the service, so I'm sure that it was not killed by the OS. Is there any way to implement this with foreground service, or should I try a different approach?

I've tried it on two different devices - LG P500 with android 2.2 and samsung S3 mini with android 4.1. Both of them had the same behaviour.

Thanks!

Upvotes: 3

Views: 2597

Answers (1)

Martin Marconcini
Martin Marconcini

Reputation: 27246

You might need to get a PARTIAL_WAKE_LOC from the PowerManager

Wake lock level: Ensures that the CPU is running; the screen and keyboard backlight will be allowed to go off.

If the user presses the power button, then the screen will be turned off but the CPU will be kept on until all partial wake locks have been released.

PseudoCode in your onStartCommand…

startForeground(myID, notification);
...

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOC, "My Tag");
wl.acquire();
return Service.START_STICKY;

In your service onDestroy (or when you are done with the Foreground) do a:

 wl.release();

What's probably happening is that the device's CPU is also going to sleep ;)

Upvotes: 2

Related Questions