Android ACTION_DATE_CHANGED трансляция

У меня есть Nexus S, и когда я меняю дату вручную на телефоне, ACTION_DATE_CHANGED не всегда транслируется. Если я изменю дату с 13 февраля 2014 года по 14 февраля 2014 года, я не получил ACTION_DATE_CHANGED для работы, но если я буду устанавливать ее на несколько лет в будущем, я иногда ее запускаю.

Я могу (99%) уверять вас, что я не злоупотребляю IntentFilters, BroadcastReceivers и т.д. Мне просто интересно, почему эта трансляция настолько плохо документирована. Быстрое сканирование через SO и Google показывает, что люди не уверены, происходит ли это, когда пользователь вручную меняет его, или когда дата переполняется в 12:00 или каждый день, или и то, и другое. Мой опыт показывает, что это довольно противоречиво в отношении пользовательских изменений, и я не пробовал системные изменения.

Я прохожу через код AOSP и выделяю все точки, в которых это происходит, и отчитывается.

Изменить: вопрос: кто-нибудь знает, что здесь происходит?: -)

Ответ 1

Вот код из 4.0.3_r1 в frameworks/base/services/java/android/server/AlarmManagerService.java.

Сначала мы создаем PendingIntent mDateChangeSender;

private final PendingIntent mDateChangeSender;

Затем в конструкторе AlarmManagerService.java мы настраиваем PendingIntent:

Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);

Затем позже в конструкторе:

mClockReceiver.scheduleDateChangedEvent();

Итак, что такое mClockReceiver? Просто BroadcastReceiver прослушивает Intent.ACTION_TIME_TICK и Intent.ACTION_DATE_CHANGED. В нем onReceive():

...
else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
...
    scheduleDateChangedEvent();
}

Затем, позже, мы найдем метод scheduleDateChangedEvent():

public void scheduleDateChangedEvent() {
     Calendar calendar = Calendar.getInstance();
     calendar.setTimeInMillis(System.currentTimeMillis());
     calendar.set(Calendar.HOUR, 0);
     calendar.set(Calendar.MINUTE, 0);
     calendar.set(Calendar.SECOND, 0);
     calendar.set(Calendar.MILLISECOND, 0);
     calendar.add(Calendar.DAY_OF_MONTH, 1);
     set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
}

Таким образом, он устанавливает одноразовый сигнал тревоги, начиная с текущего времени, затем устанавливая час/мин/сек/милли до нуля, затем добавляя день, поэтому, если бы сегодня было 13:30, то в следующий раз в течение 10 часов и 30 минут.

Это не означает, что здесь нет ошибок или чего-то еще, но он СМОТРЕТЬ, как ACTION_DATE_CHANGED, должен стрелять в полночь каждый день.

СЕЙЧАС - если мне нужно изменить дату на телефоне, скажем, 10 лет в будущем. Код для обработки изменения во времени запустит первое событие ACTION_DATE_CHANGED, а затем заплатит новый ACTION_DATE_CHANGED, который будет запущен, через 10 лет + часть дня. Затем, если мы изменим дату на 10 лет, до нужной даты, тревога по-прежнему планируется уволить через 10 лет, у вас не будет срабатывания ACTION_DATE_CHANGED (если вы не установите дату более 10 лет - попробуйте!).

tl; dr: Это ошибка в Android.

Ответ 2

Соответствие исследования ZachM, https://code.google.com/p/android/issues/detail?id=2880 регистрирует ошибку AOSP, где после того, как часы будут установлены назад, ACTION_DATE_CHANGED не будет срабатывать снова, пока часы догоняют то, что будет на следующий день.

(Там также есть заметка о многочасовых задержках в этой трансляции. Последствия установки часов для тестирования или изменения даты во время сна?)

Вне ошибки ACTION_DATE_CHANGED указывает, что часы достигли следующего дня, а ACTION_TIME_CHANGED (== "android.intent.action.TIME_SET") указывает, что часы были установлены (скорректированы).

ZachM "Если бы я исправлял это..." звучит как прекрасное обходное решение, используя такой сигнал тревоги в приложении (не транслируется).

ИЗМЕНИТЬ

Ошибка AOSP # 2880 содержит новый комментарий, указывающий на ошибку (в другом?) в scheduleDateChangedEvent(): где он вызывает calendar.set(Calendar.HOUR, 0);, первый параметр должен быть HOUR_OF_DAY.

Из java.util.Calendar:

ЧАС используется для 12-часового такта (0 - 11). Полдень и полночь представлены 0, а не на 12. Например, в 10: 04: 15.250 PM ЧАС составляет 10.

HOUR_OF_DAY используется для 24-часовых часов. Например, в течение 10: 04: 15,250 PM HOUR_OF_DAY составляет 22.

Итак, если scheduleDateChangedEvent() работает во время PM дня дня, он будет планировать следующий сигнал тревоги в течение полудня, а не в полночь.

Ответ 3

Я также столкнулся с той же проблемой. Я заметил, что даже при использовании ACTION_TIME_CHANGED и ACTION_DATE_CHANGED вместе, я не смог обнаружить всегда, когда изменилась дата. Я думаю, что это ошибка на платформе.

Итак, я добавил приемник для ACTION_TIME_TICK и зарегистрировал этот обратный вызов, когда дата изменилась.

Ответ 4

Фактически вы можете использовать BroadcastReceiver. Просто используйте ACTION_TIMEZONE_CHANGED тоже.

Я сделал хорошее решение для этого, здесь:

fooobar.com/info/448805/...