tolst0v
tolst0v
86 просмотров0 комментариев

Как сделать портретную (вертикальную) ориентацию экрана Android на Repka Pi

Меню настроек в портретном режимеЗадача

С выпуском Repka Pi 4 среди доступных дистрибутивов для работы на одноплатниках проекта появилась и ОС Android. Что это за операционная система (ОС) и зачем она может понадобится, думаем объяснять не нужно. Как пример - интерактивная информационная панель или экран терминала с пользовательским интерфейсом в виде мобильного приложения - это круто и в ряде случаев очень удобно. Так что Ура!

Но что делать, если есть необходимость повернуть экран вертикально? Особенно учитывая, что на Репку 4 портирован и доступен для установки Андроид на основе TV BOX и он залочен под работу только в горизонтальной, т.е. альбомной ориентации.

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

Немного истории появления Android для Repka Pi 4 и о его особенностях #

Ранее, разрабатывая наши первые одноплатники, ещё задолго до появления проекта Репка, мы уже ставили на них Андроид для эксперимента и это была совсем старая версия, кажется четвёртая, но этим тогда дело и ограничилось и с появлением проекта Repka Pi и его первой моделью Repka Pi 3 мы не стали в это ввязываться, не было запросов и оценивая свои силы и возможности, понимали, что пока не до этого.

С выпуском Repka Pi 4 наша команда значительно продвинулись в портировании различных операционных систем - к этому моменту мы приобрели минимально необходимые компетенции в этом вопросе, улучшили процессы разработки и производства, расширили экосистему проекта. Так что решили, решили, что настало время для Android.

В отличие от привычных нам дистрибутивов Linux (а мы портировали DietPi, Debian и Kali Linux), Android представляет собой совершенно иную экосистему с собственным стеком технологий. Нам пришлось насколько это возможно погрузиться в документацию, архитектуру AOSP и особенности сборки под специфичное железо. В качестве базы мы выбрали прошивку для TV-приставки на Allwinner H6, поскольку Repka Pi 4 также построена на этом чипе. Так было проще, чтобы не заниматься установкой или сборкой и настройкой кучи драйверов, особенно для GPU, что делать с нуля под Андроид очень не хотелось. После ряда итераций нам удалось успешно портировать Android на наше устройство.

На этом этапе мы получили рабочий Android TV, но довольно быстро столкнулись с интересным кейсом от одного из клиентов: ему необходимо было использовать устройство в портретной ориентации, и он не мог этого добиться.

Если побороть такое ограничение с ориентацией, заменить лаунчер (приложение - рабочий стол в Андроид) то вот уже обычный универсальный Андроид, только на одноплатном компьютере.

Как выяснилось, смена ориентации экрана на Android TV — задача не из тривиальных. Это объясняется просто: подавляющее большинство телевизоров не поворачивают вертикально, и сам Android TV не предполагает такого сценария использования.

Как разработчики, мы предположили, что где-то в конфигурации должен быть параметр, отвечающий за ориентацию. Действительно, в build.prop мы нашли параметр ro.default.rotation, который позволил нам повернуть экран еще на этапе запуска системы. Но радость была недолгой — с появлением лаунчера все возвращалось обратно в ландшафт.

Двинулись дальше и начали тестировать сторонние утилиты для поворота экрана. Они частично работали: позволяли крутить экран между 0 и 180 градусами, но вот добиться поворота на 90 или 270 градусов не удавалось никак — система просто игнорировала команды.

В этот момент стало понятно, что легким способом не обойтись. Придется всерьез погрузиться в исходники AOSP, поставляемые Allwinner, и разобраться, где именно в коде Android TV жестко прописано поведение, связанное с ориентацией экрана.

Итак, погружаемся в исходный код Android от AllWinner #

Обратите внимание

Если вы также, как и мы захотите погрузиться в исходный код AOSP (Android Open Source Project) для платформы Allwinner H6, то он доступен по ссылке.

Очень быстро мы заметили, что в коде встречается интересная платформа — "homlet" — и с ней связано несколько жёстко заданных логик. Мы нашли три ключевых файла, в которых встречается упоминание этой платформы и реализовано специфическое поведение, напрямую влияющее на ориентацию экрана.

WindowManagerService.java — диспетчер всего, что на экране

Файл: frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

Этот класс реализует WindowManagerService — центральный компонент, отвечающий за отображение всех окон в системе: от приложений до системных оверлеев, клавиатуры и уведомлений. Всё, что рисуется на экране, проходит через WMS.

Кроме прочего, он занимается определением и обновлением ориентации экрана. Вот ключевой фрагмент:

if ("homlet".equals(SystemProperties.get("ro.product.platform", "null"))) {
	req = "1".equals(SystemProperties.get("ro.sf.disablerotation","0"))
	    ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
	    : dc.getOrientation();
} else {
	req = dc.getOrientation();
}

Если устройство работает на "homlet", и системное свойство ro.sf.disablerotation установлено в "1", экран насильно переводится в ландшафтную ориентацию, независимо от того, что хочет приложение или пользователь. Именно это поведение мы и наблюдали — лаунчер или системные компоненты сбрасывали нашу ориентацию обратно, игнорируя настройки.

PackageParser.java — установка ориентации ещё до запуска приложения

Файл: frameworks/base/core/java/android/content/pm/PackageParser.java

Этот файл отвечает за разбор манифеста APK-файла и формирование системного описания приложения. Здесь мы нашли фрагмент, в котором ориентация экрана активности подменяется на лету:

a.info.screenOrientation = "homlet".equals(SystemProperties.get("ro.product.platform", "null"))
	? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
	: sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation,
	            SCREEN_ORIENTATION_UNSPECIFIED);

Даже если разработчик явно указал в AndroidManifest.xml, что активность должна быть портретной, на платформе homlet она всё равно будет принудительно переведена в ландшафт. Это объясняло, почему наши попытки установить нужную ориентацию не работали — решение принималось на уровне PackageParser, до запуска самой активности.

SystemServer.java — откуда всё начинается

Файл: frameworks/base/services/java/com/android/server/SystemServer.java

Этот файл — один из центральных элементов всей Android-системы. Именно он запускается после старта процесса zygote и отвечает за инициализацию всех ключевых системных служб, таких как ActivityManagerService, PackageManagerService, WindowManagerService и многих других.

Внутри SystemServer мы нашли ещё одну важную проверку на платформу "homlet":

if (SystemProperties.get("ro.product.platform").equals("homlet")) {
	wm = WindowManagerService.main(context, inputManager,
		mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
		!mFirstBoot, mOnlyCore, new TvWindowManager());
} else {
	wm = WindowManagerService.main(context, inputManager,
		mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
		!mFirstBoot, mOnlyCore, new PhoneWindowManager());
}

Эта строка определяет, какой менеджер окон будет использоваться в системе:

  • TvWindowManager — используется на "homlet" и предназначен для Android TV-устройств.

  • PhoneWindowManager — используется на обычных Android-устройствах (смартфонах, планшетах и т.п.).

Именно здесь принимается решение, каким будет поведение всей системы: будет ли она вести себя как телевизор (фиксированная ландшафтная ориентация, упрощенное управление, фокус на D-Pad-навигации и т.д.) или как "обычный" Android с поддержкой поворота экрана, сенсорного ввода, и полноценной работы в портретной ориентации.

На первый взгляд поворот экрана в Android — задача тривиальная. Но в случае с платформой "homlet" на базе Allwinner H6 это оказалось жестко зашитым поведением на всех уровнях системы. Именно поэтому стандартные подходы вроде изменения build.prop или использования сторонних приложений не работают — система попросту не создана для работы в портретном режиме. Чтобы это изменить, нам пришлось влезать в код AOSP, удалять хардкод-проверки на "homlet" и собирать собственный вариант двух очень важных файлов:

  • framework.jar содержит общую реализацию Android API — это классы, которые используют все приложения и системные компоненты: Context, Activity, View, Window, SystemProperties, и так далее.
  • services.jar — это логика запуска и работы системных сервисов, в том числе SystemServer, WindowManagerService, ActivityManagerService, и других. Именно в этом JAR-файле находится большинство изменений, связанных с поведением оконной системы и ориентацией экрана.

Чтобы эти изменения заработали, нужно было заменить оригинальные services.jar и framework.jar на нашей сборке. Заменили, но ориентация так и не меняется - почему?

Обращаем внимание

Мы не профессиональные разработчики Java и Android - у нас иной стек. Вся информация сказанная ниже показалась нам весьма интересной (потому что пришлось потратить время, чтобы к этому подойти), поэтому мы решили упомянуть ее в статье.

Как оказалось, Android не исполняет .jar-файлы напрямую — вместо этого они компилируются заранее в нативный байткод формата ART (Android Runtime), чтобы система запускалась быстрее.

Для этого Android использует следующие файлы:**

  • .vdex (Verified DEX) — содержит верифицированный DEX-код, прошедший проверку типов и ссылок;

  • .art — нативный скомпилированный байткод (аналог .so, но для классов Java);

  • .odex — в некоторых версиях Android: отдельный оптимизированный DEX-файл (в новых сборках часто интегрируется в .vdex/.art).

Без пересборки vdex и art любые изменения в системных .jar-файлах остаются "невидимыми" для Android. Чтобы изменения действительно заработали, нужно не просто пересобрать .jar, но и перегенерировать байткод, который Android использует при загрузке.

Сделали и это, заменили - работает! И через параметр в build.prop, и через приложения для смены ориентации экрана.

Способы изменить ориентацию на Android TV #

Ниже представлено 3 варианта смены ориентации экрана ОС Android на Repka Pi 4. Учитывайте, что данные варианты работают только на самой актуальной версиия нашего образа Android.

ro.default.rotation в build.prop

Обращаем внимание

После изменения данной настройки, ориентация будет применяться на этапе загрузке, когда появится надпись Repka Pi с лоадером.

  1. Для этого необходимо вставить SD-карту с уже записанным образом Android в компьютер. Настоятельно рекомендуем использовать для этого операционные системы на базе Linux, т.к. разделы Android не смогут определиться на Windows.
  2. После чего переходим в примонтированный раздел со странным названием “_“ (полный путь: /media/your-user/_).
  3. Внутри данного раздела переходим в директорию system (полный путь: /media/your-user/_/system).
  4. После чего открываем файл build.prop (для редактирование необходимы права суперпользователя) и ищем строку ro.default.rotation=. Изначально данная строка пустая, но она может принимать следующие значения: 0, 90, 180, 270 в зависимости от того, какую ориентацию вы хотите использовать по умолчанию.
  5. После изменения необходимо сохранить файл. Настройка применена!

user_rotation через терминал

Обращаем внимание

Данная настройка актуальна в случае, если у вас есть доступ к Shell на устройстве (через UART или adb)

Обращаем внимание

После изменения данной настройки, ориентация будет применяться после загрузки лаунчера.

  1. В первую очередь необходимо отключить авто-поворот экрана:

    settings put system accelerometer_rotation 0
    
  2. После чего можно изменить текущую ориентацию ()

    settings put system user_rotation X
    

    где X - может принимать значения: 0 - 0 градусов, 1 - 90 градусов, 2 - 180 градусов, 3 - 270 градусов.

Приложение Rotation

  1. На уже запущенном Android переходим в список приложений (плитка “App“).

  2. Перед нами открывается весь список приложений, которые у нас есть. Выбираем приложение Rotate.

  3. После запуска приложения, нам необходимо будет пройти небольшой туториал перед тем, как приступить к настройке.

  4. На первом экране туториала в бираем язык приложения — “Русский“ и нажимаем “Далее“ (кнопка, расположенная справа внизу).

  5. После чего пробегаемся по остатку туториала - мы настроим все в конце.

  6. После чего откроется экран с первоначальной настройкой. Включаем специальные возможности.

  7. Запускаем службу Rotation.

  8. Устанавливаем глобальное положение. В нашем случае это портретная ориентация.

  9. Как мы видим, настройка уже применилась! Включаем службу, которая будет менять настройку после запуска системы.

  10. После чего нажимаем на кнопку “Завершить“.

  11. После успешной установки первоначальных настроек откроется основное окно приложения. В этом окне в любое время мы можем изменить наши настройки.

  12. Настройка через приложение Rotation завершена!

Что в итоге? #

Портирование Android на Repka Pi 4 стало для нас не просто техническим экспериментом, а полноценным исследованием архитектуры Android — особенно в контексте платформы Allwinner H6. То, что изначально казалось простым запросом "сделать портретную ориентацию", в реальности потребовало глубокого погружения в AOSP, изучения системных служб и множества нестандартных решений.

Этот опыт показал, насколько глубоко завязана логика Android на предполагаемое поведение устройства, и как важно понимать устройство системы "под капотом", если вы хотите выйти за рамки типичных сценариев. В итоге нам удалось добиться стабильной работы Android в портретной ориентации — и теперь Repka Pi 4 готова к новым, нестандартным сценариям использования.

Важно отметить, что фактически данный функционал является экспериментальным и не полностью протестированным — точнее мы уже нашли несколько нерабочих моментов (которые в скором времени исправим). Но если кто-то не хочет проходить подобный путь (с пересборкой AOSP) у нас есть готовый образ, в котором ориентация экрана уже работает. Его можно скачать по ссылке. А по этой ссылке можно ознакомиться с инструкцией, как записать Android на SD-карту и eMMC.


Комментарии (0)

Для участия в обсуждении Вы должны быть авторизованным пользователем
Темы

Навигация

ВойтиРегистрация