В этом уроке:

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

 

Открываем серию уроков по работе с камерой. И начнем с самого простого. Если вам в приложении необходимо сделать снимок или снять видео, вовсе необязательно для этого создавать отдельное 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:

<string name="photo">Photo</string>
<string name="video">Video</string>

 

Экран main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btnPhoto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClickPhoto"
        android:text="@string/photo">
    </Button>
    <Button
        android:id="@+id/btnVideo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnPhoto"
        android:onClick="onClickVideo"
        android:text="@string/video">
    </Button>
    <ImageView
        android:id="@+id/ivPhoto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnVideo">
    </ImageView>
</RelativeLayout>

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

 

MainActivity.java:

package ru.startandroid.develop.p1311cameraintent;

import java.io.File;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {

  File directory;
  final int TYPE_PHOTO = 1;
  final int TYPE_VIDEO = 2;

  final int REQUEST_CODE_PHOTO = 1;
  final int REQUEST_CODE_VIDEO = 2;

  final String TAG = "myLogs";

  ImageView ivPhoto;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    createDirectory();
    ivPhoto = (ImageView) findViewById(R.id.ivPhoto);
  }

  public void onClickPhoto(View view) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, generateFileUri(TYPE_PHOTO));
    startActivityForResult(intent, REQUEST_CODE_PHOTO);
  }

  public void onClickVideo(View view) {
    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, generateFileUri(TYPE_VIDEO));
    startActivityForResult(intent, REQUEST_CODE_VIDEO);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode,
      Intent intent) {
    if (requestCode == REQUEST_CODE_PHOTO) {
      if (resultCode == RESULT_OK) {
        if (intent == null) {
          Log.d(TAG, "Intent is null");
        } else {
          Log.d(TAG, "Photo uri: " + intent.getData());
          Bundle bndl = intent.getExtras();
          if (bndl != null) {
            Object obj = intent.getExtras().get("data");
            if (obj instanceof Bitmap) {
              Bitmap bitmap = (Bitmap) obj;
              Log.d(TAG, "bitmap " + bitmap.getWidth() + " x "
                  + bitmap.getHeight());
              ivPhoto.setImageBitmap(bitmap);
            }
          }
        }
      } else if (resultCode == RESULT_CANCELED) {
        Log.d(TAG, "Canceled");
      }
    }

    if (requestCode == REQUEST_CODE_VIDEO) {
      if (resultCode == RESULT_OK) {
        if (intent == null) {
          Log.d(TAG, "Intent is null");
        } else {
          Log.d(TAG, "Video uri: " + intent.getData());
        }
      } else if (resultCode == RESULT_CANCELED) {
        Log.d(TAG, "Canceled");
      }
    }
  }

  private Uri generateFileUri(int type) {
    File file = null;
    switch (type) {
    case TYPE_PHOTO:
      file = new File(directory.getPath() + "/" + "photo_"
          + System.currentTimeMillis() + ".jpg");
      break;
    case TYPE_VIDEO:
      file = new File(directory.getPath() + "/" + "video_"
          + System.currentTimeMillis() + ".mp4");
      break;
    }
    Log.d(TAG, "fileName = " + file);
    return Uri.fromFile(file);
  }

  private void createDirectory() {
    directory = new File(
        Environment
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
        "MyFolder");
    if (!directory.exists())
      directory.mkdirs();
  }

}

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

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

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

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

 

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

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> - право на запись на SD карту

<uses-feature android:name="android.hardware.camera" /> - ваше приложение в маркете будет видно только устройствам с камерой

 

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

 

Жмем 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 вернул нам инфу о пути к файлу. Идем в папку и ищем свой файл.

 

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

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

  public void onClickPhoto(View view) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //intent.putExtra(MediaStore.EXTRA_OUTPUT, generateFileUri(TYPE_PHOTO));
    startActivityForResult(intent, REQUEST_CODE_PHOTO);
  }

  public void onClickVideo(View view) {
    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    //intent.putExtra(MediaStore.EXTRA_OUTPUT, generateFileUri(TYPE_VIDEO));
    startActivityForResult(intent, REQUEST_CODE_VIDEO);
  }

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

 

Жмем 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_VIDEO_QUALITY – качество видео. 0 (плохое) или 1 (хорошее).

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

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

 

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

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


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

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

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

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




Language

Автор сайта

Дмитрий Виноградов

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

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal