I need to know when my Android device screen is rotated from one landscape to another (rotation_90 to rotation_270).
In my Android service, I reimplemented onConfigurationChanged(Configuration newConfig) to be aware of the rotation of the device. But this method is only called by the system if the device is rotated from ORIENTATION_PORTRAIT to ORIENTATION_LANDSCAPE, and not if it is rotated from ORIENTATION_LANDSCAPE (90°) to the other ORIENTATION_LANDSCAPE (270°) !!
How can I be called in this case?
Thanks.
You can enable an OrientationEventListener to your activity.
OrientationEventListener mOrientationListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
#Override
public void onOrientationChanged(int orientation) {
Log.v(TAG, "Orientation changed to " + orientation);
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
return;
}
int degrees = -1;
if (orientation < 45 || orientation > 315) {
Log.i(TAG, "Portrait");
} else if (orientation < 135) {
degrees = 90;
Log.i(TAG, "Landscape"); // This can be reverse landscape
} else if (orientation < 225) {
degrees = 180;
Log.i(TAG, "Reverse Portrait");
} else {
degrees = 270;
Log.i(TAG, "Reverse Landscape"); // This can be landscape
}
}
};
if (mOrientationListener.canDetectOrientation() == true) {
Log.v(TAG, "Can detect orientation");
mOrientationListener.enable();
} else {
Log.v(TAG, "Cannot detect orientation");
mOrientationListener.disable();
}
You can save previous orientation as int member variable by using this code:
int oldRotation = getWindowManager().getDefaultDisplay().getRotation();
And then check if the device was rotated from one landscape mode to another.
if(rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
int newRotation = getWindowManager().getDefaultDisplay().getRotation();
if(newRotation != oldRotation) {
// rotation from 90 to 270, or from 270 to 90
}
oldRotation = newRotation;
}
On iOS, device orientation can be different from interface orientation, so we have two different enums. I'm not necessarily looking for enums. Does Android make the same distinction? I want to detect interface orientation changes rather than device.
People seem to be using onConfigurationChanged() to detect orientation changes, but it wasn't clear to me exactly what kind of orientation change this is.
this methods can detect (and) set orientation:
getResources().getConfiguration().orientation
and
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
I'm using those methods to catch all orientations:
inside onCreate:
initOrientation();
where
private void initOrientation() {
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mLastRotation = mWindowManager.getDefaultDisplay().getRotation();
myOrientationEventListener
= new OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI){
#Override
public void onOrientationChanged(int orientation) {
// Log.d(TAG, "ORIENTATION: " + orientation);
Display display = mWindowManager.getDefaultDisplay();
int rotation = display.getRotation();
if (((rotation == Surface.ROTATION_90 && mLastRotation == Surface.ROTATION_270)
|| (rotation == Surface.ROTATION_270 && mLastRotation == Surface.ROTATION_90)
|| (rotation == Surface.ROTATION_0 && mLastRotation == Surface.ROTATION_180)
|| (rotation == Surface.ROTATION_180 && mLastRotation == Surface.ROTATION_0))) {
//if ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && rotation != mLastRotation) {
Log.i(TAG, "changed >>> " + rotation + " :: " + _.mWidth);
// do something
mLastRotation = rotation;
}
}
};
if (myOrientationEventListener.canDetectOrientation()){
Toast.makeText(this, "Can DetectOrientation", Toast.LENGTH_LONG).show();
myOrientationEventListener.enable();
}
else{
Toast.makeText(this, "Can't DetectOrientation", Toast.LENGTH_LONG).show();
// finish();
}
}
it depends on what your really want to realize. the method above can detect portrait>portrait and landscape>landscape shifts.
In order to force lock and release rotation I'm using this approach:
protected void mLockScreenRotation(int i)
{
// Stop the screen orientation changing during an event
switch (i)
{
default:
case 0:
switch (this.getResources().getConfiguration().orientation)
{
case Configuration.ORIENTATION_PORTRAIT:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
case Configuration.ORIENTATION_LANDSCAPE:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
break;
}
case 1:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
case 2:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
break;
}
}
mLockScreenRotation(0) - locks
My application uses camera. To display the camera's preview the way the right way I must account for activity orientation relative to the physical device orientation. I. e. if the activity orientation is locked and never changes, I need not take any further steps - as the device rotates, preview image will rotate accordingly. However, imagine my activity is allowed to change orientation. You rotate the device - and preview - until you reach portrait mode (assuming it was landscape originally), at which point activity rotates to accommodate the new orientation. But preview image rotates with it, and now it's out of sync with the camera and surrounding reality. What I must do is determine activity orientation and rotate the image accordingly.
It seems that Display.getRotation() can be used for that. But apparently, it cannot: https://groups.google.com/forum/#!topic/android-developers/ij_0QbApKKc
The problem is that the point of origin is not fixed by Android API. Some tablets return rotation of 0 in normal orientation (landscape, volume buttons up), and some others (like my Nexus 7 2013) return 1.
How can I solve this problem?
You can determinate orientation using OrientationEventListener Something just like this
mOrientationEventListener = new OrientationEventListener(context, SensorManager.SENSOR_DELAY_NORMAL) {
#Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getOrientation() == Surface.ROTATION_0) { // landscape oriented devices
isLandscapeOriented = true;
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
}
};
}
if (mOrientationEventListener.canDetectOrientation()) {
mOrientationEventListener.enable();
}
Don`t forget to call mOrientationEventListener.disable();
EDIT:
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 result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
I have some problem with screen orientation. Basically what I am trying to do is to determine exact screen orientation (including reverse landscape and reverse portrait). I wrote method below to do it for me and it seems to work perfectly on my Transformer however when I start same code on emulator some things are messed.
Basically what is happening is that whenever in emulator I switch to landscape (ROTATION_90) according to documentation it is supposed to be reverse landscape (and for example on Transformer with ROTATION_90 device is in reverse portrait as Android documentation describes). Unfortunately on emulator for some reason it seems to be normal landscape mode.
So my question is this code below correct ir problem lies in it. Or perhaps I am not taking into account some other parameters (like emulator has barely accelerometer enabled for instance).
public static int getDeviceCurrentOrientation() {
WindowManager lWindowManager = (WindowManager) getContext()
.getSystemService(Activity.WINDOW_SERVICE);
Configuration cfg = getContext().getResources().getConfiguration();
int lRotation = lWindowManager.getDefaultDisplay().getRotation();
int rotation1;
int orientation;
rotation1 = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
if (cfg.orientation == Configuration.ORIENTATION_LANDSCAPE)
rotation1 = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
else if (cfg.orientation == Configuration.ORIENTATION_PORTRAIT)
rotation1 = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
else
rotation1 = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
switch (lRotation) {
case Surface.ROTATION_0:
orientation = 0;
break;
case Surface.ROTATION_90:
orientation = 1;
break;
case Surface.ROTATION_180:
orientation = 2;
break;
case Surface.ROTATION_270:
orientation = 3;
break;
default:
orientation = -1;
}
if ((orientation == 0)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE))
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
if ((orientation == 0)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT))
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if ((orientation == 1)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT))
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
if ((orientation == 1)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE))
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
if ((orientation == 2)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT))
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
if ((orientation == 2)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE))
return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
if ((orientation == 3)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT))
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if ((orientation == 3)
&& (rotation1 == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE))
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
I had similar problem and after hours of crunching......
I found this nice solution >>
Display display = getWindowManager().getDefaultDisplay();
int rotation = display.getRotation();
Point size = new Point();
display.getSize(size);
int lock = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if (rotation == Surface.ROTATION_0
|| rotation == Surface.ROTATION_180) {
// if rotation is 0 or 180 and width is greater than height, we have
// a tablet
if (size.x > size.y) {
if (rotation == Surface.ROTATION_0) {
lock = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
lock = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
} else {
// we have a phone
if (rotation == Surface.ROTATION_0) {
lock = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else {
lock = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
}
}
} else {
// if rotation is 90 or 270 and width is greater than height, we
// have a phone
if (size.x > size.y) {
if (rotation == Surface.ROTATION_90) {
lock = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
lock = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
} else {
// we have a tablet
if (rotation == Surface.ROTATION_90) {
lock = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
} else {
lock = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
}
}
Ok so I have a class that extends SurfaceView and overrides
surfaceChanged - just calls startPreview
surfaceCreated - opens camera, edits params *, sets surfaceHolder
surfaceDestroyed - calls stopPreview, release camera
this all work great because when the orientation is Portrait:
from surfaceCreated *
m_camera = Camera.open();
Camera.Parameters p = m_camera.getParameters();
if (getResources().getConfiguration().orientation !=
Configuration.ORIENTATION_LANDSCAPE)
{
p.set("orientation", "portrait");
// CameraApi is a wrapper to check for backwards compatibility
if (CameraApi.isSetRotationSupported())
{
CameraApi.setRotation(p, 90);
}
}
However, everytime the orientation changes it calls Camera.open()... which as you may know is quite an expensive operation, causing the transitions to be not so smooth.
When i force the orientation to landscape, the preview is great. Create only gets called once which works because the preview is in landscape the camera is always what the user sees. However, I need a way to set the orientation of the actual picture taken when in portrait. When I force landscape though, the surface never gets recreated and the parameters are never set when the camera is held in portrait.
So how can I do one of the following (exclusively)?
Hold onto m_camera between onDestroy and onCreate when orientation changes so that the transition is smooth
Force landscape and detect orientation changes another way... rotating the final snaped picture if held in portrait.
Also, if I am off base can someone point me in a better direction? Thank you.
The way I implemented it:
private Camera mCamera;
private OrientationEventListener mOrientationEventListener;
private int mOrientation = -1;
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// force Landscape layout
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR | ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
/*
Your other initialization code here
*/
}
#Override
protected void onResume() {
super.onResume();
if (mOrientationEventListener == null) {
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
#Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
}
else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
}
else { // orientation <135 && orientation > 45
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
if (lastOrientation != mOrientation) {
changeRotation(mOrientation, lastOrientation);
}
}
};
}
if (mOrientationEventListener.canDetectOrientation()) {
mOrientationEventListener.enable();
}
}
#Override protected void onPause() {
super.onPause();
mOrientationEventListener.disable();
}
/**
* Performs required action to accommodate new orientation
* #param orientation
* #param lastOrientation
*/
private void changeRotation(int orientation, int lastOrientation) {
switch (orientation) {
case ORIENTATION_PORTRAIT_NORMAL:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 270));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 270));
Log.v("CameraActivity", "Orientation = 90");
break;
case ORIENTATION_LANDSCAPE_NORMAL:
mSnapButton.setImageResource(android.R.drawable.ic_menu_camera);
mBackButton.setImageResource(android.R.drawable.ic_menu_revert);
Log.v("CameraActivity", "Orientation = 0");
break;
case ORIENTATION_PORTRAIT_INVERTED:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 90));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 90));
Log.v("CameraActivity", "Orientation = 270");
break;
case ORIENTATION_LANDSCAPE_INVERTED:
mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 180));
mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 180));
Log.v("CameraActivity", "Orientation = 180");
break;
}
}
/**
* Rotates given Drawable
* #param drawableId Drawable Id to rotate
* #param degrees Rotate drawable by Degrees
* #return Rotated Drawable
*/
private Drawable getRotatedImage(int drawableId, int degrees) {
Bitmap original = BitmapFactory.decodeResource(getResources(), drawableId);
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
return new BitmapDrawable(rotated);
}
And then in your PictureCallback set metadata to indicate rotation level:
private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
// Populate image metadata
ContentValues image = new ContentValues();
// additional picture metadata
image.put(Media.DISPLAY_NAME, [picture name]);
image.put(Media.MIME_TYPE, "image/jpg");
image.put(Media.TITLE, [picture title]);
image.put(Media.DESCRIPTION, [picture description]);
image.put(Media.DATE_ADDED, [some time]);
image.put(Media.DATE_TAKEN, [some time]);
image.put(Media.DATE_MODIFIED, [some time]);
// do not rotate image, just put rotation info in
switch (mOrientation) {
case ORIENTATION_PORTRAIT_NORMAL:
image.put(Media.ORIENTATION, 90);
break;
case ORIENTATION_LANDSCAPE_NORMAL:
image.put(Media.ORIENTATION, 0);
break;
case ORIENTATION_PORTRAIT_INVERTED:
image.put(Media.ORIENTATION, 270);
break;
case ORIENTATION_LANDSCAPE_INVERTED:
image.put(Media.ORIENTATION, 180);
break;
}
// store the picture
Uri uri = getContentResolver().insert(
Media.EXTERNAL_CONTENT_URI, image);
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
OutputStream out = getContentResolver().openOutputStream(
uri);
boolean success = bitmap.compress(
Bitmap.CompressFormat.JPEG, 75, out);
out.close();
if (!success) {
finish(); // image output failed without any error,
// silently finish
}
} catch (Exception e) {
e.printStackTrace();
// handle exceptions
}
mResultIntent = new Intent();
mResultIntent.setData(uri);
} catch (Exception e) {
e.printStackTrace();
}
finish();
}
};
I hope it helps.
UPDATE Now when landscape based devices are appearing an additional check for it is required in OrientationEventListener.
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getOrientation() == Surface.ROTATION_0) {
// landscape oriented devices
} else {
// portrait oriented device
}
Full code (a bit wasteful by LC, but easily demonstrates the approach)
#Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getOrientation() == Surface.ROTATION_0) { // landscape oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
if (lastOrientation != mOrientation) {
changeRotation(mOrientation, lastOrientation);
}
}
Have you considered using the standard method thats provided in the API doc, which you can call on surfaceChanged? You could store the degrees in a global variable to later use when saving the picture. Also could do a simple null checker on your camera variable, so you don't create it again in surfaceCreated.
public void setCameraDisplayOrientation()
{
if (mCamera == null)
{
Log.d(TAG,"setCameraDisplayOrientation - camera null");
return;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(CAM_ID, info);
WindowManager winManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
int rotation = winManager.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation)
{
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 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;
}
mCamera.setDisplayOrientation(result);
}
As you've seen from the other answers, this code gets very complicated. You may want to investigate using a library to help you provide this feature, for example, CWAC-Camera supports OS 2.3 and up (hopefully you can drop OS 2.1 and OS 2.2 support now):
https://github.com/commonsguy/cwac-camera
CWAC-Camera supports locking the camera preview to landscape, and will auto-rotate images into the correction orientation for you. Browse the project issues if you want a taste of all the device specific problems that need to be solved, which IMO are more reasons for trying to use a library instead of maintaining all this code and testing yourself.