Nexus 4.
I specially use System.out.println to print out the rotation on LogCat, to observe the value when I rotate my device.
int orientation_photo = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
System.out.println("For Debug: orientation_photo: " + orientation_photo);
The rotation (0, 1, 2 or 4) is not prcise at all. Sometimes I have rotated 90 degrees, but the rotation value does not change.
However, believe Nexus 4 device can detect it correctly, from the orientation performance of its default camera, which always record a correct orientation, so that we can view pictures in a correct way.
I need a correct rotation value, so that I could put in ExifInterface of the photo .jpg file.
Any help?
You are fetching the orientation of the UI, not the orientation of the phone itself. For various reasons they do not always match. In particular, many devices will never rotate their UI 180 degrees.
You probably want to look at the SensorManager class: http://developer.android.com/reference/android/hardware/SensorManager.html
I think I find the answer, that is: Yes, it is not precise, from the basic physical principle, because the orientation is subjective.
Related
I am trying to measure angle at which my phone is using accelerometer. I refer to the method demonstrated here. But the problem is that when I rotate my phone at a high speed, it skips readings. For example, if I rotate my phone from 0 degrees to 90 degrees within a second, I get readings in logcat as : 0, 50, 90. What I really want is to obtain all the values through which the phone has rotated, like 0,1,2,...,90. Is it possible? If yes, what am I missing? Do I need to use gyroscope/magnetometer as well?
Basically it was the sensor delay which was causing the issue. I resolved it by setting the delay to SensorManager.SENSOR_DELAY_FASTEST.
Jelly Bean 4.3 (API 18) added a couple new screenOrientation values.
http://developer.android.com/reference/android/R.attr.html#screenOrientation
http://developer.android.com/reference/android/content/pm/ActivityInfo.html#SCREEN_ORIENTATION_BEHIND
I suppose first: is there a difference between "orientation" and "rotation"? Or is the documentation just using inconsistent wording?
Then:
unspecified
No preference specified: let the system decide the best orientation. This will either be the orientation selected by the activity below, or the user's preferred orientation if this activity is the bottom of a task. If the user explicitly turned off sensor based orientation through settings sensor based device rotation will be ignored. If not by default sensor based orientation will be taken into account and the orientation will changed based on how the user rotates the device. Corresponds to SCREEN_ORIENTATION_UNSPECIFIED.
user
Use the user's current preferred orientation of the handset. Corresponds to SCREEN_ORIENTATION_USER.
fullUser (New)
Respect the user's sensor-based rotation preference, but if sensor-based rotation is enabled then allow the screen to rotate in all 4 possible directions regardless of what the device will normally do (for example some devices won't normally use 180 degree rotation). Corresponds to SCREEN_ORIENTATION_FULL_USER.
What's the difference? In practice currently, I believe that setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) is the way to tell the activity to rotate based on the sensor, if Rotation is enabled system-wide. So then how is fulluser different?
Likewise,
nosensor
Always ignore orientation determined by orientation sensor: the display will not rotate when the user moves the device. Corresponds to SCREEN_ORIENTATION_NOSENSOR.
locked (New)
Screen is locked to its current rotation, whatever that is. Corresponds to SCREEN_ORIENTATION_LOCKED.
Any difference?
Is there a difference between "orientation" and "rotation"? Or is the
documentation just using inconsistent wording?
Even though you see Orientation and Rotation as synonyms(as do most I think, including me), the differences lie in their respective definition. Where Orientation affords you two choices, Rotation gives you four. What will the extra two choices be used for? That will depend on you.
Say you come up with a convenience app which includes an alarm clock, a calculator, a weather informer and a currency converter. You can assign a different rotation to each of these and allow the user to navigate between the four views by rotating the device.
Another (fictional) example can be a homescreen which displays different widget groups based on rotation angle.
I tried some of the screenOrientation options and this is what I found:
fullUser: Stuck to the default rotation of 0 degrees.
user: Allowed rotation values 0, 90 and 270.
fullSensor: Allowed all 4 rotation values.
unspecified: Same behavior as user setting
locked and nosensor: Stuck to 0 degree rotation
As you see from the tests, not much is clarified as to what each screenOrientation values does. Not sure why I am not being able to reproduce the effect defined on the resource page.
fullUser: Allowed rotation values 0, 90, 180 and 270 when auto-rotate enabled, otherwise the default one.
user: Allowed rotation values 0, 90 and 270 when auto-rotate enabled, otherwise the default one. But on some tablets it's also allowed to have 4 orientations...
#Vikram when you got only 0 degress with fullUser, I guess you're using a device apilevel < 18. ;)
In Android you can get a description of the properties of a Camera by retrieving a CameraInfo. I'm interested in orientation, as described at http://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation
However the documentation seems inconsistent with how all four of my devices behave, and, I have news of a fifth device for which this seemly fixed value changes.
In particular, the documentation says:
The value is the angle that the camera image needs to be rotated
clockwise so it shows correctly on the display in its natural
orientation. ... For example, suppose a device has a naturally tall
screen. The back-facing camera sensor is mounted in landscape. You are
looking at the screen. If the top side of the camera sensor is aligned
with the right edge of the screen in natural orientation, the value
should be 90. If the top side of a front-facing camera sensor is
aligned with the right of the screen, the value should be 270.
But in the stated example, it is the camera image that is rotated 90 degrees clockwise relative to the naturally tall orientation, not the other way around. That is, the image, whose top is aligned with the right hand side of the device, needs 270 degrees clockwise rotation to align with the device's top side.
At least, all four of my devices report "90" for this value, and all act as if the camera's top is the right side of the device when held in natural orientation. That is, the image must be rotated 270 degrees clockwise, not 90, to match the natural orientation. The example seems correct; the first line does not.
This example code seems to support my conclusion as it only gives the right result when orientation is interpreted as above.
Strangely, I have log evidence from one user's device that shows it reporting this value as 90 at times, and 0 at other times! It ought to be a physical property of how the camera is seated in the device, right?
Can anyone confirm that the first line of the documentation is in fact wrong, and the example is right?
Has anyone observed a changing value of CameraInfo.orientation? Is there evidence in docs that this is legal behavior, or is it likely a bug in the device?
Any other related comments, experiences, gotchas I have not run into yet?
1) Can anyone confirm that the first line of the documentation is in fact
wrong, and the example is right?
You have thoroughly addressed this already within your answer, thanks for the follow up explanation!
2) Has anyone observed a changing value of CameraInfo.orientation? Is there evidence in docs that this is legal behavior, or is it likely a
bug in the device?
While I can easily imagine this to be a bug in principle, it would still be a pretty severe one affecting all sorts of imaging related apps due to the resulting information being embedded via EXIF in photos for example (other EXIF related bugs aside for a moment).
Thus, I'd consider it more likely to be an actual feature of one of those thousands of Android devices out there, i.e. a camera with an option to physically rotate the lens. While I'm not aware of an Android based one currently, there used to be such phones available, e.g. the LG VX7000 (~2004) or the Samsung SCH-a930 (~2006) (see e.g. Rotating Camera Lens within the manual), so I'd not be surprised if something like this would appear in the Android sphere as well.
Incidentally, there is an unanswered question Why are my pics upside down or backwards. within Customer Questions & Answers for Samsung SCH-A930 regarding the latter:
Lately my pics have been upside down or backwards. Why is this
happening and how can I fix it.
This might actually be a bug in the otherwise functioning rotation adjustment hardware/firmware ;)
So in conclusion, I think it might be best to actually prepare for the orientation being able to change until you have more definite evidence for this to be a buggy device indeed.
I believe I've answered my own question here after some more thinking.
The example is correct. And, the text is correct actually. In the given example, if the preview data is displayed on the screen, it will appear rotated 90 degrees counter-clockwise, since "up" in the data is at the display's right hand, and it is shown on the display, whose "up" is at the data's left hand so to speak. So, it would be necessary to compensate by rotating the image data 90 degrees clockwise before displaying.
I think it's more natural to understand this figure as the rotation at which the camera is mounted relative to the natural orientation.
For this reasons and others I've concluded that the device that shows a changing value for orientation is simply buggy. At the least, when it reports 0, its data is acting like "90" is the right value.
Another way to deal with the problem is to extends OrientationEventListener
and override the method onOrientationChanged you will get the orientation of your phone even the autorotate disabled(because the listener emit the rotate event via sensor).
you should enable and disable the orientation listener on onResume/onPause to prevent some drain battery.
private class OnOrientationChange extends OrientationEventListener {
private boolean isEnabled = false;
public OnOrientationChange(Context context) {
super(context);
disable();
}
#Override
public void onOrientationChanged(int orientation) {
if (camera != null && orientation != ORIENTATION_UNKNOWN) {
int newOutputOrientation = getCameraPictureRotation(orientation);
if (newOutputOrientation != outputOrientation) {
outputOrientation = newOutputOrientation;
Camera.Parameters params = camera.getParameters();
params.setRotation(outputOrientation);
try {
camera.setParameters(params);
lastPictureOrientation = outputOrientation;
} catch (Exception e) {
Log.e(getClass().getSimpleName(),
"Exception updating camera parameters in orientation change",
e);
// TODO: get this info out to hosting app
}
}
}
}
#Override
public void enable() {
isEnabled = true;
super.enable();
}
#Override
public void disable() {
isEnabled = false;
super.disable();
}
boolean isEnabled() {
return (isEnabled);
}
}
thanks for common-sware for the solution
So I want my app to always lock onto the natural orientation of the device. So basically, I want to force the rotation to 0 degrees. There's a getRotation() method here:
http://developer.android.com/reference/android/view/Display.html
However, there is no setRotation(int rotation) that would accept one of the Surface.ROTATION_X parameters found here:
http://developer.android.com/reference/android/view/Surface.html
So, is there some way to do this with a single line of code that will always work? Or would this have to be done with some code?
The only thing I can think of as a manual solution is the following, but I have some concerns about it.
I can use the display.getRotation(). Then I'll check if it's 0 or 180 degrees, after that I'll get the display height and width, and see which one is longer than the other. If it appears I'm in landscape mode, then I'll know that the device's natural orientation is landscape so I could set it to landscape. However if the rotation was 270 or 90, then I would know the natural orientation is portrait, and I could set it to portrait.
However, my concern is where to do this such that it always works. Let's say the user is rotating the screen as this piece of code is executing, if the device changes orientation in between the time I use the getRotation() method, and check the width against the height with some if statements and what not, I think it could throw everything off. What happens if I put this in onCreate() or onResume()? Is it possible that things can get out of wack?
Is it possible for a the onCreate() or onResume() to be interrupted by a screen re-orientation due to the user turn the device around? The other issue is that if you flip the device by 180 degrees, the activity is never destroyed, so I think the behavior of this situation could very whether it's a 90 degree turn, or a 180 degree turn.
You can "set" the screen orientation in the manifest. See here: http://developer.android.com/guide/topics/manifest/activity-element.html#screen
<activity
android:name=".Activity"
android:screenOrientation="portrait"
android:theme="#style/Theme.D1"
android:label="#string/title_activity"/>
The value you're probably looking for is; "user" The user's current preferred orientation. However, I would test this on several test cases to be sure. HTH!
I have an activity that is showing a compass, and I need to know the orientation of the screen to properly rotate the needle. I need to distinguish between 90° and 270° degree rotation to properly handle this.
When I rotate the screen (on my Nexus S at least) the activity's onCreate gets called, e.g. when I rotate from portrait to landscape mode. When I rotate from one landscape mode to the other with the top edge raised, onCreate() gets called twice (once for portrait orientation and once for the target landscape mode).
However, when I rotate with the bottom edge up, the screen rotates 180° and onCreate is not getting called. Is there an event that gets fired in this case?
You are correct that at a 180 degree rotation you will not get restarted or get a configuration change, because the configuration has not actually changed. (It is still in landscape or portrait, and everything else is the same.)
However if you are showing a compass, that must mean you are updating it from sensor events. Thus you can just call Display.getRotation() each time you get a sensor update to get the current rotation of the screen. In fact that you need is rotation of interpreting sensor events (or actually how your drawing of them will be modified when it gets to the screen), not just the orientation.
I found a relevant blog post that is well worth reading.
Be sure to read the SDK documentation.
Also check out the discussion about using Display.getRotation() to correctly remap sensor coordinates.
The helper class OrientationEventListener makes it very easy to get call backs on rotation. I would suggest you give it a try.
Just take a look at the SensorManager Documentation, there you can get the best examples and explanations of how to use the accelerometer to get the most precise informations. Instead of making the things just by detecting the phone orientation, with that API you can get the exactly rotation, just like used by racing games like Asphalt and Need For Speed.
As Monchote said, in order to make your needle rotate as expected on the compass, it's better to lock your UI to portrait or landscape, and change your needle angle according to the device rotation angle, which can be gained easily from OrientationListener.
In this way, no matter the auto rotation feature is opened or not by user, you can always get rotation angle change notification. Here's a good example for your reference.
Have a look at the OnConfigurationChanged method to track down the orientation change and re-arrange your UI as needed.
See some sample code