Phone vibration stops working after screen is off / locked
Given this:
I have a service that checks for updates on my website and I would like it to be able to cause a vibration when a update is found even if the screen is off or locked.
And this:
How can I vibrate a phone even if its screen is off? I've tried to use a WakeLock but that doesn't seem to be the problem?
I draw a conclusion that your service works without problems when your app is in the foreground but not when it's in the background. So, it's most likely your target Android API is 26
and higher.
In this case, your update service stops working after some time due to the background limitations imposed by the OS. As the update service no longer runs, obviously, it cannot initiate any vibration.
Background Execution Limits for API >= 26
Starting from Android 8.0 there are limitations on what apps can run when they're in the background. So, your service will work for a certain time and then it will be killed by the system as stated in the documentation (please read more here):
When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
Hence, if you want your service to continue operating while the app is in the background you still have options. Some of them are the following
WorkManager
The WorkManager API makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or device restarts.
Replace your service with a WorkManager, which is run periodically to query your server.
JobScheduler
Well, you don't really need it if you use WorkManager
. It will be used by WorkManager
internally if your device API is 23
and later.
Foreground Service
Convert your service to a foreground service so that the app is considered in foreground during its execution. But in this case, it has to be active the whole time you're performing your update checks, so maybe it's not the best solution. Please read more here.
Conclusion
Keep in mind that background services should be replaced with WorkManager
or Foreground Service
starting from API 26
. Otherwise, they may not perform as intended as the system kills them after a certain amount of time.
Either you use a service or life cycle methods, you will need create a loop cycle so that your vibrator restarts when finished the pattern you defined.
I did it as follows using a handler.
Handler handlerVibrate;
Vibrator vibrator;
private void vibrate(){
// this handler will keep vibrator running even with screen off (vibrator stops when the phone has the screen off)
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
handlerVibrate = new Handler();
handlerVibrate.post(new Runnable() {
@Override
public void run() {
if(vibrator != null) {
Log.d("mainActivity", "handler");
long[] pattern = {0, 500, 500};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0)); // repeat at index 0
} else {
//deprecated in API 26
vibrator.vibrate(pattern, 0); // repeat at index 0
}
}
if(CONDITIONS TO STOP/CONTINUE){
// keep launching so that it keeps vibrating even with the screen off
handlerVibrate.postDelayed(this, 1000);
} else {
if(vibrator != null) {
vibrator.cancel();
}
}
}
});
}