我正在开发一个开源设备管理器,但是有一个安全功能的问题,如果手机被盗,用户可以从相机拍照。在模拟器中一切都运行良好,但在运行Android 4.3.1的Nexus 4上,我收到以下错误(包括调试打印输出):
12-20 10:05:28.083: D/HelperService(22358): HERE0
12-20 10:05:28.354: D/HelperService(22358): HEREA
12-20 10:05:28.354: D/HelperService(22358): HEREB
12-20 10:05:28.374: D/HelperService(22358): HEREC
12-20 10:05:28.374: D/HelperService(22358): HERED
12-20 10:05:28.644: D/HelperService(22358): HERE2
12-20 10:05:28.644: D/HelperService(22358): HERE11
12-20 10:05:28.654: I/Choreographer(22358): Skipped 33 frames! The application may be doing too much work on its main thread.
12-20 10:05:30.656: D/AndroidRuntime(22358): Shutting down VM
12-20 10:05:30.656: W/dalvikvm(22358): threadid=1: thread exiting with uncaught exception (group=0x416287c0)
12-20 10:05:30.676: E/AndroidRuntime(22358): FATAL EXCEPTION: main
12-20 10:05:30.676: E/AndroidRuntime(22358): java.lang.RuntimeException: takePicture failed
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.hardware.Camera.native_takePicture(Native Method)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.hardware.Camera.takePicture(Camera.java:1145)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.hardware.Camera.takePicture(Camera.java:1090)
12-20 10:05:30.676: E/AndroidRuntime(22358): at com.nowsci.odm.HelperService$2$1.run(HelperService.java:271)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.os.Handler.handleCallback(Handler.java:730)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.os.Handler.dispatchMessage(Handler.java:92)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.os.Looper.loop(Looper.java:137)
12-20 10:05:30.676: E/AndroidRuntime(22358): at android.app.ActivityThread.main(ActivityThread.java:5289)
12-20 10:05:30.676: E/AndroidRuntime(22358): at java.lang.reflect.Method.invokeNative(Native Method)
12-20 10:05:30.676: E/AndroidRuntime(22358): at java.lang.reflect.Method.invoke(Method.java:525)
12-20 10:05:30.676: E/AndroidRuntime(22358): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
12-20 10:05:30.676: E/AndroidRuntime(22358): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:555)
12-20 10:05:30.676: E/AndroidRuntime(22358): at dalvik.system.NativeStart.main(Native Method)
以下是代码。我知道这有点难看,但我一直试图让这个工作与统一尝试/捕获,巩固相机打开等等。
public class HelperService extends Service {
...
private SurfaceHolder sHolder;
private Camera mCamera;
private Parameters parameters;
...
// For API 14 and newer
public class CamCallback implements Camera.PreviewCallback {
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG,"HERE1");
/*
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.takePicture(null, null, mCall);
//camera.takePicture(null, null, mCall);
}
}, 2000);
*/
}
}
...
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
...
public void onReceive(Context context, Intent intent) {
...
if (message.equals("Command:FrontPhoto") || message.equals("Command:RearPhoto")) {
boolean cont = true;
if (message.equals("Command:RearPhoto")) {
Log.d(TAG,"HERE0");
try {
mCamera = Camera.open();
} catch (RuntimeException e) {
Log.d(TAG, e.getMessage());
cont = false;
} finally {
if (mCamera != null) {
Log.d(TAG,"HEREA");
mCamera.stopPreview();
Log.d(TAG,"HEREB");
mCamera.release();
Log.d(TAG,"HEREC");
mCamera = null;
Log.d(TAG,"HERED");
}
}
try {
mCamera = Camera.open();
} catch (RuntimeException e) {
Log.d(TAG, e.getMessage());
cont = false;
}
} else {
int cameraCount = 0;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
mCamera = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.d(TAG, e.getMessage());
cont = false;
} finally {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
try {
mCamera = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.d(TAG, e.getMessage());
cont = false;
}
}
}
}
if (cont) {
if (android.os.Build.VERSION.SDK_INT >= 14) {
Log.d(TAG,"HERE2");
CamPreview camPreview = new CamPreview(context, mCamera);
camPreview.setSurfaceTextureListener(camPreview);
CamCallback camCallback = new CamCallback();
mCamera.setPreviewCallback(camCallback);
mCamera.startPreview();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.takePicture(null, null, mCall);
Log.d(TAG,"HERE12");
}
}, 2000);
Log.d(TAG,"HERE11");
} else {
// Pre-android 4.0
Log.d(TAG,"HERE3");
SurfaceView sv = new SurfaceView(context);
sHolder = sv.getHolder();
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
try {
mCamera.setPreviewDisplay(sHolder);
parameters = mCamera.getParameters();
mCamera.setParameters(parameters);
mCamera.startPreview();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.takePicture(null, null, mCall);
}
}, 2000);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
...
上面的违规代码是:
Log.d(TAG,"HERE2");
CamPreview camPreview = new CamPreview(context, mCamera);
camPreview.setSurfaceTextureListener(camPreview);
CamCallback camCallback = new CamCallback();
mCamera.setPreviewCallback(camCallback);
mCamera.startPreview();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.takePicture(null, null, mCall);
Log.d(TAG,"HERE12");
}
}, 2000);
Log.d(TAG,"HERE11");
我在StackOverflow上发现这是另一个解决方案,用于在Android 4.0及更高版本的服务中拍照(大多数解决方案都集中在4.0之前的版本)。如上所述,在模拟器中工作正常,但在设备上无效。清单包括预期的:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.front" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
想法?
感谢。