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.
The vibration currently only works if the screen is not off / locked. All other functions does work even if the screen is off / locked.
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] pattern = new long[]{0, 400, 200, 400};
if (Build.VERSION.SDK_INT >= 26) { // New API
vibrator.vibrate(VibrationEffect.createWaveform(pattern,0));
} else { // Old API
vibrator.vibrate(pattern, 0);
}
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 have all the permissions set, as its working when the screen is on.
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();
}
}
}
});
}
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.
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
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.
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.
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.
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.
You can try to add a receiver to control the screen logic on/off:
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// DO WHATEVER YOU NEED TO DO HERE
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = new long[]{0, 400, 200, 400};
// Only perform this pattern one time (-1 means "do not repeat")
v.vibrate(pattern, -1);
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// AND DO WHATEVER YOU NEED TO DO HERE
wasScreenOn = true;
}
}
}
public class ExampleActivity extends Activity {
@Override
protected void onCreate() {
// INITIALIZE RECEIVER
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
// YOUR CODE
}
@Override
protected void onPause() {
// WHEN THE SCREEN IS ABOUT TO TURN OFF
if (ScreenReceiver.wasScreenOn) {
// THIS IS THE CASE WHEN ONPAUSE() IS CALLED BY THE SYSTEM DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED OFF");
} else {
// THIS IS WHEN ONPAUSE() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onPause();
}
@Override
protected void onResume() {
// ONLY WHEN SCREEN TURNS ON
if (!ScreenReceiver.wasScreenOn) {
// THIS IS WHEN ONRESUME() IS CALLED DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED ON");
} else {
// THIS IS WHEN ONRESUME() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onResume();
}
}
Here is an activity lifecycle:
Reference:
https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
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