sendWakefulWork not always called with cwac-wakeful-1.1.0
Asked Answered
H

1

2

I've got a problem for a long time now and I discovered cwac-wakeful, which could solve all my problems. I thought... :'( In short, for solving the problem, I've implemented a most simple app, which schedules alarm every 60 seconds and logs everytime. Here's my code :

MainActivity :

package com.par.hasard.mysimpleapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button)findViewById(R.id.myExportButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MyLogManager.copyLogToClipboard(view.getContext());
                MyLogManager.emptyLogFile(view.getContext());
            }
        });
        try {
            MyLogManager.createLogFile(this);
            MyLogManager.write(this, "Application launched\n");
            MyAlarmPlanner.planAlarm_v2(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

MyAlarmPlanner :

package com.par.hasard.mysimpleapplication;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.widget.Toast;
import com.commonsware.cwac.wakeful.WakefulIntentService;
import java.io.IOException;

public class MyAlarmPlanner {
    public static void planAlarm_v2(Context context) throws IOException {
        MyLogManager.write(context, "Beginning of planAlarm_v2\n");
        WakefulIntentService.scheduleAlarms(new MyAppListener(), context, true);
        MyLogManager.write(context, "End of planAlarm_v2\n");
    }
}

MyAppListener :

package com.par.hasard.mysimpleapplication;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.SystemClock;

import com.commonsware.cwac.wakeful.AlarmReceiver;
import com.commonsware.cwac.wakeful.WakefulIntentService;

import java.io.IOException;

public class MyAppListener implements WakefulIntentService.AlarmListener {
    @Override
    public void scheduleAlarms(AlarmManager alarmManager, PendingIntent pendingIntent, Context context) {
        try {
            MyLogManager.write(context, "Beginning of scheduleAlarms\n");
            alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+60000, pendingIntent);
            MyLogManager.write(context, "End of scheduleAlarms\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void sendWakefulWork(Context context) {
        try {
            MyLogManager.write(context, "Beginning of sendWakefulWork\n");
            WakefulIntentService.sendWakefulWork(context, MyAppService.class);
            MyLogManager.write(context, "End of sendWakefulWork\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public long getMaxAge(Context context) {
        return (AlarmManager.INTERVAL_FIFTEEN_MINUTES * 2);
    }
}

MyAppService :

package com.par.hasard.mysimpleapplication;
import android.content.Intent;
import com.commonsware.cwac.wakeful.WakefulIntentService;
import java.io.IOException;

public class MyAppService extends WakefulIntentService {
    public MyAppService(){
        super("MyAppService");
    }

    @Override
    protected void doWakefulWork(Intent intent) {
        try {
            MyLogManager.write(this, "Beginning of doWakefulWork\n");
            MyAlarmPlanner.planAlarm_v2(this);
            MyLogManager.write(this, "End of doWakefulWork\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Manifest :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.par.hasard.mysimpleapplication">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.par.hasard.mysimpleapplication.MySimpleWakefulReceiver">
            <intent-filter android:priority="1">
                <action android:name="com.par.hasard.mysimpleapplication.REGULAR_ALARM" />
            </intent-filter>
        </receiver>

        <receiver android:name="com.commonsware.cwac.wakeful.AlarmReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>

            <meta-data
                android:name="com.commonsware.cwac.wakeful"
                android:resource="@xml/wakeful"/>
        </receiver>
        <service android:enabled="true" android:name="com.par.hasard.mysimpleapplication.MySimpleWakefulService" />
        <service android:enabled="true" android:name="com.par.hasard.mysimpleapplication.MyAppService" />
    </application>

</manifest>

wakeful.xml :

<WakefulIntentService
    listener="com.par.hasard.mysimpleapplication.MyAppListener"
    />

All this works perfectly, but sometimes, it won't log anything. I think it is due to sleep mode of my phone (Sony Xperia). But it seems to have the same behaviour on other phones. Here's an example of the log :

18/12 2h47m37s304 => Beginning of sendWakefulWork
18/12 2h47m37s311 => End of sendWakefulWork
18/12 2h47m37s316 => Beginning of doWakefulWork
18/12 2h47m37s317 => Beginning of planAlarm_v2
18/12 2h47m37s320 => Beginning of scheduleAlarms
18/12 2h47m37s322 => End of scheduleAlarms
18/12 2h47m37s323 => End of planAlarm_v2
18/12 2h47m37s324 => End of doWakefulWork
18/12 2h48m37s332 => Beginning of sendWakefulWork
18/12 2h48m37s338 => End of sendWakefulWork
18/12 2h48m37s347 => Beginning of doWakefulWork
18/12 2h48m37s348 => Beginning of planAlarm_v2
18/12 2h48m37s350 => Beginning of scheduleAlarms
18/12 2h48m37s351 => End of scheduleAlarms
18/12 2h48m37s352 => End of planAlarm_v2
18/12 2h48m37s353 => End of doWakefulWork
18/12 3h35m6s293 => Beginning of sendWakefulWork    //nothing before ??
18/12 3h35m6s298 => End of sendWakefulWork
18/12 3h35m6s319 => Beginning of doWakefulWork
18/12 3h35m6s327 => Beginning of planAlarm_v2
18/12 3h35m6s331 => Beginning of scheduleAlarms
18/12 3h35m6s338 => End of scheduleAlarms
18/12 3h35m6s340 => End of planAlarm_v2
18/12 3h35m6s345 => End of doWakefulWork
18/12 3h36m7s307 => Beginning of sendWakefulWork
18/12 3h36m7s313 => End of sendWakefulWork
18/12 3h36m7s319 => Beginning of doWakefulWork
18/12 3h36m7s320 => Beginning of planAlarm_v2
18/12 3h36m7s322 => Beginning of scheduleAlarms
18/12 3h36m7s323 => End of scheduleAlarms
18/12 3h36m7s324 => End of planAlarm_v2
18/12 3h36m7s325 => End of doWakefulWork

Can someone help me ?

Houseless answered 23/12, 2016 at 12:30 Comment(0)
A
3

In terms of the time gap, most likely, you are experiencing Doze mode on Android 6.0+ devices, or the equivalent offered by some manufacturers on older devices (e.g., SONY's STAMINA mode). Other than adding your app to the appropriate whitelist (e.g., for Doze, Settings > Apps > (gear icon) > Special access > Battery optimization), there is very little that you can do.

You are welcome to switch to setExactAndAllowWhileIdle() on API Level 23+ devices, however:

  • You will not get control every minute (I think it is limited to every 9 minutes)

  • You will not have Internet access when you do get control (which presumably is required for whatever you are trying to do for real)

  • This will not help for manufacturer-specific pre-6.0 devices (since that method does not exist)

Overall, designing your app to deal with Doze mode, and not assume that it will get control much in the background, is a more reliable approach.

Abseil answered 23/12, 2016 at 12:49 Comment(4)
Thanks for your answer ! I just set my app in whitelist (I didn't know that Battery optimization menu) and launched it. I hope this will solve the problem. However, I agree with you, I'd rather code something that could work without that parametrization. Most annoying is the 9 minutes interval... But if I schedule an alarmManage at time T-10, doWakefulWork can be fired between T-10 and T-1, and then I could schedule again at T exactly. Thanks again, you opened me new trails ! I'll keep you informed of my progress.Houseless
I just understood what does the 9 minutes interval mean... doWakefulWork will be fired every minute as long as the device isn't in doze mode, but when in doze, it can be fired at the right time, but the next will be 9 minutes later. I'll get confirmation with my log, tomorrow morning...Houseless
Ahem... Yesterday, I set my app in whitelist, just for test. But it didn't change anything. No activity for 50 minutes, then for 80, 110, 110 and 140 minutes. Must the device be restarded to apply whitelist changes ? However, I'll test with setExactAndAllowWhileIdle.Houseless
Hi and merry christmas to all ! Good news, setExactAndAllowWhileIdle is really better ! With it and my app on the whitelist, I still got time gap, but 15 minutes maximum. So, that's what you explained, the device wakes up in doze mode at the right time, but next one has to wait 15 minutes. I'll just try without the app on the whitelist, but whatever, I consider you solved my problem. Thanks a lot !!Houseless

© 2022 - 2024 — McMap. All rights reserved.