问题
I'm trying to get the picture into service from Camera.
@Override
public void onCreate() {
super.onCreate();
//android.os.Debug.waitForDebugger();
myCamera=Camera.open();
SurfaceView dummy=new SurfaceView(getApplicationContext());
try {
if(myCamera!=null)
{
myCamera.setPreviewDisplay(dummy.getHolder());
myCamera.setPreviewCallback(this);
Log.i(TAG,"myCamera is not null");
}
getFrames();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "setPreviewDisplay " + e);
}
myCamera.startPreview();
}
public void getFrames() {
new Thread(new Runnable() {
public void run() {
while(flag)
{
Log.i(TAG, "getFrames");
try{
//method();
takePictureNoPreview();
Thread.sleep(54);
} catch (Exception e) {
Log.e(TAG, "getFrames thread error: " + e);
}
}
myCamera.release();
}
}).start();
}
public void takePictureNoPreview(){
try{
Log.i(TAG,"takePictureNoPreview");
myCamera.takePicture(null, null, getJpegCallback())
} catch (Exception e) {
Log.e(TAG, "takePictureNoPreview " + e);
}
private PictureCallback getJpegCallback(){
PictureCallback jpeg=new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
Log.i(TAG,"getJpegCallback");
FileOutputStream(String.format("/sdcard/RealSpeaker/%d.jpg", System.currentTimeMillis()));
FileOutputStream os = new FileOutputStream(String.format("/sdcard/Sample/%d.jpg", System.currentTimeMillis()));
os.write(data);
os.close();
} catch (IOException e) {
//do something about it
}
}
};
return jpeg;
}
The problem is that the method getJpegCallback around is incorrect: (no logs and images in a folder)ю When i'm debugging application, TAG - getJpegCallback do not show in LogCat, but TAG takePictureNoPreview shows. And after closing application, Camera dont allow(now it's no problem). What's wrong?
回答1:
I faced this issue when developing EyeSpy. I wanted to capture images even app is in background or foreground. I tried for some weeks but no luck. Capturing photo using camera means displaying its preview.
From Document(5. and 6.) And you have to use SurfaceView to display preview.
When you close app or your app goes into background the surface of SurfaceView
will be destroyed. That is why I think it's not possible.
If you found any other way then please post here.
Hope this help you..
回答2:
From API 11 on, instead of using the SurfaceHolder
of your SurfaceView
, you can use a SurfaceTexture
. Then, you set it up using Camera.setPreviewTexture
instead of Camera.setPreviewDisplay
.
It worked fine for me in a service on different devices.
This answer as well as this one discuss this point.
回答3:
public class TakePicture extends Activity implements SurfaceHolder.Callback {
// a variable to store a reference to the Image View at the main.xml file
// private ImageView iv_image;
// a variable to store a reference to the Surface View at the main.xml file
private SurfaceView sv;
// a bitmap to display the captured image
private Bitmap bmp;
FileOutputStream fo;
// Camera variables
// a surface holder
private SurfaceHolder sHolder;
// a variable to control the camera
private Camera mCamera;
// the camera parameters
private Parameters parameters;
private String FLASH_MODE;
private boolean isFrontCamRequest = false;
private Camera.Size pictureSize;
/** Called when the activity is first created. */
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// check if this device has a camera
if (checkCameraHardware(getApplicationContext()))
{
// get the Image View at the main.xml file
// iv_image = (ImageView) findViewById(R.id.imageView);
// get the Surface View at the main.xml file
Bundle extras = getIntent().getExtras();
String flash_mode = extras.getString("FLASH");
FLASH_MODE = flash_mode;
boolean front_cam_req = extras.getBoolean("Front_Request");
isFrontCamRequest = true;
System.out.println("front_cam_req :"+front_cam_req);
sv = (SurfaceView) findViewById(R.id.camera_preview);
// Get a surface
sHolder = sv.getHolder();
// add the callback interface methods defined below as the Surface
// View
// callbacks
sHolder.addCallback(this);
// tells Android that this surface will have its data constantly
// replaced
if (Build.VERSION.SDK_INT < 11)
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
else {
// display in long period of time
Toast.makeText(getApplicationContext(),
"Your Device dosen't have a Camera !", Toast.LENGTH_LONG)
.show();
}
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** Check if this device has front camera */
private boolean checkFrontCamera(Context context)
{
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT))
{
// this device has front camera
return true;
}
else
{
// no front camera on this device
return false;
}
}
public static Camera getCameraInstance()
{
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// get camera parameters
if (mCamera != null) {
parameters = mCamera.getParameters();
if (FLASH_MODE == null || FLASH_MODE.isEmpty()) {
FLASH_MODE = "auto";
}
parameters.setFlashMode(FLASH_MODE);
pictureSize = getBiggesttPictureSize(parameters);
if (pictureSize != null)
parameters
.setPictureSize(pictureSize.width, pictureSize.height);
// set camera parameters
mCamera.setParameters(parameters);
mCamera.startPreview();
// sets what code should be executed after the picture is taken
Camera.PictureCallback mCall = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// decode the data obtained by the camera into a Bitmap
Log.d("ImageTakin", "Done");
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
if (bmp != null)
bmp.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File imagesFolder = new File(
Environment.getExternalStorageDirectory(),
"OneSheeld");
if (!imagesFolder.exists())
imagesFolder.mkdirs(); // <----
File image = new File(imagesFolder,
System.currentTimeMillis() + ".jpg");
// write the bytes in file
try {
fo = new FileOutputStream(image);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
}
try {
fo.write(bytes.toByteArray());
} catch (IOException e) {
// TODO Auto-generated catch block
}
// remember close de FileOutput
try {
fo.close();
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment
.getExternalStorageDirectory())));
} catch (IOException e) {
// TODO Auto-generated catch block
}
if (mCamera != null) {
mCamera.stopPreview();
// release the camera
mCamera.release();
}
Toast.makeText(getApplicationContext(),
"Your Picture has been taken !", Toast.LENGTH_LONG)
.show();
if (bmp != null) {
bmp.recycle();
bmp = null;
System.gc();
}
TakePicture.this.finish();
}
};
mCamera.takePicture(null, null, mCall);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
// The Surface has been created, acquire the camera and tell it where
// to draw the preview.
if (isFrontCamRequest)
{
//Toast.makeText(getApplicationContext()," isFrontCamRequest()",Toast.LENGTH_LONG).show();
System.out.println("isFrontCamRequest 1");
// set flash 0ff
FLASH_MODE = "off";
// only for gingerbread and newer versions
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD)
{
System.out.println("isFrontCamRequest 2");
mCamera = openFrontFacingCameraGingerbread();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera = null;
Toast.makeText(getApplicationContext(),"API dosen't support front camera",Toast.LENGTH_LONG).show();
TakePicture.this.finish();
}
}
else
{
System.out.println("isFrontCamRequest 3");
if (checkFrontCamera(getApplicationContext()))
{
mCamera = openFrontFacingCameraGingerbread();
try
{
mCamera.setPreviewDisplay(holder);
}
catch (IOException exception)
{
mCamera = null;
Toast.makeText(getApplicationContext(),
"API dosen't support front camera",
Toast.LENGTH_LONG).show();
TakePicture.this.finish();
}
}/*
* else { // API dosen't support front camera or no front camera
* Log.d("Camera",
* "API dosen't support front camera or no front camera");
* Toast.makeText( getApplicationContext(),
* "API dosen't support front camera or no front camera",
* Toast.LENGTH_LONG).show();
*
* finish(); }
*/
}
}
else
{
System.out.println("isFrontCamRequest 4");
mCamera = getCameraInstance();
try
{
mCamera.setPreviewDisplay(holder);
}
catch (Exception exception) {
mCamera = null;
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// stop the preview
/*
* mCamera.stopPreview(); // release the camera mCamera.release();
*/
// unbind the camera from this object
mCamera = null;
}
private Camera openFrontFacingCameraGingerbread() {
int cameraCount = 0;
Camera cam = null;
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 {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e("Camera",
"Camera failed to open: " + e.getLocalizedMessage());
Toast.makeText(getApplicationContext(),
"Front Camera failed to open", Toast.LENGTH_LONG)
.show();
}
}
}
return cam;
}
@Override
protected void onDestroy() {
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my message!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
super.onDestroy();
}
private Camera.Size getBiggesttPictureSize(Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
return (result);
}
}
回答4:
It seems the solution is late but still..Actually we can have a UI from a service by usgin WindowManager
in onCreate() and inflating a layout..and setVisibility(View.INVISIBLE)
@Override public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
recording = false;
myview = inflater.inflate(R.layout.service_layout, null);
layout = (FrameLayout) myview.findViewById(R.id.preview);
minimize = (ImageButton) myview.findViewById(R.id.minimize);
minimize.setVisibility(ImageButton.GONE);
start = (Button) myview.findViewById(R.id.record);
start.setVisibility(Button.GONE);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!recording) {
if (prepareMediaRecorder()) {
try {
mediaRecorder.start();
Log.e("Camera------>", "working after");
recording = true;
start.setText("STOP");
handler.post(sendUpdates);
}catch (Exception e){
Log.getStackTraceString(e);
}
}
}else{
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder();
recording = false;
Log.e("Camera1------>", "working");
start.setText("START");
handler.post(sendUpdates);
}
}
});
you can also refer to a sample app https://github.com/gauravbspr/Research-Projects/tree/master/Camera%20Service and also contribute if seem neccesary
回答5:
You can try this
Intent translucent = new Intent(getApplication(),
TakePicture.class);
translucent.putExtra("FLASH", "on");
startActivity(translucent);
Toast.makeText(getApplicationContext(), "Started Capture", 500).show();
<SurfaceView
android:id="@+id/camera_preview"
android:layout_width="1dp"
android:layout_height="1dp" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
JUST DO THIS ITS WORKING FOR ME. Hope it helps.
来源:https://stackoverflow.com/questions/18634994/using-the-camera-in-background-android