Эта статья будет посвящена тому, как мы в команде PREMIER, пытались установить актуальность загруженного контента и что из этого вышло. Возможно публикация будет полезна тем, кто решил следить за переводами времени устройства в условиях отсутствующего соединения.   По договоренности с правообладателем все скачанные фильмы и сериалы могут быть доступны пользователю только в течение 14 дней. Поэтому мы должны ограничивать пользователя в доступе к просмотру загрузок по истечении этого срока. Время окончания доступности для серии рассчитывается в момент ее загрузки и проверяется с помощью времени на устройстве. Но может возникнуть ситуация, когда пользователь умышлено отключит интернет и, убрав последнюю возможность синхронизировать время с сервером, переведет время на устройстве назад, продлив тем самым для себя возможность просмотра контента. Чтобы избежать проблем с правообладателями и не ограничивать пользователей, которые по каким-то причинам перевели время вперед, уменьшив для себя время доступности контента, было принято решение пробовать отслеживать реальное оставшееся время для загрузок. Изначально была идея использовать библиотеку AndroidTrueTime, но из-за того, что в ней используется NTP(Network Time Protocol), а нам требовалось работать в оффлайне, ее пришлось откинуть. Также была мысль использовать системное время из линукс (Hardware Time), который бы не изменялся после перевода времени, но для его использования нужно чтобы у пользователя был установлен BusyBox или что-то подобное. Изменения времени решили устанавливать самостоятельно по системному уведомлению приходящему из BroadcastReceiver’a. Так как Android не присылает никакой информации о том, на сколько было изменено время на девайсе, а просто шлет уведомление о событии, то появилась потребности рассчитывать разницу между старым и новым временем устройства. Для этого воспользовались связкой системных переменных:    Разница между ними:    Это позволило получить неизменяемый timestamp, который бы отличался только при изменении времени на устройстве и при перезагрузке устройства, но об этом позже.   Таким образом, для того чтобы узнать насколько изменилось время, мы находим разницу:   savedTimestamp устанавливается  методом currentTimestamp() при первом запуске приложения и служит базовой точкой отсчета при вычислениях разницы времени. Изменение во времени сохраняем в переменную timeChangingDelta. Вывод актуального времени стал выглядеть так: Но что делать, если устройство было перезагружено, ведь в этот момент elapsedRealtime сбрасывается к 0, ломая наши вычисления? Правильно, дополнительно сохранять его в переменную elapsingTimeChangingDelta. Перезагрузку устройства можно определить по признаку того, что сохраненное значение станет больше реального(т.к. реальное сбросится) или как аналог можно воспользоваться Settings.Global.BOOT_COUNT, которая возвращает количество перезагрузок устройства.   Если девайс был перезагружен, то вычисляем изменение elapsedRealtime и суммируем с предыдущими изменениями:   Метод получения времени стал выглядеть так:   Сохраненное значение elapsedRealtime суммируется к нашей timeChangingDelta, и таким образом мы находим сдвиг времени.   Еще одним препятствием оказалось то, что событие о переводе времени приходит с задержкой или, в зависимости от ОС  девайса, вовсе не приходит при закрытом приложении. Все вычисления потребовалось выполнять уже в момент отображения контента, что могло произойти с большой задержкой после перевода времени или перезагрузки.   Стало ясно, что в текущем виде без дополнительной синхронизации устанавливать актуальное время не удастся. В итоге, подход не справился с задачей в полной мере и от него пришлось отказаться. Пользователь все равно сможет обойти защиту с помощью перезагрузки и перевода времени. Но решение может оказаться для кого-то полезным в случае изменений времени в рамках одного цикла перезагрузки девайса. Проблему пришлось решить другим способом, сохранив последнее время открытия серии в lastOpenTimestamp и при обнаружении, что время девайса меньше сохраненного, блокировать доступ к серии.  (currentTimestamp < lastOpenTimestamp) . Это не решило всех проблем, но позволило защитить контент.