Android provider mediastore action image capture

У нас есть фотик и котик — работаем с камерой

Практически все современные телефоны и планшеты снабжаются камерами, что позволяет фотографировать любимых котиков.

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

Если камера в вашем приложении выполняет вспомогательную функцию, а приложение может работать и без неё, то установите значение false в предыдущем коде и проверяйте наличие камеры программно. Если камеры нет, то отключайте возможность съёмок для пользователя.

Программное включение приложения Камера

Раньше на старых телефонах можно было программно запустить из своей программы системное приложение «Камера» (в этом случае вам не понадобятся дополнительные разрешения) через намерение.

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

А вообще у пользователя могут стоять разные приложения, способные фотографировать. Тогда у вас будет появляться диалоговое окно с выбором нужного приложения. Они все имеют в своём составе такую запись в манифесте (для общего развития):

У Гугла есть своя программа Google Камера. Запустим её, зная имя пакета.

При вызове метода getIntent() вместо new Intent() приложение запускалось сразу, иначе — выводилось диалоговое окно выбора программы из списка. Также нужно быть уверенным, что программа установлена, в примере нет кода проверки.

Делаем фотографии и сохраняем результат. Простой пример

Просто включить камеру не слишком интересно. Рассмотрим практичный пример, когда мы программно запустим приложение «Камера», а полученную фотографию сохраним в папке. Сначала сделаем простой вариант, а потом напишем более сложное приложение.

Используйте статическую константу MediaStore.ACTION_IMAGE_CAPTURE для создания намерения, которое потом нужно передать методу startActivityForResult(). Разместите на форме кнопку и ImageView, в который будем помещать полученный снимок. Этот код запускает стандартное приложение камеры. Полученное с камеры изображение можно обработать в методе onActivityResult():

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

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

При тестировании примера на своём телефоне я обнаружил небольшую проблему — когда снимок передавался обратно на моё приложение, то оно находилось в альбомном режиме, а потом возвращалось в портретный режим. При этом полученный снимок терялся. Поэтому перед нажатием кнопки я поворачивал телефон в альбомный режим, чтобы пример работал корректно. Возможно следует предусмотреть подобное поведение, например, запретить приложению реагировать на поворот и таким образом избежать перезапуска Activity. У некоторых телефонов такой проблемы нет.

По умолчанию фотография возвращается в виде объекта Bitmap, содержащего миниатюру. Этот объект находится в параметре data, передаваемом в метод onActivityResult(). Чтобы получить миниатюру в виде объекта Bitmap, нужно вызвать метод getParcelableExtra() из намерения, передав ему строковое значение data. В примере использовался упрощённый вариант.

Читайте также:  Delivery from the pain mod андроид

Миниатюра и полноразмерное изображение

Если вы укажете исходящий путь URI с помощью параметра MediaStore.EXTRA_OUTPUT в запущенном намерении, полноразмерное изображение, снятое камерой, сохранится в заданном месте. В таком случае в метод onActivityResult() не будет передана миниатюра, а итоговое намерение продемонстрирует значение null.

В следующем примере показано, как при создании снимка получать миниатюру или полноценное изображение, используя намерение. Изображение будет сохранено во внешнем хранилище под именем test.jpg.

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

Добавим разрешение на запись файла в хранилище.

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

Запуск камеры в нужном режиме

Мы можем выбрать намерение, позволяющее включить камеру в нужном режиме: фотосъёмка или видео.

Снимаем и кадрируем

Рассмотрим ещё один пример с режимом кадрирования. Основная часть кода остаётся прежней. Рекомендую проверять работу с камерой на реальных устройствах, так как многие производители заменяют стандартные методы съёмки своими прошивками и драйверами. В частности, намерение с кадрированием является проблемной, и в интернете многие жалуются на отсутствие поддержки этого способа. Пример для старых устройств до Android 6.0.

Создадим простенький макет из кнопки для запуска камеры и ImageView для вывода кадрированного изображения.

Для большей красоты сделаем задний фон у ImageView с закруглёнными углами и обводкой. Для этого в атрибуте android:background мы прописали специальный стиль. Создайте папку res/drawable, а в ней файл background.xml следующего содержания:

Этот шаг не является обязательным и его можно пропустить.

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

После того, как пользователь сделал нужный кадр, программа Камера возвращает результат обратно в наше приложение. Результат обрабатывается в методе onActivityResult():

Получив полноразмерное изображение, мы пытаемся откадрировать его. Для этого создадим метод performCrop(), который запускает специальное намерение, предназначенное для этих целей. В успешном случае результат снова возвращается в наше приложение, но уже с другим кодом PIC_CROP. Теперь мы имеем нужное изображение, которое можно вывести на экран.

При кадрировании мы указываем желаемые размеры (код метода ниже). Если указать слишком больше размеры (больше 400), то результат не возвращается. Попробуйте добавить ещё два параметра:

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

Источник

Полный список

— получаем фото и видео, используя системное приложение

Открываем серию уроков по работе с камерой. И начнем с самого простого. Если вам в приложении необходимо сделать снимок или снять видео, вовсе необязательно для этого создавать отдельное Activity и работать в нем с объектом Camera. Можно использовать уже существующее в системе приложение.

Для этого ваше приложение должно отправить Intent с action = MediaStore.ACTION_IMAGE_CAPTURE (фото) или MediaStore.ACTION_VIDEO_CAPTURE (видео) и ждать ответ. Т.е. надо использовать методы startActivityForResult и onActivityResult.

Также, в этот Intent вы можете поместить желаемый путь к файлу и туда будет сохранен результат работы камеры. Для этого в Intent необходимо добавить Uri с ключом MediaStore.EXTRA_OUTPUT.

Напишем простое приложение, демонстрирующее эти возможности.

Project name: P1311_CameraIntent
Build Target: Android 2.3.3
Application name: CameraIntent
Package name: ru.startandroid.develop.p1311cameraintent
Create Activity: MainActivity

Добавим строки в strings.xml:

На экране только кнопки для получения фото и видео, и ImageView, в котором будем отображать полученное фото.

Читайте также:  Отозвать сообщение outlook android

В onCreate мы вызываем свой метод createDirectory, который в папке Pictures создаст папку для наших файлов и поместит соответствующий объект File в переменную directory.

В onClickPhoto и onClickVideo создаем Intent с соответствующим action, добавляем в этот Intent желаемый путь к файлу и отправляем методом startActivityForResult.

В onActivityResult мы ловим результат от приложения камеры. Код громоздкий, т.к. там куча проверок на null. Для фото и для видео я пытаюсь вытащить путь к получившемуся файлу, используя Intent.getData. Кроме этого, для фото я еще пытаюсь вытащить Bitmap с получившимся изображением.

Метод generateFileUri генерирует путь к файлу. Для этого он берет путь из directory, определяет префикс и расширение в зависимости от типа (фото или видео) и использует системное время, как основную часть имени файла. Далее все это конвертируется в Uri и возвращается как результат метода.

Осталось дописать в манифест пару настроек.

— право на запись на SD карту

— ваше приложение в маркете будет видно только устройствам с камерой

Сохраняем все и запускаем приложение.

Жмем Photo – открывается системное приложение камеры. Делаем фото и подтверждаем, что нас устраивает полученный снимок. Нас возвращают в наше приложение.

fileName = /storage/emulated/0/Pictures/MyFolder/photo_1376465721626.jpg
Intent is null

В ответе мы не получили ничего, Intent = null. Но мы указывали путь, куда надо сохранить фото. Идем в папку Pictures/MyFolder и ищем свой файл, он должен там быть.

Попробуем получить видео. Жмем кнопку Video, снимаем ролик и подтверждаем, что он нас устраивает.

fileName = /storage/emulated/0/Pictures/MyFolder/video_1376466182087.mp4
Video uri: file:///storage/emulated/0/Pictures/MyFolder/video_1376466182087.mp4

В случае с видео Intent не null. И его метод getData вернул нам инфу о пути к файлу. Идем в папку и ищем свой файл.

Теперь давайте не будем явно указывать путь для сохранения, и посмотрим, как поведет себя приложение камеры.

Закомментируем соответствующие строки кода:

Сохраняем, запускаем приложение.

Жмем Photo, делаем снимок и подтверждаем его, открывается наше приложение и ImageView показывает только что сделанное фото.

Photo uri: null
bitmap 120 x 160

getData вернул null, хотя хелп обещал, что там будет путь к файлу. Зато в Intent мы получили Bitmap. Но, как видим, размер его оставляет желать лучшего. Получается, что вообще нет доступа к полноценному сделанному фото. Оно у меня даже не создалось в папке, куда камера по дефолту фоты сохраняет.

Скорее всего, это зависит от версии Android и системного приложения камеры. И у вас вполне может быть другое поведение системы.

Попробуем с видео. Жмем Video, снимаем и подтверждаем ролик.

Video uri: content://media/external/video/media/8018

С видео все ок. Камера сохранила видео в папку по умолчанию, и в Intent вернула нам Uri.

Кроме желаемого пути для видео вы можете указать еще некоторые параметры в intent:

MediaStore.EXTRA_DURATION_LIMIT – лимит продолжительности видео в секундах

MediaStore.EXTRA_SIZE_LIMIT – лимит размера получившегося видео в байтах

На следующем уроке:

— используем объект Camera для получения изображения с камеры
— подгоняем изображение под размеры экрана
— учитываем поворот устройства

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

Читайте также:  Страшные бродилки для андроид

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android’s New Image Capture from a Camera using File Provider

Prudhvi Raj Kumar

Jan 31, 2018 · 3 min read

From the latest version of Android, Nougat — Capturing an image through a default camera is exposing a FileUriExposedException. Google has launched a more generic way in order to capture the image through a File Provider which reduces the risk of exposing a content:// uri to another application. I have pushed the source code on github-Source and published one video here.

So, Let’s start how can we achieve capturing an image from the camera and getting the file path and load an image in an ImageView.

First, you need to add the permission in the manifest file as

In the permission, the android:required=”true” is to tell the Google’s play to filter all the Android devices which have camera function. If we use android:required=”false”, we need to check for the camera via programmatically.

So, next query for all the activities in the device which will handle the CAPTURE_REQUEST intent.

Now, get the result from onActivityResult() and load the image as following:

But if you want the imagePath to send the image to a server as a MultiPartRequest, you need to save the file in a directory as temporary file. From that file obtain the path and will send to the server.

Now, add the permission in the manifest to save the image file in to the external storage as

Now let’s create a function to generate a random file name with .jpg extension in the external files directory.

With this method available to create a file for the photo, you can now create and invoke the Intent like this:

If you observe the above code carefully, you may notice where the “com.example.android.provider” came? So, from the latest applications target API level 24, to access the files, they need to add a FileProvider Content Provider to their manifest file. Just follow the steps as:

The $ automatically gets the package name of your android application. On the above Statement also, we can use context.getPackageName() instead of hard-coded text of package name.

The “ @xml/file_paths” we need to add it separately in the resources directory. Just create a android resource directory of type xml and create a file named file_paths.xml in that and copy the code exactly with the following.

Note: The path component corresponds to the path that is returned by getExternalFilesDir() when called with Environment.DIRECTORY_PICTURES .

To obtain the imageFilePath we don’t need to use the same as what we have used earlier, a new approach is :

If you want to handle, what if the user cancelled the camera intent without taking a picture like, though we have the imagePath, but it’s not a valid image because the user has not taken the picture. So, just compare the resultCode integer to confirm whether the user cancelled or taken the picture.

Источник

Оцените статью