Как только Google анонсировал возможность создания кастомных циферблатов в новом Android 5.0 для Android Wear, мы заказали в ближайшем интернет-магазине новый ASUS ZenWatch для того, чтобы испытать эту новейшую фичу. Было решено не портировать одни из существующих трехмерных живых обоев, а создать новую сцену именно для часов. В результате был придуман концепт и создано приложение с набором из пяти цифровых циферблатов, реализованное в 3D с помощью OpengGL ES 2.0.
Первоначальный концепт
Идея циферблата возникла под впечатлением от этой работы (автор beeple):
Видео выглядит классно и не кажется сложным на первый взгляд. Однако мы обнаружили некоторые технические ограничения, которые препятствовали создать такую же сцену, как и в видео. Не так-то просто сделать цифры из линий (wireframe), которые бы корректно перекрывали друг друга. Вкратце, это бы потребовало большого количества команд отрисовки (draw calls) и весьма ограниченное железо часов могло бы не справиться с таким количеством draw call-ов. Так что мы перешли к другой идее — добавить глубины к цифрам из пикслельных шрифтов со старых компьютеров.
Конфигурация OpenGL ES без компоненты глубины
Класс Gles2WatchFaceService из Android Wear API не предоставляет доступ ко всем фичам, необходимым для создания полноценной трехмерной сцены циферблата. Основная проблема, с которой мы сразу же столкнулись, это невозможность выбора необходимой конфигурации OpenGL ES. По сути, данный класс вообще не предоставляет доступа к EGL. Его достаточно для запуска циферблата ‘Tilt’ из примера API, но он не имеет никакой гибкости для настройки EGL. Этот пример не требует наличия буфера глубины, так как не содержит никакой пересекающейся геометрии. В Gles2WatchFaceService попросту выбирается конфигурация без EGL_DEPTH_SIZE и API не дает возможности ее изменить.
Ввиду обнаружения столь существенного ограничения было принято решение декомпилировать исходный код и создать свою реализацию Gles2WatchFaceService с блекджеком и правильной конфигурацией EGL.
Также весьма известный разработчик живых обоев и циферблатов Kittehface Software сообщил в своем блоге о том, что Moto360 не работает с вполне корректной 16-битной конфигурацией EGL. Поэтому на всех устройствах наше приложение всегда использует 32-битный цвет. Огромное спасибо Kittehface Software за то, что предупредили нас и других разработчиков об этом — поиск причины падения на Moto360 мог бы занять дни, да и самих часов в распоряжении на тот момент у нас не было.
glViewport()
Оффициальная докуметация имеет очень скудные и расплывчатые упоминания о том, как работать с устройствами с разными экранами, используя метод onApplyWindowInsets(). Там сказано, что этот метод нужно использовать для того, чтобы адаптироваться к экранам с обрезанным нижним краем. Это необходимо для того, чтобы скорректировать вид на таких устройствах, как Moto 360.
Не имея на руках Moto360, было непонятно, как именно использовать этот метод так, чтобы наши первые попытки запустить приложение на этих часах привели к тому, что вид был смещен — сдвинут вверх на размер обрезанной части экрана. Довольно странным было то, что этой проблемы не было в примере циферблата Tilt — он был корректно отцентирирован. Чтобы разобраться в этом, пришлось снова заглянуть в декомпилированный код сервиса Gles2WatchFaceService. Причина была в применении glViewport(). Для реализации эффекта свечения (bloom) мы использовали рендер в текстуру и вызывали glViewport() для переключения рендеринга в текстуру или на экран. Для того, чтобы избежать смещения картинки, нужно принимать во внимание значение нижнего отступа для обрезанных экранов, когда задаете glViewport().
Прозрачность в обычном и ambient режиме
По неизвестным причинам, невозможно рисовать непрозрачные карточки оповещений (peek cards) в режиме экономии экрана (ambient mode). В обычном режиме вы можете задавать вид карточек, но в режиме экономии они всегда полностью прозрачные. Вам прийдется самому рисовать черный прямоугольник в том месте, где над ним будет выводиться карточка, используя метод getPeekCardPosition(). В нашем случае было достаточно использовать карточки малого размера и они не перекрывались с цифрами, но в общем желательно уменьшать размер области отрисовки для того согласно размеров карточки.
Отправка сообщений с настройками для обновления циферблата на часах
В нашей реализации приложения настройки циферблатов мы используем HoloColorPicker для выбора цветов цифр и фона. Изменение цвета на часах происходит в реальном времени, как только пользователь изменяет цвет (в событии ColorPicker.OnColorChangedListener контрола выбора цвета). Однако это вызывает некоторые проблемы. Пользователь может изменять цвет очень быстро (событие возникает при движении пальцем по «кольцу» выбора цвета), что приводит к переполнению очереди сообщений об изменении цвета. Wearable Data Layer API не предназначен для столь интенсивной отправки сообщений. Ничего не падает, но некоторая часть последних сообщений может попросту не дойти до часов. Для избежания этого мы ограничиваем отправку обновлений цвета интервалом 500 мс. Такая несущественная задержка не вызывает никаких неудобств и позволяет не перегружать возможности Wearable Data Layer API.
Общие впечатления о железе Android Wear
Большинство часов для Android Wear построены на основе чипа Snapdragon 400 — ASUS, Sony, Samsung и LG используют именно его во всех своих часах. Этот чип имеет впечатляющий четырехъядерный процессор с частотой до 1,2Гц, чего более чем достаточно для часов. Его видеокарта Adreno 305 может показаться немного устаревшей на первый взгляд. Но часы имеют довольно маленькое разрешение 320х320 пикселей, так что ее мощности достаточно для отрисовки достаточно сложных 3D-сцен при 60 кадрах в секунду. Даже Moto 360 с его устаревшим чипом OMAP3630 имеет достаточно производительную видеокарту PowerVR SGX530, которая выдает достаточную производительность при имеющемся разрешении экрана.
Для примера, дополнительный эффект блума в разрешении 128х128 с четырехпроходным размытем не вызвал никакого падения производительности — Adreno 305 запросто справился с этой дополнительной задачей. Однако для часов оказалось достаточным использовать и более низкое разрешение блума 64х64 с двумя циклами размытия.
Есть множество видео, где люди показывают такие игры, как Temple Run 2 или GTA, запущенные на Android-часах, которые работают без лага — это в очередной раз демонстрирует производительность видеокарт в этих устройствах.
Публикация
При публикации Android Wear приложения на Google Play необходимо отметить галочку «Distribute your app on Android Wear». Это инициирует процесс модерации приложения на соответствие требованиям Wear App Quality. В нашем случае этот процесс занял всего несколько часов.
Автор: diamond3