9

I have a custom camera application. When I rotating the phone by 90, camera preview works fine. But when I rotate phone quickly 180 degree, camera preview turns upside down. Is there any solution...

Here is my code below:

public class CustomCameraActivity extends Activity implements
    SurfaceHolder.Callback {

Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;
LayoutInflater controlInflater = null;
private Sensor mOrientaion1;
int cameraId = 0;
public final String TAG = "CustomCamera";
private SensorManager sensorManager;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.main);

    context = this;

    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mOrientaion1 = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

    // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    imageView = (ImageView) findViewById(R.id.imgError);

    getWindow().setFormat(PixelFormat.UNKNOWN);
    surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    controlInflater = LayoutInflater.from(getBaseContext());
    View viewControl = controlInflater.inflate(R.layout.custom, null);
    LayoutParams layoutParamsControl = new LayoutParams(
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

    Button btn1 = (Button) viewControl.findViewById(R.id.Button01);
    Button btn2 = (Button) viewControl.findViewById(R.id.Button02);

    btn1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // Toast.makeText(context, "1111111111111111111111111",
            // Toast.LENGTH_SHORT).show();
            camera.takePicture(null, null, mPicture);

            Constant.rotationValueForCamera = Constant.rotationValue;
        }
    });

    btn2.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // Toast.makeText(context, "22222222222222222222222222",
            // Toast.LENGTH_SHORT).show();
            Log.e("0 imagePickerStatus", Constant.imagePickerStatus + "");

            Constant.imagePickerStatus = 0;

            Log.e("0 imagePickerStatus", Constant.imagePickerStatus + "");

            finish();
        }
    });

    this.addContentView(viewControl, layoutParamsControl);

    int ot = getResources().getConfiguration().orientation;

    if (Configuration.ORIENTATION_LANDSCAPE == ot) {
        imageView.setVisibility(View.GONE);
        Log.e("ori1111", "land");
    } else {
        imageView.setVisibility(View.VISIBLE);
        Log.e("ori111", "port");
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        // Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
        findViewById(R.id.Button01).setVisibility(View.VISIBLE);
        findViewById(R.id.Button02).setVisibility(View.VISIBLE);
        imageView.setVisibility(View.GONE);
        Log.e("ori", "land");
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        // Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
        findViewById(R.id.Button01).setVisibility(View.INVISIBLE);
        findViewById(R.id.Button02).setVisibility(View.INVISIBLE);
        imageView.setVisibility(View.VISIBLE);
        Log.e("ori", "port");
    }
}

public String getPollDeviceAttitude() {

    return Constant.rotationValueForCamera;
}

private SensorEventListener sensorEventListener = new SensorEventListener() {

    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
};

protected void onPause() {
    super.onPause();

    sensorManager.unregisterListener(sensorEventListener);

}

@Override
public void onResume() {
    super.onResume();

    sensorManager.registerListener(sensorEventListener,
            sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
            SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(sensorEventListener,
            sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
            SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(sensorEventListener,
            sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
            SensorManager.SENSOR_DELAY_NORMAL);

    if (Constant.isCapturedOk) {
        Constant.isCapturedOk = false;

        finish();
    }

}

PictureCallback mPicture = new PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        Log.e("Camrera", "22222222222222222");
        BitmapFactory.Options bfo = new BitmapFactory.Options();
        bfo.inDither = false;
        // bfo.inJustDecodeBounds = true;
        bfo.inPurgeable = true;
        bfo.inTempStorage = new byte[16 * 1024];

        Intent intent = new Intent(context, PreviewActivity.class);
        // intent.putExtra("data", data);
        Bitmap bitmapPicture = BitmapFactory.decodeByteArray(data, 0,
                data.length, bfo);
        Matrix matrix = new Matrix();
        if (Constant.result == 180) {
            matrix.postRotate(270);
        }
        if (Constant.result == 270) {
            matrix.postRotate(180);
        }
        int height = bitmapPicture.getHeight();
        int width = bitmapPicture.getWidth();
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmapPicture,
                height, width, true);
        Bitmap rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
                true);
        ByteArrayOutputStream blob = new ByteArrayOutputStream();
        Log.e("Camrera1", "22222222222222222");
        rotatedBitmap.compress(CompressFormat.JPEG,
                50 /* ignored for PNG */, blob);
        byte[] bitmapdata = blob.toByteArray();
        Constant.imageData = bitmapdata;
        Log.e("Camrera2", "22222222222222222");
        startActivity(intent);

    }
};
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    if (previewing) {
        camera.stopPreview();
        previewing = false;
    }

    if (camera != null) {
        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
            setCameraDisplayOrientation(this, cameraId, camera);
            previewing = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static void setCameraDisplayOrientation(Activity activity,
        int cameraId, android.hardware.Camera camera) {
    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(cameraId, info);
    int rotation = activity.getWindowManager().getDefaultDisplay()
            .getRotation();
    int degrees = 0;
    switch (rotation) {
    case Surface.ROTATION_0:
        degrees = 0;
        Constant.result = 0;
        break;
    case Surface.ROTATION_90:
        degrees = 90;
        Constant.result = 90;
        break;
    case Surface.ROTATION_180:
        degrees = 180;
        Constant.result = 180;
        break;
    case Surface.ROTATION_270:
        degrees = 270;
        Constant.result = 270;
        break;
    }

    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        result = (info.orientation + degrees) % 360;
        result = (360 - result) % 360; // compensate the mirror
    } else { // back-facing
        result = (info.orientation - degrees + 360) % 360;
    }
    camera.setDisplayOrientation(result);
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    camera = Camera.open();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    camera.stopPreview();
    camera.release();
    camera = null;
    previewing = false;
}

@Override
protected void onStop() {
    super.onStop();

    Log.e("Tab", "Stoping");
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    if (keyCode == KeyEvent.KEYCODE_BACK) {

        return true;

    }
    return super.onKeyDown(keyCode, event);

}

}

App crashes image

Mohammad Rajob
  • 743
  • 1
  • 11
  • 29
  • solution: don't do that. it's a hardware issue. – Nikola Oct 23 '13 at 04:14
  • @Nikola, so there is no solution for this problem? – Mohammad Rajob Oct 23 '13 at 04:30
  • 1
    maybe, i just don't think it has anything to do with your code. – Nikola Oct 23 '13 at 04:31
  • Check this thread: http://stackoverflow.com/questions/12059447/screen-orientation-landscape-upside-down-why – Alex Cohn Oct 23 '13 at 05:24
  • @AlexCohn, Thank you for your response. But it's not working for me. – Mohammad Rajob Oct 23 '13 at 06:00
  • possible duplicate of [Camera rotated directly and fast](http://stackoverflow.com/questions/18976859/camera-rotated-directly-and-fast) – Alex Cohn Oct 23 '13 at 07:11
  • Do you even receive the `surfaceChanged()` callback when you quickly rotate from landscape to landscape? – Alex Cohn Oct 23 '13 at 07:17
  • @AlexCohn, i don't know. – Mohammad Rajob Oct 23 '13 at 07:34
  • Please add a log message there. I suspect that your phone simply ignores the fast rotation and does not restart the surface. If that's what is happening, you must check the orientation sensor yourself, and restart, and not rely on `surfaceChanged()`. – Alex Cohn Oct 23 '13 at 08:01
  • @AlexCohn, It can not receive the surfaceChange() callback when you quickly rotate from landscape to landscape. Now what can i do. Please Help me... – Mohammad Rajob Oct 23 '13 at 08:35
  • @AlexCohn, please help me. Your Assumption is right. Now how can I solve this problem? – Mohammad Rajob Oct 23 '13 at 09:04
  • If you slowly put the phone (landscape) flat on the table, then slowly pick it up reverse landscape, does you surface rotate correctly? – Alex Cohn Oct 23 '13 at 10:37
  • Open calculator, show it in landscape mode, quickly rotate it to reverse landscape. Does the screen show upside down? – Alex Cohn Oct 23 '13 at 10:39
  • @AlexCohn,If I slowly put the phone (landscape) flat on the table, then slowly pick it up reverse landscape, surface not rotate correctly. – Mohammad Rajob Oct 24 '13 at 04:05
  • @AlexCohn, I opened calculator, saw it in landscape mode, then quickly rotate it to reverse landscape, the screen not upside down. It was correct. – Mohammad Rajob Oct 24 '13 at 04:09
  • @AlexCohn, I am waiting for your answer brother. – Mohammad Rajob Oct 24 '13 at 05:40
  • Yes, I reduced your app to minimum, and I too see that 180° rotation does not trigger the expected event. Digging. – Alex Cohn Oct 24 '13 at 16:51
  • So @AlexCohn, is there any solution? Please help me if there is any solution, because it is very important to me. Thanks for spending your valueable time. I will still waiting for your answer. – Mohammad Rajob Oct 25 '13 at 04:12
  • See http://stackoverflow.com/questions/4843809/how-do-i-detect-screen-rotation. – Alex Cohn Oct 25 '13 at 21:02
  • See also *[How to detect screen rotation through 180 degrees from landscape to landscape orientation?](http://stackoverflow.com/questions/9909037)*, which discusses teh broader question, including case when the orientation is changed programmatically. – Alex Cohn May 16 '16 at 07:09

2 Answers2

13

You can use OrientationEventListener to trigger recalculation of camera rotation.

Add to your activity:

private OrientationEventListener orientationListener = null;

to onCreate():

orientationListener = new OrientationEventListener(this) {
    public void onOrientationChanged(int orientation) {
        setCameraDisplayOrientation(CustomCameraActivity.this, cameraId, camera);
    }
};

to surfaceCreated():

orientationListener.enable();

to surfaceDestroyed():

orientationListener.disable();

Now, it almost works. To make setCameraDisplayOrientation() more robust,

  1. add check for camera != null
  2. only call camera.setDisplayOrientation(result) (or perform any heavy-lifting) if result changed since last time the function was called.
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • 1
    Thanks a lot. I am speechless for your help. It's work fine now. – Mohammad Rajob Oct 28 '13 at 04:34
  • 1
    I don't like this solution. System restarts your activity and camera output is interrupted. I prefer to set fixed landscape activity orientation, and only manipulate the UI to similulate layout rotation (that's how the stock Camera app is written) – Alex Cohn Oct 28 '13 at 04:55
  • Just to add: I had to do 'orientationListener.disable();' onPause() since onDestroy is called quite some ms later (and if you press power it wont get called at all). So the bug I was getting is: rotation 90 -> home button -> rotate to 0 -> back to app -> wrong rotation – Patrick Nov 02 '13 at 22:11
  • @for3st: note that the example uses `SurfaceHolder.Callback.surfaceDestroyed()` and not `Activity.onDestroy()`. – Alex Cohn Nov 03 '13 at 13:22
  • @AlexCohn yes I get that and did it in the SurfaceHolder Callback not the acitivty/fragment (sorry that was not very clear). The problem with `SurfaceHolder.Callback.surfaceDestroyed()` it does not seem to be synchronized to any onPause/onStop/etc. so in my experiments it was called when the activty was already gone and I was in the launcher. Also if you press the power-button for any reason `SurfaceHolder.Callback.surfaceDestroyed()` won't be called at all. – Patrick Nov 03 '13 at 13:59
  • @for3st: It's OK to keep the camera running with black screen (after press power-button), if you still need it (for video processing or recording). But yes, if you don't use it, it is better to release it onPause() to preserve battery. – Alex Cohn Nov 03 '13 at 14:08
  • @AlexCohn the problem is, I cannot rely on `SurfaceHolder.Callback.surfaceDestroyed()` so any resouce cleaning has to be done onPause() or similar in the fragment and thus I had to do `orientationListener.disable()` in onPause() – Patrick Nov 03 '13 at 14:12
  • @AlexCohn one thing to mind is, that this will get called not only on rotation change but on every degree that changes even in the same rotation-type – Patrick Nov 04 '13 at 13:28
  • @for3st: that's why I advised **2** to only call `setDisplayOrientation()` (or do any heavy-lifting at all) only if `result` has changed since last time. – Alex Cohn Nov 04 '13 at 14:52
  • @AlexCohn the problem is, that on some devices when you press home and come back the roation is the same but somehow the preview reverts to default rotation, so it wont get rotated - fixable with a force rotation onResume(), but just sayin ;) – Patrick Nov 04 '13 at 16:10
  • @for3st: sure, you must set `savedResult=0` in onPause – Alex Cohn Nov 04 '13 at 18:18
  • @AlexCohn, i got an error with this, some time after capturing application crashes. I added a image of logcat when crash. plz check. – Mohammad Rajob Nov 14 '13 at 09:37
  • I don't know what you have at line 512, but there is some **null** hidden there. – Alex Cohn Nov 14 '13 at 14:03
1

android:configChanges="keyboardHidden|orientation|screenSize"

Add this line in your Android Manifest file after declaring all activities in activity tags *

like:

<activity android:name="com.geeklabs.ActivityMain"
            android:configChanges="keyboardHidden|orientation|screenSize" />

May be it will helps you.

Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138