Мир Android развивается очень бурно, и мы, разработчики, имеем счастье каждый день узнавать что-то новое и тем самым становиться лучше. Технологии, которые были передовыми год назад, уже могут быть не так эффективны. К примеру, начиная с API версии 21 был введен новый класс Camera2, предоставляющий возможность управлять камерой. Старому классу Camera присвоен статус deprecated: это значит, что он все еще доступен для использования, но уже очень скоро его исключат и на новых устройствах этот класс работать не будет. Мы ориентируемся на перспективу, для этого сегодня мы изучим новые возможности, разобравшись, зачем же он же пришел на смену старому.

WARNING

Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.
 

Конвейер как концепция

Паттерн pipeline и класс Camera2
Паттерн pipeline и класс Camera2

Хоть названия классов и схожи, концепция работы серьезно изменилась. Модель работы камеры представлена в виде конвейера (pipeline). Это паттерн ООП, который предполагает использование многопоточной разработки с целью последовательного преобразования объекта, выводимого как конечный результат. В нашем случае мы подключаемся к камере, задаем параметры съемки и получателя сформированного изображения. Камера — это физический объект, поэтому для повышения производительности и экономии ресурсов устройства целесообразно все вычисления возложить на дополнительные потоки. Сейчас ты увидишь, что это не только не страшно, но и полезно! 🙂

 

Махмуд, поджигай! ©

Настало время применить на практике новый API. Интересно будет разобраться, как теперь решается одна из наших любимых задач: создать приложение, которое в фоне может делать фотографии без ведома пользователя.

Как обычно в Android, начнем мы с добавления пермишенов в манифест-файл. Сегодня нам нужен доступ к камере.

<uses-permission android:name="android.permission.CAMERA" />

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

CameraManager manager = (CameraManager)
getApplicationContext().getSystemService(Context.CAMERA_SERVICE);

Вообще, максимально широкое использование многопоточности — это тренд современной разработки под Android. Работа с сетью, физическими датчиками на устройстве, обработка полученной информации — это все очень ресурсозатратные и часто долговременные операции. Порождение дополнительных потоков позволяет не только по максимуму использовать все ресурсы аппарата (все современные мобильные устройства обладают многоядерными процессорами), но и создать у пользователя ощущение «легкости»: в основном потоке ведется только отображение элементов интерфейса.

Формирование картинки начнем с создания новых потоков и обработчиков событий. Сперва создадим новый поток, который будет висеть в фоне и ждать команды на выполнение какой-либо операции. Он будет нам полезен при задании настроек камеры и передаче картинки между объектами.

mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper

Камера — довольно сложное и не самое быстро реагирующее физическое устройство. По сравнению с вычислениями в памяти устройства перевод камеры из состояния в состояние может занимать целую вечность. Поэтому операции с камерой будут выполняться вне главного потока, а изменения состояния камеры мы будем отлавливать с помощью обработчиков событий. К примеру, инициализируем в нашем приложении объект CameraDevice.StateCallback, один из методов которого будет вызван после того, как на устройстве откроется камера.

private final CameraDevice.StateCallback mStateCallback =
new CameraDevice.StateCallback() {
  @Override
  public void onOpened(@NonNull CameraDevice cameraDevice){...}

Еще нам потребуется отслеживать тот момент, когда нам станет доступна картинка, снятая камерой. Организация передачи картинки с камеры другим объектам — довольно ресурсозатратный процесс, поэтому он тоже будет выполняться в фоне. Для этого существует объект CameraCaptureSession.CaptureCallback, его метод onCaptureCompleted будет вызван после захвата камерой изображения.

private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
  @Override
  public void onCaptureCompleted(...);

Теперь определимся, как мы будем обрабатывать полученное изображение. Сформированное с помощью класса CameraCaptureSession изображение будет доступно в виде объекта Surface. Это обертка для фотографий, сделанных с помощью класса Camera2. Специально для работы с ним создан класс ImageReader. Воспользуемся интерфейсом ImageReader.OnImageAvailableListener, метод onImageAvailable в созданном объекте будет вызван сразу, как только картинка станет доступна.

ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
  @Override
  public void onImageAvailable(ImageReader reader) {...};
 

Фотографируем

Для начала нужно определиться, с какой именно камеры мы будем снимать данные, ведь на устройстве их может быть несколько. У каждой камеры есть уникальный идентификатор, организуем небольшой перебор с использованием уже объявленного нами объекта manager и класса CameraCharacteristics.

for (String cameraId : manager.getCameraIdList()) {
  CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

Объект класса CameraCharacteristics содержит в себе физические параметры камеры под номером cameraId. Нас сейчас интересует, в какую сторону направлена камера. Камеры могут быть трех типов: фронтальная (LENTS_FACING_FRONT), задняя (LENS_FACING_BACK) и внешняя (LENS_FACING_EXTERNAL). Камеру не для селфи мы будем искать методом исключения.

Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {continue;}

Теперь нужно разобраться, какого качества фотографии можно получить с камеры. Объект класса SteamConfigurationMap будет содержать в себе информацию о поддерживаемых разрешениях изображения для выбранного режима съемки. Тут мы воспользовались данными из класса CameraCharacteristics, он позволяет управлять многими другими параметрами камеры: фокусом, чувствительностью и так далее. Сегодня мы к нему еще вернемся.

Продолжение статьи доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

Заинтересовала статья, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для статей, опубликованных более двух месяцев назад.


1 комментарий

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

Исследователи считают, что в распространении малвари FinFisher участвуют интернет-провайдеры

Специалисты ESET утверждают, что провайдеры как минимум в двух странах помогают распростра…