2014-01-29 47 views
4

作爲一種學習練習,我正在編寫一個安全應用程序,當發生任意事件時,需要打開相機,拍照並關閉相機,而不用擔心關於閃光燈,焦點或顯示預覽。我跟隨在線演示,製作了一個可以拍照的工作應用程序,但它使用了預覽和所有這些。所以我開始努力讓它在沒有預覽的情況下運行。無論如何,我不斷收到'takePicture failed'的例外情況,我沒有任何現實的想法。我希望有更多Camera API經驗的人可以看看並指出我的方向。以下是我的相關文件。我正在使用最新的Android Studio並在Galaxy S4上進行測試。Android Camera.take圖片失敗

[MainActivity.java]

package com.g5digital.cam2; 

import android.content.pm.PackageManager; 
import android.hardware.Camera; 
import android.support.v7.app.ActionBarActivity; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.Button; 
import android.widget.LinearLayout; 
import android.widget.Toast; 

import java.io.IOException; 

public class MainActivity extends ActionBarActivity implements View.OnClickListener { 

    private static final String TAG = "MainActivity"; 
    private Button button; 
    private int cameraId; 
    private Camera camera; 
    private CameraPreview camPreview; 
    private LinearLayout container; 
    private Camera.Parameters camParms; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     container = (LinearLayout)findViewById(R.id.container); 

     button = (Button)findViewById(R.id.button); 
     button.setOnClickListener(this); 
    } 


    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int id = item.getItemId(); 
     if (id == R.id.action_settings) { 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    @Override 
    public void onClick(View view) { 
     openCamera(); 

     try { 
      if (camera != null) { 
       PhotoHandler ph = new PhotoHandler(this, camera); 
       camera.takePicture(null, null, ph); 

       // Commented until takePicture() works 
       /*(new Handler()).postDelayed(new Runnable() { 
        @Override 
        public void run() { 
         MainActivity.this.closeCamera(); 
        } 
       }, 1000);*/ 
      } 
     } 
     catch (Exception e) { 
      closeCamera(); 
      Log.d(TAG, e.getMessage()); 
      e.printStackTrace(); 
     } 
    } 

    private void openCamera() { 
     // do we have a camera? 
     if (!getPackageManager() 
       .hasSystemFeature(PackageManager.FEATURE_CAMERA)) { 
      Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG) 
        .show(); 
     } 
     else { 
      closeCamera(); 

      cameraId = findFrontFacingCameraId(); 
      if (cameraId < 0) { 
       Toast.makeText(this, "No front facing camera found.", 
         Toast.LENGTH_LONG).show(); 
      } else { 
       camera = Camera.open(cameraId); 
       try { 
        setCamParms(); 

        setCamPreview(); 
        camera.startPreview(); 
       } 
       catch (Exception e) { 
        closeCamera(); 
        e.printStackTrace(); 
        finish(); 
        return; 
       } 
      } 
     } 
    } 

    private void closeCamera() { 
     if (camera != null) { 
      camera.release(); 
      camera = null; 
     } 
    } 

    private int findFrontFacingCameraId() { 
     int camera_id = -1; 
     // Search for the front facing camera 
     int numberOfCameras = Camera.getNumberOfCameras(); 
     for (int i = 0; i < numberOfCameras; i++) { 
      Camera.CameraInfo info = new Camera.CameraInfo(); 
      Camera.getCameraInfo(i, info); 
      if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 
       Log.d(TAG, "Camera found"); 
       camera_id = i; 
       break; 
      } 
     } 
     return camera_id; 
    } 

    private void setCamParms() { 
     if (camParms == null && camera != null) { 
      camParms = camera.getParameters(); 
      camParms.setFlashMode("Off"); 
     } 
     if (camera != null) { 
      camera.setParameters(camParms); 
      camera.setDisplayOrientation(90); 
     } 
    } 

    private void setCamPreview() throws IOException { 
     if (camPreview == null && camera != null) { 
      camPreview = new CameraPreview(this, camera); 
     } 
     if (camera != null) { 
      camera.setPreviewDisplay(camPreview.getHolder()); 
     } 
    } 
} 

[CameraPreview.java]

package com.g5digital.cam2; 

import android.content.Context; 
import android.hardware.Camera; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

import java.io.IOException; 

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 
    private Context context; 
    private Camera camera; 
    private SurfaceHolder holder; 
    private static final String TAG = "CameraPreview"; 

    public CameraPreview(Context c, Camera cam) { 
     super(c); 
     context = c; 
     camera = cam; 
     holder = getHolder(); 
     holder.addCallback(this); 
    } 

    @Override 
    public void surfaceCreated(SurfaceHolder surfaceHolder) { 
     try { 
      camera.setPreviewDisplay(holder); 
      camera.startPreview(); 
     } catch (IOException e) { 
      Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 
     } catch (Exception e) { 
      // Probably getting "called after release()" message 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) { 
     // If your preview can change or rotate, take care of those events here. 
     // Make sure to stop the preview before resizing or reformatting it. 

     if (holder.getSurface() == null){ 
      // preview surface does not exist 
      return; 
     } 

     // stop preview before making changes 
     try { 
      camera.stopPreview(); 
     } catch (Exception e){ 
      // ignore: tried to stop a non-existent preview 
     } 

     // set preview size and make any resize, rotate or 
     // reformatting changes here 

     // start preview with new settings 
     try { 
      camera.setPreviewDisplay(holder); 
      camera.startPreview(); 

     } catch (Exception e){ 
      Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
     } 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 
     // 
    } 
} 

[PhotoHandler.java]

package com.g5digital.cam2; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Matrix; 
import android.hardware.Camera; 
import android.os.Environment; 
import android.util.Log; 
import android.widget.Toast; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

public class PhotoHandler implements Camera.PictureCallback { 
    private final Context context; 
    private final Camera camera; 

    public PhotoHandler(Context context, Camera c) { 
     this.context = context; 
     this.camera = c; 
    } 

    @Override 
    public void onPictureTaken(byte[] bytes, Camera cam) { 
     Log.i("PhotoHandler", "Picture taken!"); 
     File pictureFileDir = getDir(); 

     if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) { 

      Log.d("PhotoHandler", "Can't create directory to save image."); 
      Toast.makeText(context, "Can't create directory to save image.", 
        Toast.LENGTH_LONG).show(); 
      return; 

     } 

     Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 
     int width = bmp.getWidth(); 
     int height = bmp.getHeight(); 
     Matrix matrix = new Matrix(); 
     matrix.postRotate(270); 
     Bitmap rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0, 
       width, height, matrix, true); 

     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); 
     String date = dateFormat.format(new Date()); 
     String photoFile = "Picture_" + date + ".jpg"; 

     String filename = pictureFileDir.getPath() + File.separator + photoFile; 

     File pictureFile = new File(filename); 

     try { 
      FileOutputStream fos = new FileOutputStream(pictureFile); 
      boolean result = rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); 
      //fos.write(bytes); 
      fos.close(); 
      if (result) { 
       Toast.makeText(context, "New Image saved:" + photoFile, 
         Toast.LENGTH_LONG).show(); 
      } 
      else { 
       Toast.makeText(context, "Couldn't save image:" + photoFile, 
         Toast.LENGTH_LONG).show(); 
      } 
      camera.startPreview(); 
     } catch (Exception error) { 
      Log.d("PhotoHandler", "File" + filename + "not saved: " 
        + error.getMessage()); 
      Toast.makeText(context, "Image could not be saved.", 
        Toast.LENGTH_LONG).show(); 
     } 
    } 

    private File getDir() { 
     File sdDir = Environment 
       .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); 
     return new File(sdDir, "CameraAPIDemo"); 
    } 
} 

[AndroidManifest.xml中]

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.g5digital.cam2" > 

    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-permission android:name="android.permission.FLASHLIGHT" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-feature android:name="android.hardware.camera" /> 
    <uses-feature android:name="android.hardware.camera.autofocus" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name="com.g5digital.cam2.MainActivity" 
      android:label="@string/app_name" 
      android:screenOrientation="portrait"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application> 

</manifest> 

[activity_main.xml中]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" 
    tools:context="com.g5digital.cam2.MainActivity" 
    tools:ignore="MergeRootFrame"> 

    <Button 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@string/click" 
     android:id="@+id/button" /> 
</LinearLayout> 

[logcat的輸出]

01-29 14:55:45.826 5853-5853/com.g5digital.cam2 D/MainActivity﹕ takePicture failed 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ java.lang.RuntimeException: takePicture failed 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.native_takePicture(Native Method) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1194) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1139) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.g5digital.cam2.MainActivity.onClick(MainActivity.java:66) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View.performClick(View.java:4475) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View$PerformClick.run(View.java:18786) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:730) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:92) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Looper.loop(Looper.java:137) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5419) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:525) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187) 
01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 
01-29 14:55:45.836 5853-5853/com.g5digital.cam2 W/System.err﹕ at dalvik.system.NativeStart.main(Native Method) 

回答

3

沒有,要拍照你必須顯示預覽。有很多熟練人員發明的解決方法,例如見Take Picture without preview Android, Android: Is it possible to take a picture with the camera from a service with no UI,How to use Camera to take picture in a background Service on Android? ...

但請記住,該要求不是技術性的,而是隱私的目的。系統繼續發展,並防止發現新的解決方法。

也許在S4上隱藏預覽的最健壯的方法是使用SurfaceTexture,但是卻不可見地顯示它,從視口移出。

+0

哦....我想我應該多用一點google了。謝謝您的幫助。 –