我的相机应用 manifest.xml 中有以下设置:
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="8" />
现在我把它改成了:
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="13" />
问题是:我的应用程序无法再打开相机了。此行引发错误:
this.camera = Camera.open();
错误信息:
连接相机服务失败
顺便说一句,奇怪的事情:使用新设置启动应用程序后,我不再让相机设备运行(所有其他照片应用程序也在启动时崩溃)。我必须重新启动设备才能再次使用相机。
有人可以帮我吗?
我的 Preview.java 类:
package net.mt.lib.cc;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import net.mt.lib.Tools;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Debug;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.crittercism.app.Crittercism;
import com.flurry.android.FlurryAgent;
/**
*
* openCamera()
* onSizeChanged()
* onLayout()
* onLayout()
* surfaceCreated()
* surfaceChanged()
* onLayout()
*/
class Preview extends ViewGroup implements SurfaceHolder.Callback { // <1>
private static final String TAG = "Preview";
SurfaceHolder mHolder; // <2>
public Camera camera; // <3>
SurfaceView mSurfaceView;
BaseCameraActivity cameraActivity;
int l2 = 0, t2 = 0, r2 = 0, b2 = 0;
int padding = 20;
PreviewCallback cb;
private double downscalingFactor = 1;
// the size of this view. gets set in onMeasure()
int fullWidth, fullHeight;
Size bestPictureSize = null;
Size bestPreviewSize = null;
private String allResolutions;
private Context context;
public Preview(Context context, PreviewCallback callback) {
super(context);
this.cb = callback;
init(context);
}
private void init(Context context) {
setKeepScreenOn(true);
cameraActivity = (BaseCameraActivity) context;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
this.context = context;
mHolder = mSurfaceView.getHolder(); // <4>
mHolder.addCallback(this); // <5>
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // <6>
}
public void openCamera() {
Log.d(TAG,"openCamera()");
if (this.camera == null) {
try{
this.camera = Camera.open();
this.camera.setErrorCallback(new ErrorCallback() {
@Override
public void onError(int error, Camera camera) {
Log.e(TAG, "error! code:"+error);
Toast.makeText(cameraActivity, "Camera error occured: "+error, 8000).show();
}
});
requestLayout(); // -> onSizeChanged() -> onLayout()
}catch (Exception e) {
String errorMessage = "Manufacturer: "+Build.MANUFACTURER+"; Model:"+Build.MODEL+"; Camera: "+this.camera+"; Stacktrace:"+Tools.exception2String(e);
Log.d(TAG,"error occured: "+errorMessage);
FlurryAgent.onError("1", errorMessage, "Preview.openCamera()");
Toast.makeText(cameraActivity, "Uuups, I am sorry! Could not connect to the camera device. Please restart me or your phone.", 8000).show();
Crittercism.logHandledException(e);
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG,"onSizeChanged() "+w+" "+h);
fullWidth = w;
fullHeight = h;
if(fullWidth < fullHeight){
int tmp = fullHeight;
fullHeight = fullWidth;
fullWidth = tmp;
Log.d(TAG,"switched:"+fullWidth+"x"+fullHeight);
}else{
Log.d(TAG,"fullSize:"+fullWidth+"x"+fullHeight);
}
if(this.camera != null){
this.setCameraPreviewSize();
this.setCameraPictureSize();
if (getChildCount() > 0) {
final View child = getChildAt(0);
Log.d(TAG,"r:"+this.getPreviewRight()+" l:"+this.getPreviewLeft()+" b:"+this.getPreviewBottom()+" t:"+this.getPreviewTop());
child.layout(this.getPreviewLeft(), this.getPreviewTop(), this.getPreviewRight(), this.getPreviewBottom());
cb.previewReady(getPreviewLeft(), getPreviewTop(), getPreviewRight()-getPreviewLeft(), getPreviewBottom() - getPreviewTop(), getBestPictureSize().width, getBestPictureSize().height, (int) downscalingFactor, allResolutions);
}
}
super.onSizeChanged(w, h, oldw, oldh);
}
private void calcScaledPreviewSize(){
int previewWidth = getBestPreviewSize().width;
int previewHeight = getBestPreviewSize().height;
float scaledWidth;
float scaledHeight;
Log.d(TAG,"preview width: "+previewWidth+", preview height: "+previewHeight);
Log.d(TAG,"display width: "+fullWidth+", display height: "+fullHeight);
float previewRatio = (float) previewWidth / (float) previewHeight;
float displayRatio = (float) fullWidth / (float) fullHeight;
if(displayRatio >= previewRatio){ // the display is wider then the preview image
scaledHeight = fullHeight - 2*padding;
scaledWidth = scaledHeight * previewRatio;
l2 = (int) (fullWidth - scaledWidth) / 2;
t2 = padding;
r2 = (int) (fullWidth + scaledWidth) / 2;
b2 = (int) scaledHeight + padding;
}else{
scaledWidth = fullWidth - 2*padding;
scaledHeight = scaledWidth / previewRatio;
l2 = padding;
t2 = (int) (fullHeight - scaledHeight) / 2;
r2 = (int) scaledWidth + padding;
b2 = (int) (fullHeight + scaledHeight) / 2;
}
}
public int getPreviewTop() {
if(this.t2 == 0){
this.calcScaledPreviewSize();
}
return t2;
}
public int getPreviewBottom() {
if(this.b2 == 0){
this.calcScaledPreviewSize();
}
return b2;
}
public int getPreviewLeft() {
if(this.l2 == 0){
this.calcScaledPreviewSize();
}
return l2;
}
public int getPreviewRight() {
if(this.r2 == 0){
this.calcScaledPreviewSize();
}
return r2;
}
public int getPreviewWidth() {
return this.getPreviewRight()-this.getPreviewLeft();
}
public int getPreviewHeight() {
return this.getPreviewBottom()-this.getPreviewTop();
}
private void setCameraPreviewSize() {
Camera.Parameters parameters = camera.getParameters();
if(parameters.getPreviewSize() != this.getBestPreviewSize()){
parameters.setPreviewSize(this.getBestPreviewSize().width, this.getBestPreviewSize().height);
this.camera.setParameters(parameters);
}
}
private void setCameraPictureSize() {
Camera.Parameters parameters = this.camera.getParameters();
if(parameters.getPictureSize() != this.getBestPictureSize()){
parameters.setPictureSize(getBestPictureSize().width, getBestPictureSize().height);
this.camera.setParameters(parameters);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.d(TAG,"onLayout()");
/*
if (changed && getChildCount() > 0 && this.camera != null) {
final View child = getChildAt(0);
Log.d(TAG,"r:"+this.getPreviewRight()+" l:"+this.getPreviewLeft()+" b:"+this.getPreviewBottom()+" t:"+this.getPreviewTop());
child.layout(this.getPreviewLeft(), this.getPreviewTop(), this.getPreviewRight(), this.getPreviewBottom());
cameraActivity.initOverlay(this.getPreviewLeft(),this.getPreviewTop(),this.getPreviewRight(),this.getPreviewBottom());
}*/
}
public Size getBestPictureSize() {
if(this.bestPictureSize == null){
this.calculateOptimalPictureAndPreviewSizes();
}
return bestPictureSize;
}
public Size getBestPreviewSize() {
if(this.bestPreviewSize == null){
this.calculateOptimalPictureAndPreviewSizes();
}
return bestPreviewSize;
}
// Called once the holder is ready
public void surfaceCreated(SurfaceHolder holder) { // <7>
// The Surface has been created, acquire the camera and tell it where
// to draw.
Log.d(TAG,"surfaceCreated()");
try {
if (this.camera != null) {
this.camera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.d(TAG,"surfaceChanged()");
if (camera != null) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(getBestPreviewSize().width, getBestPreviewSize().height);
camera.setParameters(parameters);
camera.startPreview();
cb.onPreviewStart();
requestLayout();
}
}
public void surfaceDestroyed(SurfaceHolder holder) { // <14>
Log.d(TAG,"surfaceDestroyed()");
if(this.camera != null){
camera.stopPreview();
camera.lock();
camera.release();
this.camera = null;
}
}
public void releaseCamera(){
Log.d(TAG,"releaseCamera()");
if (camera != null) {
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
}
}
预览是这样初始化的(来自主要活动):
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"onResume()");
previewLayout.removeAllViews();
preview = new Preview(this, this);
previewLayout.addView(preview, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
preview.openCamera();
}
和清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.mc.ccPro"
android:versionCode="35"
android:versionName="3.5" >
<application
android:hardwareAccelerated="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:largeHeap="true" >
<activity
android:name=".ccProActivity"
android:configChanges="keyboard|orientation|keyboardHidden"
android:label="@string/app_name"
android:windowSoftInputMode="adjustPan" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="net.mc.lib.cc.PreferenceActivity"
android:label="@string/set_preferences" >
</activity>
</application>
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:resizeable="true"
android:anyDensity="true" />
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="8" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-library android:name="net.mc.lib.cc" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
</manifest>