How to keep the vibrator indefinitely from a service or receiver

I need to warn the user about some events with:

  • Vibration
  • Notification

Vibration must remain undefined until the user acknowledges the notification.

The problem is stopping the vibration when the device goes into sleep mode. I read the following questions:
Allow the phone to vibrate when the screen turns off
Continue to vibrate even after the screen goes to sleep in Android

There was an answer to one of the above questions, which said that vibration without patterns did the trick. So I tried calling the version of Vibrator.vibrate , which takes milliseconds instead of a large number pattern, but the vibration will stop anyway.

Other answers suggest registering the receiver in ACTION_SCREEN_OFF action. This would allow me to resume vibration if the device goes into sleep mode after starting the alarm, but it won’t work if the device has already slept.

However, I could get this to work if I could turn on the screen first and then register the receiver to deal with any event that might happen from there. Therefore, I tried to get a full lock after a trigger event was received before triggering a sound or vibration, but it does not work even though I use the FULL_WAKE_LOCK and ACQUIRE_CAUSES_WAKEUP flags. Part of the awakening works, but soon after that the device will fall asleep again. I would like to think that the FULL_WAKE_LOCK flag does not work, since it is deprecated in API 17, but Samsung 4.1..2, which is API 16, works on my device!

The recommended approach now apparently uses WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON , but this should be called from the action, and I don't have a screen if the user does not click on the notification, and if this happens, the sound and vibration should already be stopped.

So this seems like a dead end.

What else could I try?

UPDATE:
I was not lucky that the screen was always turned on with wake locks, but on the other hand, they allow me to turn on the screen, if only for a few seconds. Actually, I don’t need to turn on the screen, so I register the receiver in the Intent.ACTION_SCREEN_OFF action, and when the screen turns off, the receiver resumes vibration again. This had a good effect on Samsung, but now I switched to Huawei to continue testing, and the receiver does not work.

UPDATE:
Here's the exception stack trace on a Huawei device:

  java.util.NoSuchElementException: Death link does not exist at android.os.BinderProxy.unlinkToDeath(Native Method) at com.android.server.VibratorService.unlinkVibration(VibratorService.java:294) at com.android.server.VibratorService.removeVibrationLocked(VibratorService.java:284) at com.android.server.VibratorService.cancelVibrate(VibratorService.java:213) at android.os.IVibratorService$Stub.onTransact(IVibratorService.java:83) at android.os.Binder.execTransact(Binder.java:338) at dalvik.system.NativeStart.run(Native Method) 
+6
source share
2 answers

After some testing, I finally managed to get it to work.

Vibrator class hass two methods:

  • vibrate (long[] pattern, int repeat)
  • vibrate (long milliseconds)

the first one is the only way to vibrate endlessly using the API (passing 0 as the second argument). But on some devices (Huawei), this has been proven since I posted in this question. I'm not saying that the vibration is stopped by the OS when the device goes into sleep mode, it was about using the receiver plus tracking locks, as described in the question. I am talking about exceptions thrown by a listening implementation (the Vibrator class is abstract).

The second version of this method does not accept the template and does not allow indefinite vibration, but we can deceive this by passing a very large number of milliseconds as a parameter. This works well on some devices (Huawei) as the answer I provided in the question correctly indicated, but does not work on others (Samsung), where the implementation has a default value of max, which will be used instead if the value passed as a parameter exceeds it. This maximum value is actually less than a minute, and this means that we cannot rely on this approach.

So, I figured it all out and created a Service, where I manually vibrated so vaguely:

  while(vibrationActive){ Vibrator.vibrate(1000); Thread.sleep(1000); } 

The receiver trick to detect when the screen turns off is no longer needed. Of course, the OS continues to turn off the vibrator when this happens, but the next iteration of the loop will resume vibration again. With this approach, you can create a certain pattern if the sleep time is longer than the vibration time, but again this pattern will be interrupted at any point if the screen goes blank.

Special service for reliable on and off vibrator. Can you believe it? About 150 lines of code (without unit tests) for something that should have been possible with multiple lines.

+1
source

Are you going to let the device fall asleep or not? You can purchase wakelock, which wakes up the screen.

  PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "myTAG"); wl.acquire(LOCK_SCREEN_TIME_MINUTES * 60 * 1000); 

This does not work for you? After that, you can show a notification, but I'm not sure about the effect, it will keep vibrations. One works on GalaxyTab 2 with Android 4.2.2 and HTC Hero with Android 2.4.4.

+1
source

Source: https://habr.com/ru/post/970685/


All Articles