I know that I have to use the class OrientationListener to get the angle from the device. I want to get the angle between -90° and 90°. I don't know how to do it.
picture on the left: 90 degree, picture in the middle: 0 degree and picture on the right: -90 degree
Code
class OrientationListener implements SensorEventListener
{
#Override
public void onSensorChanged(SensorEvent event)
{
angle = Math.round(event.values[2]);
if (angle < 0)
{
angle = angle * -1;
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
You can use this code for simple 0, 90, 180 degrees.
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = display.getRotation();
Surface.ROTATION_0 is 0 degrees, Surface,ROTATION_90 is 90 degrees etc.
You can also use SensorEventListener interface if you want the degrees other than 0, 90, etc:
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float rawX = event.values[0];
}
}
You'd need to get use this code to get the degrees:
double k = 90/9.8;
double degrees = rawX * k; // this is a rough estimate of degrees, converted from gravity
This is a working example.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
setContentView(tv);
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int rotation = display.getRotation();
String rotString="";
switch(rotation) {
case Surface.ROTATION_0:
rotString="portrait";
break;
case Surface.ROTATION_90:
rotString="landscape left";
break;
case Surface.ROTATION_180:
rotString="flipped portrait";
break;
case Surface.ROTATION_270:
rotString="landscape right";
break;
}
tv.setText(rotString);
}
This is an old question, but there is an OrientationEventListener() I found while trying to figure out the rotation for a camera in degrees.
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
The answers here actually help me as I am not capturing the onConfigurationChanged() as discussed in the Handling Runtime Changes Yourself topic in the developer guide.
I am simply going to use the display.getRotation() method presented by Elduderino here in onSurfaceCreated() of MyActivity to set the rotation of the camera appropriately. This will work as the surface gets recreated by default whenever the device orientation changes.
Related
This is an issue that has plagued me for MONTHS. I've seen all the SO posts there are about rotating an image chosen from the gallery or taken via image capture intent, but none have worked. The big offender is, of course, Samsung devices, but I've even seen some funky behavior on my Nexus.
I'm using intents to choose images from gallery and camera, but it seems that landscape photos always seem to come in rotated 90 degrees. The first step is always ExifInterface, something like this:
ExifInterface exif = new ExifInterface(imageUri.getLastPathSegment();
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationNeeded = getRotationFromExifData(orientation);
Matrix matrix = new Matrix();
matrix.setRotate(rotationNeeded);
Where getRotationFromExifData(orientation) is:
private static int getRotationFromExifData(int orientation) {
Log.d(LOG_TAG, "Orientation: " + orientation);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
Log.d(LOG_TAG, "Exif returned 90");
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
Log.d(LOG_TAG, "Exif returned 180");
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
Log.d(LOG_TAG, "Exif returned 270");
return 270;
default: // Normal or 0
Log.d(LOG_TAG, "Exif returned 0");
return 0;
}
}
This doesn't work, ExifInterface (from what I'm seeing) always returns 0 (or normal), especially on Samsung devices.
Other steps include querying the MediaStore and other junk that doesn't work. Can somebody please tell me what the exact way to get proper image rotation using all native Intents, so all images are displayed correctly? Thanks in advance.
Not sure about the photos selected from gallery but for that taken directly from camera, you can try this:
In your activity/fragment to capture a photo, try adding and enabling an OrientationEventListener in onResume(), and disabling it in onPause().
Here is the onResume()
#Override
public void onResume() {
super.onResume();
orientationListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
#Override
public void onOrientationChanged(int angle) {
if (angle > 315 || angle <= 45) {
rotation = 90;
} else if (angle > 45 && angle <= 135) {
rotation = 180;
} else if (angle > 135 && angle <= 225) {
rotation = 270;
} else if (angle > 225 && angle <= 315) {
rotation = 0;
} else {
rotation = -1;// UNKNOWN
}
if (currentFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (360 - rotation) % 360;
}
Log.i("Orientation", "rotation = " + rotation);
}
};
if (orientationListener.canDetectOrientation()) {
orientationListener.enable();
}
}
Here is the onPause()
#Override
public void onPause() {
//...
orientationListener.disable();
super.onPause();
}
When you take the photo using your camera, use that rotation to rotate the bitmap accordingly, as following:
camera.takePicture(null, null, null, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap theBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (rotation != -1) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
theBitmap = Bitmap.createBitmap(theBitmap, 0, 0, theBitmap.getWidth(), theBitmap.getHeight(), matrix, false);
}
// Save the bitmap here...
}
}
Hope this helps.
So after a while of messing with the camera, I've finally got the actual camera orientation working with this:
private 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; 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;
}
camera.setDisplayOrientation(result);
}
However, the status bar (the thing at the top with time and network info) is still in landscape.
I've already included this:
android:screenOrientation="portrait"
in my AndroidManifest.xml
Any ideas on how to fix this?
If you know what you want to set your orientation as you can use setRequestedOrientation(int requestedOrientation) in your Activity
This is my camera Activity which is in Portrait mode. I am rotating the device and the camera is rotating with it.
This is my second Activity where my image is displaying on the ImageView upside down, received from PictureCallback(). I already tried ExifInterface but its returning orientation 0.
I had a similar Problem. Orientation 0 in ExifInterface means undefined. If that occurs i ask the MediaStore and in my case it always returns the correct orientation if ExifInterface returns 0.
String[] cols = { MediaStore.Images.Media.ORIENTATION };
Cursor cur = context.getContentResolver().query(uri, cols, null, null, null);
int orientation = 0;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(MediaStore.Images.Media.ORIENTATION));
}
Setting for camera:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
try {
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;
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;
}
camera.setDisplayOrientation(result);
} catch (Exception e) {
// TODO: handle exception
}
}
And use ExifInterface when display result
When i am in landscape, if it's at 0degrees, it captures a good video, but if i turn the phone over 180 degrees, it will record upside down, how can i change this?
When i start recording i do this code:
myMediaRecorder.setPreviewDisplay(mySurfaceHolder.getSurface());
if (rotationInDegreeValue == 90) {
LogService.log(TAG, "set orientation hint : " + 0);
myMediaRecorder.setOrientationHint(0);
} else if (rotationInDegreeValue == 270) {
LogService.log(TAG, "set orientation hint : " + 180);// 180
myMediaRecorder.setOrientationHint(180);
}
myMediaRecorder.prepare();
myMediaRecorder.start();
Then, i have an orientation listener:
orientationListener = new OrientationEventListener(getActivity(), SensorManager.SENSOR_DELAY_UI) {
#Override
public void onOrientationChanged(int orientation) {
LogService.log(TAG, "onOrientationChanged");
if ((myCamera == null)) {
return;
}
Log.d(TAG, "orientation changed : " + orientation);
if (((orientation < 45) || (orientation > 315) || ((orientation < 225) && (orientation > 135))) && !isRecording) {
if (!isAlertShown && !isUserListDisplayed) {
// AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
// alertDialogBuilder.setTitle("Orientation").setMessage("Return to landscape").setCancelable(false);
// orientationAlert = alertDialogBuilder.create();
// orientationAlert.show();
isAlertShown = true;
}
} else {
if (isAlertShown) {
// orientationAlert.hide();
// orientationAlert.dismiss();
isAlertShown = false;
}
}
rotateCamera();
}
};
This is the RotateCamera Function:
private void rotateCamera() {
LogService.log(TAG, "rotateCamera()");
int cameraId = CameraInfo.CAMERA_FACING_BACK;
if (isUsingBackCam) {
cameraId = CameraInfo.CAMERA_FACING_FRONT;
}
android.hardware.Camera.CameraInfo myCameraInfo = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, myCameraInfo);
Display display;
display = getActivity().getWindow().getWindowManager().getDefaultDisplay();
int rotation = display.getRotation();
int degrees = 0;
Point size = new Point();
display.getSize(size);
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
rotationInDegreeValue = 0;
SCREEN_HEIGHT = size.x;
break;
case Surface.ROTATION_90:
degrees = 90;
rotationInDegreeValue = 90;
SCREEN_HEIGHT = size.y;
break;
case Surface.ROTATION_180:
degrees = 180;
rotationInDegreeValue = 180;
break;
case Surface.ROTATION_270:
rotationInDegreeValue = 270;
degrees = 270;
SCREEN_HEIGHT = size.y;
break;
}
int result;
if (myCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (myCameraInfo.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = ((myCameraInfo.orientation - degrees) + 360) % 360;
}
if (!isRecording) {
try {
myCamera.setDisplayOrientation(result);
} catch (Exception e) {
LogService.err(TAG, e.getMessage(), e, 1);
}
}
}
What do i have to do, to stop the camera from recording upside down, when i turn the phone 180 degrees. I tried to comment out the orientation listener, but still no luck.
Also, i do not know if it is important of not, but this happens in a fragment. The Activity of the fragment, does not have onconfigurationchanged set.
The setOrientationHint function worked, but i had to append more videos, and when this was happening, the composition matrix of the videos was getting lost.
I have changed in the manifest, from SensorLandscape to Landscape, and this is how i solved this issue.
I need to implement an OrientationEventListener to get the camera working correctly. Google posted a sample implementation of onOrientationChanged that looks like this:
#Override
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
But I'm building against API level 8, so I don't have CameraInfo. How can I accomplish a similar thing as the above without CameraInfo?
Although the orientation changes, I find I have to also change the camera preview to match, if you want full-screen images on rotation, so I use a similar method but in the onLayout() method of a camera surface view like so:
/*
* This class provides the surface for the camera.
*/
public class CameraSurfaceView extends ViewGroup implements SurfaceHolder.Callback
{
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
if (changed)
{
final int width = right - left;
final int height = bottom - top;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null)
{
Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation())
{
case Surface.ROTATION_0:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
break;
case Surface.ROTATION_180:
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
break;
case Surface.ROTATION_270:
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
mCamera.setDisplayOrientation(180);
break;
}
}
final int scaledChildHeight = previewHeight * width / previewWidth;
cameraView.layout(0, height - scaledChildHeight, width, height);
}
}
}
This has worked for me on an HTC Desire using Android API 8 (Android 2.2).
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
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;
}
parameters.setRotation(degrees );
mcamera.setParameters(parameters);
}
Hope this helps.
EDIT :
Refer the Camera app source code to know how they handled it. This link is to the latest source. Can go back in revisions and see for 2.2 version.
Camera source
EDIT : Here is the link to one of those revisions nearby 2.2 release. Search onOrientationChanged in this file: Camera src