0

I am running into an issue using camera 2 API and surface view. This is for an old embedded system and I HAVE to use surfaceview for reasons I can't explain here.

I found this sample where it is shown how it can be done:

https://android.googlesource.com/platform/frameworks/base/+/ee699a6/tests/Camera2Tests?autodive=0

What I need to start the preview with a delay after "onCreate". The code works without any delay. But if I add a delay the preview never comes on (the surface callback never gets called)

here is a snipped of code that does NOT work:

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

    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
        @Override
        public void run() {
            startCameraExec();
        }
    }, 2000);
}

But This works:

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

my startCameraExec just sets up the background thread and sets up the surface callback

private void startCameraExec() {
    Log.d(TAG, "Starting API2 camera...");
    // Start a background thread to manage camera requests
    mBackgroundThread = new HandlerThread("background");
    mBackgroundThread.start();
    mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    mForegroundHandler = new Handler(getMainLooper());
    mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);

    mSurfaceView = (SurfaceView) findViewById(R.id.mainSurfaceView);
    mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
}

the .xml is pretty simple too:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary"
    android:orientation="vertical">

    <SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mainSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:layout_margin="80dp"
        android:onClick="onClickOnSurfaceView" />
</RelativeLayout>

here is what what I think is the problem, this never gets called if the delay the intialization

final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {

... a bunch of code
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // On the first invocation, width and height were automatically set to the view's size
        if (mCameraId == null) {
            // Find the device's back-facing camera and set the destination buffer sizes
            try {
                for (String cameraId : mCameraManager.getCameraIdList()) {
                    CameraCharacteristics cameraCharacteristics =
            ... a bunch of code

any clues how I can go around the issue?

thank you.

gmmo
  • 2,577
  • 3
  • 30
  • 56
  • 1
    You're right; `mSurfaceHolderCallback` isn't added until the surface creation/changing has, in all likelihood, already taken place. So you probably shouldn't expect `onSurfaceChanged()` to be called. That leads us to, "why do you need the delay?" – greeble31 Feb 14 '19 at 02:22
  • This is not normal android app. It is an embedded system, the camera is controlled differently and it can only be started via special JNI commands and it takes much longer than the activity layout inflation. I have to delay the whole thing until the camera is ready. – gmmo Feb 14 '19 at 17:34

2 Answers2

1

You can try to enter the delay after surfaceChanged( { // if (mCameraId == null) {

But you must keep track of all conditions required to obtain and start the camera stream. If may be safer to only delay the call to start preview.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
0

I found a simpler solution. I hid the surface and made it visible only after a delay. That was what I looking for. Thank you for the inputs.

private void startCameraExec() {
    Log.d(TAG, "Starting API2 camera...");

    mSurfaceView = (SurfaceView) findViewById(R.id.mainSurfaceView);

    // This did the trick :)
    mSurfaceView.setVisibility(View.VISIBLE);
    mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
gmmo
  • 2,577
  • 3
  • 30
  • 56