Android ACTION_IMAGE_CAPTURE Intent

Мы пытаемся использовать собственное приложение для камеры, чтобы пользователь мог сделать новое изображение. Он отлично работает, если оставить EXTRA_OUTPUT extra и вернуть небольшое изображение растрового изображения. Однако, если мы putExtra(EXTRA_OUTPUT,...) в намерении перед запуском, все работает, пока вы не попытаетесь нажать кнопку "ОК" в приложении камеры. Кнопка "ОК" просто ничего не делает. Приложение камеры остается открытым и ничего не блокируется. Мы можем отказаться от него, но файл никогда не записывается. Что именно нам нужно сделать, чтобы получить ACTION_IMAGE_CAPTURE, чтобы записать снимок, сделанный в файл?

Изменить: это делается с помощью намерения MediaStore.ACTION_IMAGE_CAPTURE, чтобы быть четким

Ответ 1

это хорошо документированная ошибка в некоторых версиях android. т.е. при сборке google на основе android, захват изображения не работает, как документировано. то, что я обычно использовал, это что-то вроде этого в классе утилит.

public boolean hasImageCaptureBug() {

    // list of known devices that have the bug
    ArrayList<String> devices = new ArrayList<String>();
    devices.add("android-devphone1/dream_devphone/dream");
    devices.add("generic/sdk/generic");
    devices.add("vodafone/vfpioneer/sapphire");
    devices.add("tmobile/kila/dream");
    devices.add("verizon/voles/sholes");
    devices.add("google_ion/google_ion/sapphire");

    return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/"
            + android.os.Build.DEVICE);

}

тогда, когда я запускаю захват изображения, я создаю намерение, проверяющее ошибку.

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
    i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp")));
} else {
    i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(i, mRequestCode);

затем в действии, к которому я возвращаюсь, я делаю разные вещи на основе устройства.

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
     switch (requestCode) {
         case GlobalConstants.IMAGE_CAPTURE:
             Uri u;
             if (hasImageCaptureBug()) {
                 File fi = new File("/sdcard/tmp");
                 try {
                     u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null));
                     if (!fi.delete()) {
                         Log.i("logMarker", "Failed to delete " + fi);
                     }
                 } catch (FileNotFoundException e) {
                     e.printStackTrace();
                 }
             } else {
                u = intent.getData();
            }
    }

это избавит вас от необходимости писать новое приложение для камеры, но этот код тоже невелик. большие проблемы:

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

  • вам нужно вести список. в виде написано, возможно для устройств для сверки с версией android (скажем cyanogenmod's builds), в котором исправлена ​​ошибка. если это произойдет, ваш код будет авария. исправление заключается в использовании всего отпечаток устройства.

Ответ 2

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

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

String storageState = Environment.getExternalStorageState();
        if(storageState.equals(Environment.MEDIA_MOUNTED)) {

            String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg";
            _photoFile = new File(path);
            try {
                if(_photoFile.exists() == false) {
                    _photoFile.getParentFile().mkdirs();
                    _photoFile.createNewFile();
                }

            } catch (IOException e) {
                Log.e(TAG, "Could not create file.", e);
            }
            Log.i(TAG, path);

            _fileUri = Uri.fromFile(_photoFile);
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
            intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri);
            startActivityForResult(intent, TAKE_PICTURE);
        }   else {
            new AlertDialog.Builder(MainActivity.this)
            .setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
            .setCancelable(true).create().show();
        }

Сначала я создаю уникальное (несколько) имя файла, используя хеш MD5 и помещаю его в соответствующую папку. Затем я проверяю, существует ли он (не должен, но его хорошая практика проверять в любом случае). Если он не существует, я получаю родительский каталог (папку) и создаю иерархию папок до него (поэтому, если папки, ведущие к местоположению файла, не существуют, они будут после этой строки. Я создаю файл. После создания файла я получаю Uri и передаю его намерению, а затем кнопка OK работает так, как ожидалось, и все золотые.

Теперь, когда кнопка ОК нажата в приложении камеры, файл будет присутствовать в данном месте. В этом примере это будет /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg

Нет необходимости копировать файл в "onActivityResult", как указано выше.

Ответ 3

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

mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
            new ContentValues());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);

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

https://github.com/deepwinter/AndroidCameraTester

Ответ 4

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

Проблема исчезла после указания безопасного имени файла без белых пробелов без специальных символов в MediaStore.EXTRA_OUTPUT Кроме того, если вы указываете файл, который находится в каталоге, который еще не был создан, вам необходимо создать это сначала. Приложение камеры не делает mkdir для вас.

Ответ 5

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

private void saveFullImage() {
  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
  outputFileUri = Uri.fromFile(file);
  intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
  startActivityForResult(intent, TAKE_PICTURE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) {
    // Check if the result includes a thumbnail Bitmap
    if (data == null) {    
      // TODO Do something with the full image stored
      // in outputFileUri. Perhaps copying it to the app folder
    }
  }
}

Обратите внимание, что это Операция Camera, которая будет создавать и сохранять файл, а на самом деле это не часть вашего приложения, поэтому у него не будет права на запись в папку вашего приложения. Чтобы сохранить файл в папке вашего приложения, создайте временный файл на SD-карте и переместите его в папку приложения в обработчике onActivityResult.

Ответ 6

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

Это означает, что вы не можете создать файл в месте, которое может быть записано только вашим приложением (например, что-то под getCacheDir()) Что-то в getExternalFilesDir() должно работать.

Было бы неплохо, если бы приложение камеры напечатало сообщение об ошибке в журналах, если оно не могло записать указанный путь EXTRA_OUTPUT, но я его не нашел.

Ответ 7

чтобы камера записывала на SDCard, но сохранила в новом альбоме приложение галереи. Я использую это:

 File imageDirectory = new File("/sdcard/signifio");
          String path = imageDirectory.toString().toLowerCase();
           String name = imageDirectory.getName().toLowerCase();


            ContentValues values = new ContentValues(); 
            values.put(Media.TITLE, "Image"); 
            values.put(Images.Media.BUCKET_ID, path.hashCode());
            values.put(Images.Media.BUCKET_DISPLAY_NAME,name);

            values.put(Images.Media.MIME_TYPE, "image/jpeg");
            values.put(Media.DESCRIPTION, "Image capture by camera");
           values.put("_data", "/sdcard/signifio/1111.jpg");
         uri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values);
            Intent i = new Intent("android.media.action.IMAGE_CAPTURE"); 

            i.putExtra(MediaStore.EXTRA_OUTPUT, uri);

            startActivityForResult(i, 0); 

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

Ответ 8

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

Ответ 9

У меня была такая же проблема, и я исправил ее следующим образом:

Проблема заключается в том, что при указании файла, к которому имеет доступ только ваше приложение (например, путем вызова getFileStreamPath("file");)

Вот почему я просто убедился, что данный файл действительно существует и что у ВСЕГО есть доступ на него.

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File outFile = getFileStreamPath(Config.IMAGE_FILENAME);
outFile.createNewFile();
outFile.setWritable(true, false);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,Uri.fromFile(outFile));
startActivityForResult(intent, 2);

Таким образом, приложение камеры имеет доступ на запись к данному Uri, и кнопка OK работает нормально:)

Ответ 10

Очень просто решить эту проблему с помощью кода результата деятельности. Простой метод:

if (reqCode == RECORD_VIDEO) {
   if(resCode == RESULT_OK) {
       if (uri != null) {
           compress();
       }
    } else if(resCode == RESULT_CANCELED && data!=null){
       Toast.makeText(MainActivity.this,"No Video Recorded",Toast.LENGTH_SHORT).show();
   }
}

Ответ 11

Я создал простую библиотеку, которая будет управлять выбором изображений из разных источников (Галерея, Камера), возможно, сохранит ее в каком-либо месте (SD-Card или внутренняя память) и вернет изображение, чтобы, пожалуйста, бесплатно использовать его и улучшить его - Android-ImageChooser.

Ответ 12

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

В моем использовании я хотел сохранить файл во внутреннем хранилище. Я сделал это с помощью:

Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (i.resolveActivity(getPackageManager()!=null)){
    try{
        cacheFile = createTempFile("img",".jpg",getCacheDir());
        cacheFile.setWritavle(true,false);
    }catch(IOException e){}
    if(cacheFile != null){
        i.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(cacheFile));
        startActivityForResult(i,REQUEST_IMAGE_CAPTURE);
    }
}

Здесь cacheFile - это глобальный файл, используемый для ссылки на файл, который написан. Затем в методе результата возвращаемое намерение равно null. Затем метод обработки намерения выглядит так:

protected void onActivityResult(int requestCode,int resultCode,Intent data){
    if(requestCode != RESULT_OK){
        return;
    }
    if(requestCode == REQUEST_IMAGE_CAPTURE){
        try{
            File output = getImageFile();
            if(output != null && cacheFile != null){
                copyFile(cacheFile,output);

                //Process image file stored at output

                cacheFile.delete();
                cacheFile=null;
            }
        }catch(IOException e){}
    }
}

Здесь getImageFile() - это метод утилиты для указания и создания файла, в котором должно храниться изображение, а copyFile() - метод копирования файла.

Ответ 13

Вы можете использовать этот код

private Intent getCameraIntent() {

    PackageManager packageManager = mContext.getPackageManager();
    List<ApplicationInfo> list = packageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
    Intent main = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    List<ResolveInfo> launchables = packageManager.queryIntentActivities(main, 0);
    if (launchables.size() == 1)
        return packageManager.getLaunchIntentForPackage(launchables.get(0).activityInfo.packageName);
    else
        for (int n = 0; n < list.size(); n++) {
            if ((list.get(n).flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
                Log.d("TAG", "Installed Applications  : " + list.get(n).loadLabel(packageManager).toString());
                Log.d("TAG", "package name  : " + list.get(n).packageName);
                String defaultCameraPackage = list.get(n).packageName;


                if (launchables.size() > 1)
                    for (int i = 0; i < launchables.size(); i++) {
                        if (defaultCameraPackage.equals(launchables.get(i).activityInfo.packageName)) {
                            return packageManager.getLaunchIntentForPackage(defaultCameraPackage);
                        }
                    }
            }
        }
    return null;
}

Ответ 14

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_CANCELED)
    {
        //do not process data, I use return; to resume activity calling camera intent
        enter code here
    }
}