Экранное время без облаков и подписок: сколько часов уходит на игры, соцсети и рабочие приложения — в том же дизайне, что и десктопная версия.
- Честное экранное время — считается по журналу переключений между приложениями, который ведёт сам Android.
- Только ваши приложения — системный интерфейс, клавиатуры, сервисы и лаунчер отсеиваются. Показать их можно переключателем в настройках.
- Те же графики — активность по часам и дням, кольцо долей, тепловая карта «день × час», тренд за две недели. Всё нарисовано на Canvas.
- Шесть тем и свои цвета — палитры Midnight, Nebula, Carbon, Matrix, Daylight, Sakura плюс собственные акцентные цвета: образцы или точная подстройка по RGB.
- Свои обои и прозрачность — любая картинка на фоне, отдельные ползунки для плотности карточек и затемнения картинки.
- Работа в фоне — приложение просит не усыплять себя и раз в три часа снимает статистику, чтобы история жила дольше системного журнала.
- Данные не покидают телефон — локальная база SQLite и экспорт в CSV.
Android уже ведёт журнал использования приложений — своя служба с опросом
активного окна только жгла бы батарею и дублировала работу системы. Seconder
читает готовые данные через UsageStatsManager, а фоновая задача нужна лишь
затем, чтобы переливать их в свою базу: система хранит подробную историю
недолго, и без снимков статистика за месяц просто не накопится.
Отсюда и запрос «разрешить работу в фоне»: без исключения из оптимизации
батареи производитель прошивки может обрывать WorkManager, и в графике
появятся дыры.
| Разрешение | Зачем | Обязательное |
|---|---|---|
| Доступ к данным об использовании | сама статистика | да |
| Игнорирование оптимизации батареи | чтобы фоновые снимки не обрывались | нет, но желательно |
QUERY_ALL_PACKAGES |
названия и иконки чужих приложений | да |
| Уведомления (Android 13+) | необязательная сводка за день | нет |
RECEIVE_BOOT_COMPLETED |
вернуть задачу в очередь после перезагрузки | нет |
Первое разрешение система не выдаёт по кнопке — приложение открывает нужный экран настроек, дальше пару касаний делает пользователь.
В собранном манифесте видны ещё WAKE_LOCK, ACCESS_NETWORK_STATE и
FOREGROUND_SERVICE — их добавляет библиотека WorkManager при слиянии
манифестов. Сам Seconder не открывает ни одного сетевого соединения: в коде нет
ни клиента, ни адресов, а INTERNET не запрашивается вовсе, так что отправить
данные наружу приложение технически не может.
Нужны JDK 17 и Android SDK (platform 34, build-tools 34). Проще всего открыть проект в Android Studio и нажать Build — она подтянет всё сама.
Из командной строки понадобится указать пути к JDK и SDK, например (PowerShell):
$env:JAVA_HOME="H:\android-toolchain\jdk"; $env:ANDROID_HOME="H:\android-toolchain\sdk"git clone https://github.com/<username>/SeconderMobile.gitcd SeconderMobile && gradle :app:assembleDebugAPK появится в app/build/outputs/apk/debug/.
Для релизной сборки положите рядом keystore.properties:
storeFile=seconder.jks
storePassword=...
keyAlias=seconder
keyPassword=...gradle :app:assembleReleaseРелиз собирается с R8: код и ресурсы ужимаются, отладочные строки вырезаются.
app/src/main/java/com/seconder/app/
MainActivity.kt точка входа
SeconderApp.kt постановка фоновой задачи
data/
UsageRepository.kt разбор событий системы на почасовые интервалы
UsageDb.kt своя SQLite: корзины «пакет + день + час»
AppCatalog.kt названия, иконки, отсев системных пакетов
Prefs.kt настройки поверх SharedPreferences
work/
SnapshotWorker.kt периодический снимок статистики
BootReceiver.kt восстановление задачи после перезагрузки
Permissions.kt проверки и интенты системных экранов
ui/
Root.kt каркас, нижняя навигация, обои
theme/Theme.kt палитры и пользовательские акценты
charts/Charts.kt столбики, кольцо, линия, тепловая карта
components/Common.kt карточки, строки, тумблеры
screens/ обзор, приложения, статистика, настройки, онбординг
События системы (ACTIVITY_RESUMED / ACTIVITY_PAUSED, гашение экрана)
разбираются в интервалы, интервалы режутся по границам часов и складываются в
корзины. Дальше любой график строится одним запросом к своей базе.
По умолчанию берётся системный гротеск, «широкий» характер задаётся разрядкой в
заголовках. Чтобы поставить свой шрифт, положите .ttf в
app/src/main/res/font/ и замените DisplayFont в ui/theme/Theme.kt:
val DisplayFont = FontFamily(Font(R.font.my_display))