Android точно сигнализирует всегда 3 минуты

У меня есть приложение, которое использует AlarmManager, чтобы регулярно просыпаться по телефону в полный час и отправлять сообщение на часы Android Wear, что делает короткую вибрацию. У меня есть два пользователя с Samsung Galaxy S6 с запасом Android 5.1.1 и Sony SW 3 с 5.1.1, которые испытывают странную ошибку. В первый же полный час вибрация происходит в точное время, но все остальные вибрации задерживаются на 3 минуты. Иногда даже первая полная часовая вибрация задерживается.

Вот какой код:

final Calendar time = Calendar.getInstance();
time.set(Calendar.SECOND, 0);
time.set(Calendar.MILLISECOND, 0);
time.set(Calendar.MINUTE, 0);
time.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY) + 1);

final Intent hourlyChimeIntent = new Intent(context, HourlyChimeReceiver.class);
hourlyChimeIntent.setAction(key);
final AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, hourlyChimeIntent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);

Я получаю WakeLock в приемнике, а затем отправляю сообщение в часы Wear в потоке. Отсутствует вибрация, они опоздали на 3 минуты.

У меня нет других сообщений об этой проблеме, и все мои тестовые устройства работают хорошо. У меня нет устройства Samsung.

Любые идеи, что может вызвать задержку в 3 минуты? Samsung игнорирует setExact и делает мой сигнал неточным? Как заставить точную сигнализацию на Samsung?

EDIT:

Вот специальный код Android Wear. В методе приемника onReceive я делаю это:

final PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock lock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID);
lock.acquire(7L * 1000L);

final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context).addApi(Wearable.API).build();

new Thread(new Runnable() {
    @Override
    public void run() {
        googleApiClient.blockingConnect();

        long pattern[];
        pattern = new long[] {0L, 500L};

        final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(2000L, TimeUnit.MILLISECONDS);

        if (nodes != null) {
            for (final Node node : nodes.getNodes()) {
                // just send and forget
                Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), "/hourly_chime", Utils.Vibrator.serializeVibratePattern(pattern).getBytes()).await();
            }
        }
    }
}).start();

Ответы

Ответ 1

Проблема, похоже, происходит только на устройствах Samsung (например, Galaxy Grand, S4, S5, S6, Note 3, Note 4) с Lollipop (5.0, 5.1, 5.1.1). Кажется, что аварийные сигналы запланированы неточно, когда устройство находится на батарее с выключенным экраном. Если устройство заряжается или имеет экран во время диспетчеризации, проблема не возникает.

Вы можете проверить, не будет ли следующий сигнал тревоги недействительным:

adb shell dumpsys alarm

Я не нашел идеального решения для этой проблемы - только обходные пути, где у каждого есть некоторые недостатки:

  • Используйте setAlarmClock вместо setExact (см. этот ответ). Это работает очень хорошо (не на всех устройствах), но проблема с этим решением заключается в том, что тревога будет влиять на систему, показывая значок тревоги в строке состояния (если у кого-то еще не установлен будильник) и отображается следующий запланированный будильник по тревожным виджетам и т.д. К сожалению, пока это работает на Galaxy Grand с 5.1.1, оно не распространяется на Galaxy S4 с 5.0.1.
  • Включить экран перед планированием тревоги (я делаю это за полсекунды до планирования следующего сигнала тревоги, чтобы избежать состояния гонки). Конечно, это нехорошее решение для каждого приложения, чтобы включить экран, чтобы запланировать следующий сигнал тревоги.
  • Один отчет об ошибке, описывающий подобную проблему, соединяет его с длиной имени пакета приложения! Я не проверял, действительно ли это исправляет проблему, потому что изменение имени пакета не является вариантом для уже опубликованного приложения.
  • еще один отчет, где кто-то утверждает, что это можно исправить, используя WakefulBroadcastReceiver, но это не работает в моем случае.

BTW Эта проблема сводит меня с ума:)

Изменить: похоже, эта проблема не возникает, если в имени пакета приложений имеется ключевое слово "alarm" или "alert" (как указано в Mateieu H. в комментариях ниже).

Я также смог исправить проблему вручную, отключить Оптимизацию приложений в настройках батареи (или в приложении Smart Manager). Кажется, это невозможно сделать программно, поэтому вы можете попробовать спросить своих пользователей...

Ответ 2

Ужасный трюк от samsung. В моем первоначальном пакете есть слово тревоги, которое приложение работало безупречно, после удаления "тревоги" из пакета я столкнулся с той же ужасной проблемой, снова установив "тревогу", как сказал Матье.,