http://goo.gl/bMjh

Android has an API for accessing a variety of sensor
types<http://developer.android.com/reference/android/hardware/SensorManager.html>,
such as an accelerometer or light sensor. Two of the most commonly-used
sensors are accelerometers and magnetometers (that is, compasses.)
Applications and devices frequently use these as forms of user input, and to
determine which way to orient the screen.

However, there’s a new wrinkle: recently, a few devices have shipped (see
here<http://www.motorola.com/Consumers/US-EN/Consumer-Product-and-Services/Mobile-Phones/MOTOROLA-CHARM-with-MOTOBLUR-US-EN>
 and 
here<http://mediacenter.motorola.com/content/detail.aspx?ReleaseID=12865&NewsAreaId=2>)
that run Android on screens that are naturally landscape in their
orientation. That is, when held in the default position, the screens are
wider than they are tall. This introduces a few fairly subtle issues that
we’ve noticed causing problems in some apps. Now, part of the reason for
this is that the Android SDK docs on the sensor API left a couple things
unsaid, leading many developers to use them incorrectly. Even a couple of
our own samples did the wrong thing. Sorry about that!

Fortunately, using these APIs correctly is pretty simple, if you keep three
rules in mind:

   -

   The sensor coordinate system used by the API for the natural orientation
   of the device does not change as the device moves, and is the same as the
   OpenGL coordinate system.
   -

   Applications must not assume that the natural orientation is portrait.
   That's not true on all devices.
   -

   Applications that match sensor data to on-screen display must always use
   android.view.Display.getRotation() to map sensor coordinates to screen
   coordinates — even if their manifest specifies portrait-only display.

If you have a strong background in math, the three rules above may be all
you need to work out the rest. But if that’s not you, the rest of this post
explains things step-by-step, and gives some tips for using sensors
correctly.
 The Basic Problem

Before we dive in, here’s a tip that I personally have found to be helpful:
always remember that *the sensor data’s coordinate system never changes.
Ever.*The rest of this post is going to talk about coordinate systems and
rotations and so on. But sometimes when your head is deep in 3D transforms,
you can get disoriented, so I’ve found it helps to frequently remind myself
that no matter what is happening to the screen, the sensor coordinate system
never changes.

Now with that tip in mind, we need an example to talk about. Let’s consider
a simple app that draws an arrow that always points in the direction of
gravity, animating the arrow as the user moves the phone around, like a
plumb-bob <http://en.wikipedia.org/wiki/Plumb-bob>. When a typical phone is
held normally, the arrow points down, as shown in Figure A:
<http://1.bp.blogspot.com/_GTM_W5mVPTU/TIlO8Tq8uwI/AAAAAAAAALI/SiTXyfWzDEI/s1600/figureA.png>

*(Note: In the figures in this post, the letter “G” means the direction of
gravity in the sensor coordinate system. In Figure A, for example, “G = -y”
means that gravity is aligned with the device’s negative-Y axis, as measured
by the accelerometer. And remember — the sensor coordinate system never
changes!)*

This app is pretty straightforward to implement in OpenGL: you simply need
to draw an arrow on a GL SurfaceView, after rotating the coordinate space in
response to the sensor data returned by the accelerometer. This “just works”
because — in this basic case — the OpenGL screen coordinate system lines up
with the sensor coordinate system.

So, this technique works, and the arrow will always point down — until you
turn the phone too far.
So What’s the Problem?

Most Android devices use the accelerometer to detect when the device is
being held sideways, and rotate the screen accordingly. This normally causes
the apps to display horizontally, from the point of view of the user.

What this reorientation actually does is remap the X and Y axes, causing the
app to draw itself horizontally. However, the Android sensor APIs define the
sensor coordinate space to be relative to the *top* and *side* of the
device — *not* the short and long sides. When the system reorients the
screen in response to holding the phone sideways, the sensor coordinate
system no longer lines up with the screen’s coordinate system, and you get
unexpected rotations in the display of your app. Figure B shows an example:
<http://1.bp.blogspot.com/_GTM_W5mVPTU/TIlPGGJ9X7I/AAAAAAAAALQ/ik9-7hVqs_s/s1600/FigureB.png>

There are are a couple different fixes for this problem that are commonly
used today, but we’ve noticed that these often don’t work properly on
landscape-default devices.

A common first attempt to solve the auto-rotation problem is to simply lock
the screen to portrait mode, via the
android:screenOrientation<http://developer.android.com/guide/topics/manifest/activity-element.html#screen>
attribute
in AndroidManifest.xml. This prevents the system from performing a screen
coordinate system remap in response to device orientation, and so the sensor
and screen coordinate systems remain in sync. However, locking the screen to
portrait mode this way *prevents* the coordinate systems from getting out of
sync on portrait-default devices, but causes them to become out of sync on
landscape-default devices. This is because it forces a screen reorientation
on those devices.

The second common technique is to detect when the device is in landscape
mode, and compensate for it by adding a rotation to the graphics that are
displayed. Unfortunately, this technique is often only a partial fix,
because if you aren’t careful about detecting landscape mode, you will
again *cause* an unnecessary compensation on landscape-default devices.
 The Correct Fix

So what’s a poor developer to do? This seems like a catch-22: you can’t *
prevent* screen reorientation, but you can’t *compensate* for it, either.

Or can you? Actually, you can compensate — you just have to make sure you’re
correctly detecting when compensation is necessary. The question is, how
does the device tell you that it’s been reoriented? And the answer is:
android.view.Display.getRotation()<http://developer.android.com/reference/android/view/Display.html#getRotation()>
.

That method will return one of four values, indicating that either the
device has not been reoriented (ROTATION_0), or that it has been reoriented
by 90 degrees, 180 degrees, or 270 degrees (which respectively are
ROTATION_90, ROTATION_180, and ROTATION_270.)

Pay special attention to those last two. ROTATION_180 and ROTATION_270 mean
that each device actually has *two* portrait and *two* landscape modes:
normal portrait and landscape, and the upside-down versions of each. Some
Android devices that do “360 reorientation” will use these rotation modes as
well, so you need to handle this generally, beyond just accounting for
portrait or landscape mode.

Once you have the screen orientation info in hand, you can treat it as a
rotation around the screen’s Z axis when rendering graphics. By applying the
rotation to the values you get from your SensorEventListener, you can
correctly and reliably compensate for screen reorientations on all devices.

Note that Display.getRotation() will tell you if the screen has been
reoriented at all, not that it was reoriented specifically in response to
the accelerometer. For example, even if you disable accelerometer-based
reorientation by using android:screenOrientation=”nosensor", your app might
still be reoriented if the user has opened a hard keyboard on the device.

Because handling all this involves some math that can be a bit of a chore,
as a convenience we’ve provided the
android.hardware.sensor.SensorManager.remapCoordinateSystem()<http://developer.android.com/reference/android/hardware/SensorManager.html#remapCoordinateSystem(float[],%20int,%20int,%20float[])>
method
to do much of this remapping work for you. If you choose not to do use this
method, you can achieve a similar effect by essentially swapping axes, along
with the rule of thumb that 2 axis swaps requires that you negate the third
axis. (Since this is a bit error-prone, we do recommend that you use
remapCoordinateSystem() when you can.)
 Recipes for Sensuous Delights

Okay, now we’ve got a technique that we can rely on to work on all devices.
But how do you update your app? To give you a more explicit helping hand on
how to fix your apps, I’ve whipped up a few recipes for updating your apps.
 Apps That Never Draw Sensor Data

Apps that never display graphics derived from sensor data usually don’t need
to make any changes. Examples of this type of app are those that detect for
bumps to the device, those that use sensors for gesture input, apps that
monitor g-forces (watching for free-fall or acceleration), and so on. These
apps aren’t drawing images that vary according to the device’s orientation.

This isn’t a hard and fast rule; there probably are some apps out there that
do need to take screen orientation into consideration, even though they
don’t draw graphics depicting the sensor data. But, if your app just uses
sensors in the background, there’s a good chance you won’t need to make any
changes.
 Apps That Work in Both Portrait and Landscape

Most Android apps work fine in both portrait and landscape, using the
standard tools. If your app is one of these and you also use sensors, the
only change your app probably requires is a tweak to use the behavior I
outlined above. That is:

   -

   Don’t assume that portrait is the default mode.
   -

   Don’t assume that locking your app to portrait mode solves this issue.
   -

   Don’t assume that disabling sensor-based reorientation solves this issue
   (since reorientations also occur on some devices when the user opens a
   keyboard.)
   -

   Check for the current device orientation via getRotation(), and
   compensate accordingly, as detailed earlier.

Apps That Only Work in One Orientation

Some apps — notably, many games — only work well (or at all!) in either
portrait or landscape mode. It’s perfectly okay, of course, for such apps to
lock themselves to the appropriate mode, and doing so simplifies the sensors
quite a bit.

However, because Android devices actually support two landscape and two
portrait modes, these apps still need to check the current orientation. That
is, if an app locks itself to landscape mode, it will need to perform a
compensation on portrait-default devices, but not on landscape-default
devices. And of course — are you sick of hearing this yet? — this can be
accomplished by checking the result of getRotation().

Phew! Quite a mouthful for what is a fairly straightforward notion, once you
understand what’s going on. But if I had to distill all that down into a
single sentence, it would be this: android.view.Display.getRotation() is
your friend.

I hope you’ve found this information useful; what’s more, I hope you’ve
found it practical. We’ll keep improving our SDK and docs, and I hope you’ll
keep improving your apps.

Happy coding!



-- 
Salam,


Agus Hamonangan

http://groups.google.com/group/id-android
http://groups.google.com/group/id-gtug
Gtalk  : id.android
Follow : @agushamonangan
E-mail :  [email protected]

-- 
"Indonesian Android Community [id-android]" 

Join: http://groups.google.com/group/id-android/subscribe?hl=en-GB  
Moderator: [email protected]
Peraturan Jual dan Kloteran ID-Android  http://goo.gl/azW7
ID Android Developer: http://groups.google.com/group/id-android-dev
ID Android Surabaya: http://groups.google.com/group/id-android-sby
ID Android on FB: http://www.facebook.com/group.php?gid=112207700729

Kirim email ke