The app shows expected behavior if the app is running in the foreground, background or killed. However, once it is rebooted the PeriodicTask
stops running
Following are the relevant bits of code:
In AndroidManifest
:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<service android:name=".tracking.MyTaskService"
android:exported="true"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
PeriodicTask config:
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(30L)
.setFlex(10L)
.setExtras(bundle)
.setPersisted(true)
.build();
mGcmNetworkManager.schedule(task);
In the Logcat, I get the following:
E/NetworkScheduler.TED: Couldn't start service: Intent
{ act=com.google.android.gms.gcm.ACTION_TASK_READY
cmp=xxx.xxxxxx.xxx/.tracking.MyTaskService (has extras)
}
Appending all relevant details:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.example.gcmnetworkmanagerquickstart">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<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>
<!-- [START manifest_service] -->
<service
android:name=".MyTaskService"
android:exported="true"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
<!-- [END manifest_service] -->
</application>
</manifest>
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int RC_PLAY_SERVICES = 123;
public static final String TASK_TAG_PERIODIC = "periodic_task";
private GcmNetworkManager mGcmNetworkManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGcmNetworkManager = GcmNetworkManager.getInstance(this);
if(checkPlayServicesAvailable()){
startPeriodicTask();
}
}
public void startPeriodicTask() {
Log.d(TAG, "startPeriodicTask");
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(5)
.setPersisted(true)
.build();
mGcmNetworkManager.schedule(task);
}
private boolean checkPlayServicesAvailable() {
GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
int resultCode = availability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (availability.isUserResolvableError(resultCode)) {
// Show dialog to resolve the error.
availability.getErrorDialog(this, resultCode, RC_PLAY_SERVICES).show();
} else {
// Unresolvable error
Toast.makeText(this, "Google Play Services error", Toast.LENGTH_SHORT).show();
}
Log.d(TAG, "Play Services NOT Available");
return false;
} else {
Log.d(TAG, "Play Services Available");
return true;
}
}
}
MyTaskService
public class MyTaskService extends GcmTaskService {
private static final String TAG = "MyTaskService";
@Override
public void onInitializeTasks() {
}
@Override
public int onRunTask(TaskParams taskParams) {
Log.d(TAG, "onRunTask: " + taskParams.getTag());
return doPeriodicTask();
}
private int doPeriodicTask() {
Log.d(TAG, "doPeriodicTask Called");
return GcmNetworkManager.RESULT_SUCCESS;
}
}
build.gradle (App Module)
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.google.example.gcmnetworkmanagerquickstart"
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
allprojects {
repositories {
jcenter()
google()
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:26.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.7.0'
compile 'com.google.android.gms:play-services-gcm:11.0.2'
}
Edit1: After some days of analysis, I have figured out the following:
AlarmManager
, FirebaseJobScheduler
and RECEIVE_BOOT_COMPLETED broadcast receiver
. AccessibilityService
permission is reset. Which means everytime you open the app after this, manually permission is to be given. (2) If the app is killed, reboots after that won't hit the RECEIVE_BOOT_COMPLETED broadcast receiver
test
in the package structure, everything works!!PeriodicTask config:
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(30L)
.setFlex(10L)
.setExtras(bundle) **/* you put this line here */**
.setPersisted(true)
.build();
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
/* you don't have ".setExtras(bundle)" line here */
/* try adding this line from above, as logcat is showing this */
.setPeriod(5)
.setPersisted(true)
.build();
Update: Found a Won't Fix (Infeasible) bug that may be related to the topic. It seems like the Accessibility Service behavior is not consistent across devices. Some will disable the service, some will resume, etc. It fits with user complaints found online, and with your observations well.
The best advise I can give is to make the service as minimal as possible on a different process (so it won't be killed with the app is killed), and also on boot check if it is enabled, and if not - use the notification system to allow quick access to Android Accessibility settings screen, for easy enablement.
I'm not familiar with the specific problem, but I believe this workaround will work for you. I use this code for AlarmManager in production.
In AndroidManifest.xml:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".BootListener">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
And create a class
public class BootListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// If your bootstrap is in Application class, then it will be called anyway - nothing to do here.
// else - call your bootsrap here
}
}
I believe that
(2) If the app is killed, reboots after that won't hit the RECEIVE_BOOT_COMPLETED broadcast receiver
Is wrong, when rebooting, Android has no knowledge that your app was killed. It was never a problem for my app (+1.2M users).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With