I want to get a preview of the camera on screen (Android Studio), the problem is that I'm in a class which extends a Fragment. I would like to have it on a surface view (with a dimension of about 1/6 of the screen size), in such a way that the preview is always running independently on the surface view while I capture pictures.
The code which take picture is running ok, the only thing that I can't do is to create the independent preview on surface view.
Any idea on how to accomplish that? Given that I'm in a Fragment and I've already created the method onCreateView.
I've searched online but I've only found code for preview plus taking picture.
The idea of what I want to do is the following, but it doesn't work in Fragment unfortunately:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
#SuppressWarnings("deprecation")
Camera camera; // camera class variable
SurfaceView camView; // drawing camera preview using this variable
SurfaceHolder surfaceHolder; // variable to hold surface for surfaceView which means display
boolean camCondition = false; // conditional variable for camera preview checking and set to false
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// getWindow() to get window and set it's pixel format which is UNKNOWN
getWindow().setFormat(PixelFormat.UNKNOWN);
// refering the id of surfaceView
camView = (SurfaceView) findViewById(R.id.camerapreview);
// getting access to the surface of surfaceView and return it to surfaceHolder
surfaceHolder = camView.getHolder();
// adding call back to this context means MainActivity
surfaceHolder.addCallback(this);
// to set surface type
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
// stop the camera
if(camCondition){
camera.stopPreview(); // stop preview using stopPreview() method
camCondition = false; // setting camera condition to false means stop
}
// condition to check whether your device have camera or not
if (camera != null){
try {
Camera.Parameters parameters = camera.getParameters();
parameters.setColorEffect(Camera.Parameters.EFFECT_SEPIA); //applying effect on camera
camera.setParameters(parameters); // setting camera parameters
camera.setPreviewDisplay(surfaceHolder); // setting preview of camera
camera.startPreview(); // starting camera preview
camCondition = true; // setting camera to true which means having camera
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera = Camera.open(); // opening camera
camera.setDisplayOrientation(90); // setting camera preview orientation
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview(); // stopping camera preview
camera.release(); // releasing camera
camera = null; // setting camera to null when left
camCondition = false; // setting camera condition to false also when exit from application
}
}
The xml code is the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.tensorflow.demo.AutoFitTextureView
android:id="#+id/texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<org.tensorflow.demo.RecognitionScoreView
android:id="#+id/results"
android:layout_width="match_parent"
android:layout_height="198dp"
android:layout_alignParentTop="true" />
<org.tensorflow.demo.OverlayView
android:id="#+id/debug_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="21dp"
android:layout_marginStart="12dp"
android:text="Capture" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignTop="#+id/button"
android:layout_marginEnd="35dp"
android:text="Preview" />
<SurfaceView
android:id="#+id/surfaceView2"
android:layout_width="wrap_content"
android:layout_height="67dp"
android:layout_alignBottom="#+id/button"
android:layout_alignParentStart="true"
android:layout_marginStart="134dp" />
The initial part of code I have in my extended Fragment is the following:
public class CameraConnectionFragment extends Fragment {
private static final Logger LOGGER = new Logger();
/**
* The camera preview size will be chosen to be the smallest frame by pixel size capable of
* containing a DESIRED_SIZE x DESIRED_SIZE square.
*/
private static final int MINIMUM_PREVIEW_SIZE = 320;
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final String FRAGMENT_DIALOG = "dialog";
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
/**
* {#link android.view.TextureView.SurfaceTextureListener} handles several lifecycle events on a
* {#link TextureView}.
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.camera_connection_fragment, container, false);
Button capture = (Button) view.findViewById(R.id.button);
Button preview = (Button) view.findViewById(R.id.button2);
preview.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
capture.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
captureSession.capture(previewRequest, captureCallback, backgroundHandler);
}
catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
}
}
});
return view;
}
What do you think I can do to have a continuos flow of image preview in the surfaceview?
Related
I am trying to implement camera features on my application. Since it's my first time doing so, I'm running a little issue with my camera preview.
My current layout looks like this:
Which is producing a preview like this:
However I want something like this:
And here is the code for my camera:
public class FragmentPhoto extends Fragment implements TextureView.SurfaceTextureListener {
private Camera camera;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_photo, container, false);
final TextureView textureView = (TextureView) view.findViewById(R.id.photo_view);
textureView.setSurfaceTextureListener(this);
return view;
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
camera = Camera.open();
camera.setDisplayOrientation(90);
camera.setPreviewTexture(surface);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
camera.stopPreview();
camera.release();
return true;
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Update your view here!
}
}
Is there any way to crop the camera? To not make the preview this chubby? What is the best aproach to do this?
I am making an application where I have a camera inside of a viewPager. I am wondering what would best be suited to "pause" and "resume" the camera so it doesn't hog resources when it is pre-loaded. I have the feeling that stopPreview is better suited for this as it does not release the camera but keeps it however it doesn't display the camera which is the main reason it hogs resources.
Enter & exit application: startCamera() & releaseCamera()
Tab visible & not visible: startPreview() & stop Preview()
Would this be a good rule of thumb?
I had a similar situation. :
If I kept camera (in ViewPager) in on state, the swipe were clunky and OOM exceptions were frequent.
Two options came in my mind:
shift the entire instance in a different thread
OR
use stopPreview() and startPreview()
I went with the second one :
However, instead of doing this on Fragment lifecycle callbacks I gave a button on the fragment which toggled the preview. Reason being, if user is swiping very fast, you can still receive OOm exception since the preview calls will be queued, especially if there are very few fragments in the viewPager.
In essence Release camera onPause(), acquire camera in onResume() and give a groovy button in fragment which will toggle your Preview on the surface!
Hello Karl I had the same things need to implement in view pager. I have circular viewer in which one fragment has the camera fragment. I want to handle the camera preview in such a way so it should not consume the camera resource.
As you know android view pager default load two fragment in to the memory. We implemented the view pager change listener and call the fragment method to start and stop the preview. even also destroy the camera preview in on destroy method of fragment.
class ViewPagerChangeListener implements ViewPager.OnPageChangeListener {
int currentPosition = DEFAULT_FRAGMENT;
#Override
public void onPageScrollStateChanged(int state) {
TimberLogger.d(TAG, "onPageScrollStateChanged");
}
#Override
public void onPageScrolled(int index, float arg1, int arg2) {
TimberLogger.d(TAG, "onPageScrolled" + index);
}
#Override
public void onPageSelected(int position) {
mWatchPosition = position;
TimberLogger.d(TAG, "onPageSelected" + mWatchPosition);
int newPosition = 0;
if (position > 4) {
newPosition = position;
}
TimberLogger.d(TAG, "newPosition" + newPosition);
/**
* Listener knows the new position and can call the interface method
* on new Fragment with the help of PagerAdapter. We can here call
* onResumeFragment() for new fragment and onPauseFragment() on the
* current one.
*/
// new fragment onResume
loadedFragment(newPosition).onResumeFragment();
// current fragment onPuase called
loadedFragment(currentPosition).onPauseFragment();
currentPosition = newPosition;
TimberLogger.d(TAG, "currentPosition" + currentPosition);
}
}
See the two method onResumeFragment and onPuaseFragment this two are the custom function each view pager fragment implements. In view pager change event we call the pause of current fragment and onResume of the new fragment.
// new fragment onResume
loadedFragment(newPosition).onResumeFragment();
// current fragment onPuase called
loadedFragment(currentPosition).onPauseFragment();
You can write your camera start preview inside custom method onResumeFragment and stop preview in onPauseFragment and also make sure you should override the onDestory() method of your camera fragment for release the camera resources.
The best solution will be to startCamera() in onResume(), and release it in onPause(), so you can handle, that camera is not free in onResume().
In ViewPager you can startPreview(), when fragment with it is selected, and stopPreview() otherwise. Also u can startPreview() in onCreateView() and stopPreview() in onDestroyView() in fragment.
This takes care of most of the operations CameraPreview.java:
package com.example.fela;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import java.util.List;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
private int cameraId;
private Activity activity;
private CameraPreviewActivityInterface activityInterface;
public CameraPreview(Activity activity, int cameraId) {
super(activity);
try {
activityInterface = (CameraPreviewActivityInterface) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ExampleFragmentCallbackInterface ");
}
this.activity = activity;
this.cameraId = cameraId;
holder = getHolder();
holder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {}
/**
* custom camera tweaks and startPreview()
*/
public void refreshCamera() {
if (holder.getSurface() == null || camera == null) {
// preview surface does not exist, camera not opened created yet
return;
}
Log.i(null, "CameraPreview refreshCamera()");
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = 0;
// specifically for back facing camera
switch (rotation) {
case Surface.ROTATION_0:
degrees = 90;
break;
case Surface.ROTATION_90:
degrees = 0;
break;
case Surface.ROTATION_180:
degrees = 270;
break;
case Surface.ROTATION_270:
degrees = 180;
break;
}
camera.setDisplayOrientation(degrees);
setCamera(camera);
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (Exception e) {
// this error is fixed in the camera Error Callback (Error 100)
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.i(null, "CameraPreview surfaceChanged()");
// if your preview can change or rotate, take care of those events here.
// make sure to stop the preview before resizing or reformatting it.
// do not start the camera if the tab isn't visible
if(activityInterface.getCurrentPage() == 1)
startCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {}
public Camera getCameraInstance() {
Camera camera = Camera.open();
// parameters for camera
Parameters params = camera.getParameters();
params.set("jpeg-quality", 100);
params.set("iso", "auto");
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
params.setPictureFormat(PixelFormat.JPEG);
// set the image dimensions
List<Size> sizes = params.getSupportedPictureSizes();
int max = 0, width = 0, height = 0;
for(Size size : sizes) {
if(max < (size.width*size.height)) {
max = (size.width*size.height);
width = size.width;
height = size.height;
}
}
params.setPictureSize(width, height);
camera.setParameters(params);
// primarily used to fix Error 100
camera.setErrorCallback(new ErrorCallback() {
#Override
public void onError(int error, Camera camera) {
if(error == Camera.CAMERA_ERROR_SERVER_DIED) {
releaseCamera();
startCamera();
}
}
});
return camera;
}
/**
* intitialize a new camera
*/
protected void startCamera() {
if(getCamera() == null)
setCamera(getCameraInstance());
refreshCamera();
}
/**
* release camera so other applications can utilize the camera
*/
protected void releaseCamera() {
// if already null then the camera has already been released before
if (getCamera() != null) {
getCamera().release();
setCamera(null);
}
}
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
public void setCameraId(int cameraId) {
this.cameraId = cameraId;
}
/**
* get the current viewPager page
*/
public interface CameraPreviewActivityInterface {
public int getCurrentPage();
}
}
In my FragmentCamera.java file:
private CameraPreview cameraPreview;
// code...
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// code...
cameraPreview = new CameraPreview(getActivity(), cameraId);
previewLayout.addView(cameraPreview);
// code...
}
// code...
#Override
public void onPause() {
super.onPause();
cameraPreview.releaseCamera();
}
#Override
public void onResume() {
super.onResume();
cameraPreview.startCamera();
}
protected void fragmentVisible() {
onResume();
}
protected void fragmentNotVisible() {
onPause();
}
And the MainActivity.java file (implements CameraPreviewActivityInterface):
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
currentPage = position;
if (currentPage == 1) {
fragmentCamera.fragmentVisible();
} else {
fragmentCamera.fragmentNotVisible();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
#Override
public int getCurrentPage() {
return currentPage;
}
I have a DrawerLayout which contains a FrameLayout and ListView in my app, I have to show the camera in the FrameLayout, I've done that fine (as following code) and the camera works correctly. The problem is when moving from portrait orientation to (right-Landscape orientation or left-landscape orientation), or vice versa, it take the mobile a long time to make changes, the problem does not appear when moving from right-Landscape orientation or left-landscape orientation or vice versa.
How could I make this operation as fast as I can?
public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback{
//This ShowCamera class is a helpful class
private SurfaceHolder holdMe;
private Camera theCamera;
public ShowCamera(Context context,Camera camera) {
super(context);
theCamera = camera;
holdMe = getHolder();
holdMe.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
theCamera.setPreviewDisplay(holder);
theCamera.startPreview();
synchronized (holder) {
}
} catch (Exception e) {}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
holdMe.removeCallback(this);
theCamera.release();
}
}
Now the original class is:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
String[] options = {"op1", "op2", "op3", "op4", "op5"}; //for the DrawerLayout
int[] icons = { 0,R.drawable.hospital,R.drawable.education,R.drawable.police,R.drawable.food}; //for the DrawerLayout
private Camera cameraObject;
private ShowCamera showCamera;
public static Camera getCamIfAvailable(){
Camera cam = null;
try { cam = Camera.open();}
catch (Exception e){}
return cam;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraObject = getCamIfAvailable();
new Thread(new Runnable()
{
int rotation = getWindowManager().getDefaultDisplay().getRotation();
#Override
public void run()
{
switch(rotation){
case 0: // portrait
cameraObject.setDisplayOrientation(90);
break;
case 1: // left Landscape
cameraObject.setDisplayOrientation(0);
break;
case 3: //right Landscape
cameraObject.setDisplayOrientation(180);
break;
}
}
}).start();
showCamera = new ShowCamera(this, cameraObject);
FrameLayout preview = (FrameLayout) findViewById(R.id.content_frame);
preview.addView(showCamera);
//.
//.
//.
//.
//. Here, code for Drawerlayout no problrm
//.
//.
//.
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
.
.
.
.
} // End of the class MainActivity
Also I have put in the manifest file the following as first answer mentioned here:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
Any help will be appreciated.
Camera.open() is an heavy operation for the system. It is only triggered when a configuration change is happening, such as when you rotate your device from landscape to portrait and vice-versa.
When flipping the device (from portrait to reversed portrait, or from landscape to reversed landscape) this doesn't trigger a configuration change, only the screen rendering is flipped and therefore you don't call Camera.open() again.
So, you won't be able to make it faster (even though I recommend you to take a look at the systrace tool to see what's really happening when you rotate your screen).
But, I strongly encourage you to try calling the Camera.open() from a background Thread to avoid freezing the UI.
I have a DrawerLayout which contains a FrameLayout and ListView in my app, I have to show the camera in the FrameLayout, I've done that fine (as following code) and the camera works correctly. The problem is when moving from portrait orientation to (right-Landscape orientation or left-landscape orientation), or vice versa, it take the mobile a long time to make changes, the problem does not appear when moving from right-Landscape orientation or left-landscape orientation or vice versa.
How could I make this operation as fast as I can?
public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback{
//This ShowCamera class is a helpful class
private SurfaceHolder holdMe;
private Camera theCamera;
public ShowCamera(Context context,Camera camera) {
super(context);
theCamera = camera;
holdMe = getHolder();
holdMe.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
theCamera.setPreviewDisplay(holder);
theCamera.startPreview();
synchronized (holder) {
}
} catch (Exception e) {}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
holdMe.removeCallback(this);
theCamera.release();
}
}
Now the original class is:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
String[] options = {"op1", "op2", "op3", "op4", "op5"}; //for the DrawerLayout
int[] icons = { 0,R.drawable.hospital,R.drawable.education,R.drawable.police,R.drawable.food}; //for the DrawerLayout
private Camera cameraObject;
private ShowCamera showCamera;
public static Camera getCamIfAvailable(){
Camera cam = null;
try { cam = Camera.open();}
catch (Exception e){}
return cam;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraObject = getCamIfAvailable();
new Thread(new Runnable()
{
int rotation = getWindowManager().getDefaultDisplay().getRotation();
#Override
public void run()
{
switch(rotation){
case 0: // portrait
cameraObject.setDisplayOrientation(90);
break;
case 1: // left Landscape
cameraObject.setDisplayOrientation(0);
break;
case 3: //right Landscape
cameraObject.setDisplayOrientation(180);
break;
}
}
}).start();
showCamera = new ShowCamera(this, cameraObject);
FrameLayout preview = (FrameLayout) findViewById(R.id.content_frame);
preview.addView(showCamera);
//.
//.
//.
//.
//. Here, code for Drawerlayout no problrm
//.
//.
//.
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
.
.
.
.
} // End of the class MainActivity
Also I have put in the manifest file the following as first answer mentioned here:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
Any help will be appreciated.
Camera.open() is an heavy operation for the system. It is only triggered when a configuration change is happening, such as when you rotate your device from landscape to portrait and vice-versa.
When flipping the device (from portrait to reversed portrait, or from landscape to reversed landscape) this doesn't trigger a configuration change, only the screen rendering is flipped and therefore you don't call Camera.open() again.
So, you won't be able to make it faster (even though I recommend you to take a look at the systrace tool to see what's really happening when you rotate your screen).
But, I strongly encourage you to try calling the Camera.open() from a background Thread to avoid freezing the UI.
In my application I was using a custom SurfaceView to retrieve a picture from the camera, and then a custom View for printing it on screen after drawing additional features over it using a canvas. These two classes were created and added to the layout in the activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
mySurfaceView = new MySurfaceView(this, myView);
setContentView(mySurfaceView);
addContentView(myView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
and then myView was called back from mySurfaceView using the
surfaceChanged and surfaceCreated methods:
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = mCamera.getParameters();
...
mCamera.setParameters(parameters);
mCamera.startPreview();
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try{
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
...
System.arraycopy(data, 0, myView.cameraData, 0, data.length);
myView.invalidate();
}
});
}catch(Exception e){
mCamera.release();
mCamera = null;
}
}
Everything was working fine... until I decided to put all of the above in a Fragment in order to use two different views in the same app. Following a tutorial, I put the two classes in the Fragment instead of the Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
mySurfaceView = new MySurfaceView(this, myView);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mySurfaceView = (MySurfaceView)inflater.inflate(R.layout.camera_view, null);
return mySurfaceView;
}
while the XML layout is:
camera_fragment (I'm not concerning about the other fragment, yet):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- "Fragment A" -->
<fragment
android:id="#+id/camera_frag"
android:name="com.example.mypackage.CameraFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
camera_view:
<?xml version="1.0" encoding="utf-8"?>
<view xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.mypackage.MySurfaceView" >
</view>
With the fragment version of the code I can see the SurfaceView with ease, but I don't seem able to print on screen the features that should be drawn by the View. No error code is reported, but the program seems to never enter the setPreviewCallback, and then the onPreviewFrame method. I don't know if it is because of how I instantiate the classes, or how I declare the layout, or both.