Как оставить вибратор включенным на неопределенный срок от службы или приемника

Мне нужно предупредить пользователя об определенных событиях с помощью:

  • Вибрация
  • Уведомление

Вибрация должна оставаться на неопределенное время, пока пользователь не подтвердит уведомление.

Проблема в том, что вибрация прекращается, когда устройство засыпает. Я прочитал следующие вопросы:
Разрешить телефону вибрировать при выключении экрана
Продолжать вибрацию даже после перехода экрана в спящий режим в Android

На один из вышеупомянутых вопросов был ответ, в котором говорилось, что вибрация без шаблонов - это главное. Итак, я попытался вызвать версию Vibrator.vibrate, которая принимает миллисекунды вместо шаблона с большим числом, но вибрация все равно прекращается.

В других ответах предлагается зарегистрировать получателя на действии ACTION_SCREEN_OFF. Это позволит мне возобновить вибрацию, если устройство перейдет в спящий режим после срабатывания будильника, но не будет работать, если устройство уже спало.

Тем не менее, я мог бы заставить эту вещь работать, если бы я мог сначала включить экран, а затем зарегистрировать приемник для обработки любого события отключения экрана, которое может произойти оттуда. Итак, я попытался получить полную блокировку пробуждения при получении события запуска, перед запуском звука или вибрации, но это не работает, несмотря на то, что я использую флаги FULL_WAKE_LOCK и ACQUIRE_CAUSES_WAKEUP. Часть пробуждения работает, но вскоре после этого устройство снова переходит в спящий режим. Я хотел бы думать, что флаг FULL_WAKE_LOCK не работает, потому что он устарел в API 17, но мое устройство - это Samsung, работающий под управлением 4.1.2, то есть API 16!

Рекомендуемый подход теперь, похоже, использует WindowManager.LayoutParams.FLAG_KEEP_SC / a>, но это должно вызываться из активности, и у меня нет никакого экрана, если пользователь не нажимает на уведомление, и если это произойдет, звук и вибрация уже должны быть остановлены.

Так что это похоже на тупик.

Что еще я мог попробовать?

ОБНОВЛЕНИЕ:
Мне не удалось постоянно держать экран включенным с помощью блокировки пробуждения, но, с другой стороны, они позволяют мне включить экран хотя бы на несколько секунд. На самом деле мне не нужно держать экран включенным, поэтому я регистрирую приемник в действии Intent.ACTION_SCREEN_OFF, и когда экран гаснет, приемник снова возобновляет вибрацию. Это хорошо работало в Samsung, но теперь я переключился на Huawei, чтобы продолжить тестирование, и приемник не работает.

ОБНОВЛЕНИЕ:
Вот трассировка стека исключения в устройстве Huawei:

    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)

person Mister Smith    schedule 11.06.2014    source источник


Ответы (2)


Собираетесь ли вы дать устройству уснуть или нет? Вы можете приобрести wakelock, который будит экран.

    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);

Это не работает для вас? После этого вы можете показать уведомление, но я не уверен в эффекте, будет ли оно удерживать вибрацию. Вышеупомянутый работает на GalaxyTab 2 с android 4.2.2 и HTC Hero с android 2.3.4.

person Nexowski    schedule 11.06.2014
comment
На самом деле это мои флаги, за исключением ON_AFTER_RELEASE, который мне не нужен. И что происходит в этом Samsung, так это то, что он действительно включается, но через 1-2 секунды он снова выключается, и я не снимаю блокировку. Теперь это не имеет значения, потому что на самом деле мне не нужен постоянно включенный экран. Я отправлю ответ, объясняющий, что я сделал. - person Mister Smith; 11.06.2014
comment
Большое спасибо за публикацию. - person Nexowski; 13.06.2014

После некоторого тестирования мне наконец удалось заставить его работать.

Класс Vibrator использует два метода:

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

первый - это единственный способ бесконечно вибрировать с помощью API (передача 0 в качестве второго аргумента). Но было доказано, что это ломается на некоторых устройствах (Huawei), как я писал в вопросе. Я не говорю о том, что ОС останавливает вибрацию, когда устройство переходит в спящий режим, это было решено с помощью приемника плюс блокировка пробуждения, как описано в вопросе. Я говорю об исключениях, вызванных ошибочной реализацией (класс Vibrator абстрактный).

второй вариант этого метода не поддерживает шаблон и не допускает неопределенной вибрации, но мы можем обмануть это, передав в качестве параметра очень большое количество миллисекунд. Это хорошо работает на некоторых устройствах (Huawei), поскольку ответ, который я цитировал в вопросе, правильно указывает, но не работает на других (Samsung ), где реализация имеет максимальное значение по умолчанию, которое будет использоваться вместо этого, если значение, переданное в качестве параметра, превышает его. Это максимальное значение на самом деле меньше минуты, а это означает, что мы не можем полагаться на такой подход.

Итак, я выложился на полную и создал Сервис, где я вручную бесконечно вибрирую вот так:

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

Уловка приемника, чтобы определить, когда экран гаснет, больше не нужна. Конечно, ОС продолжает выключать вибратор, когда это происходит, но на следующей итерации цикла вибрация снова возобновится. При таком подходе также можно создать своего рода шаблон, если время сна больше, чем время вибрации, но опять же, этот шаблон будет прерван в любой момент, если экран погаснет.

Специальная услуга для надежного включения и выключения вибратора. Ты можешь в это поверить? Около 150 строк кода (без модульных тестов) для чего-то, что должно было быть возможно с несколькими строками.

person Mister Smith    schedule 11.06.2014