简体   繁体   中英

How to check device natural (default) orientation on Android (i.e. get landscape for e.g., Motorola Charm or Flipout)

I have an activity showing preview from camera, so it need to be set as landscape only. At the bottom (regardless of device rotation) I want to show a text view. I am using OrientationEventListener which gives device's orientation from its natural position. I can implement a solution which works well on portrait default devices but to make it work also on landscape default devices I need to be aware of running on such a device. Thus the question is how to check it?

This method can help:--

public int getDeviceDefaultOrientation() {

    WindowManager windowManager =  (WindowManager) getSystemService(Context.WINDOW_SERVICE);

    Configuration config = getResources().getConfiguration();

    int rotation = windowManager.getDefaultDisplay().getRotation();

    if ( ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
            config.orientation == Configuration.ORIENTATION_LANDSCAPE)
        || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&    
            config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
      return Configuration.ORIENTATION_LANDSCAPE;
    } else { 
      return Configuration.ORIENTATION_PORTRAIT;
    }
}

Well, you can find out what current orientation is the way @Urboss said. You cannot get the layout (landscape/portrait) that way ofcourse, so you'll have to get the screen width/heigth to check if the current (be it changed or not, but you've checked that ;) ) position is landscape or portrait:

    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    wPix = dm.widthPixels;
    hPix = dm.heightPixels;

(so if the rotation is 0 and you get landscape with above metrix, your device is default landscape. If the rotation is 90 degrees and you're portrait, the default is also landscape, and so on)

After hours and hours of trying to figure this out. It's not possible. However, the closest thing you can do is to set the orientation to "NOSENSOR"

 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

What this will do is set your application to the natural orientation of the device. At this point you can get the height and width of the display using the DisplayMetrics class, and calculate if you are in landscape or portrait. After you then figure out if it's landscape or portrait, you can then do this

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_XXXXX);

Where XXXX is either LANDSCAPE or PORTRAIT.

The case where doing this may not work is if you have a slide out keyboard.

Thanks to diyism's excellent answer above, I also added the logic to check the actual orientation position (landscape right, portrait, landscape left, portrait flipped):在此处输入图片说明 Here is the code:

@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
    //The coordinate-system is defined relative to the screen of the phone in its default orientation
    int orientation = 0;
    float roll=0;
    float pitch=0;
    switch (getWindowManager().getDefaultDisplay().getRotation())  {
        case Surface.ROTATION_0:
                 roll=event.values[2];
                 pitch=event.values[1];
            break;
            case Surface.ROTATION_90:
                 roll=event.values[1];
                 pitch=-event.values[2];
            break;
            case Surface.ROTATION_180:
                 roll=-event.values[2];
                 pitch=-event.values[1];
            break;
            case Surface.ROTATION_270:
                 roll=-event.values[1];
                 pitch=event.values[2];
            break;
           }

    if (pitch >= -45 && pitch < 45 && roll >= 45)
        orientation = 0;
    else if (pitch < -45 && roll >= -45 && roll < 45) 
        orientation = 1; 
    else if (pitch >= -45 && pitch < 45 && roll < -45) 
        orientation = 2;
    else if (pitch >= 45 && roll >= -45 && roll < 45 ) 
        orientation = 3;

    if (m_nOrientation != orientation) { //orientation changed event
        m_Inst.Debug(LOG_TAG,"onSensorChanged: orientation:" + orientation);
        m_nOrientation = orientation;
        // fire event for new notification, or update your interface here
    }
}

This code is also posted here: http://www.pocketmagic.net/?p=2847

Here's my solution:

public class ActivityOrientationTest extends Activity {
private static final String TAG = "ActivityOrientationTest";
private int mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
private TextView mTextView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);        
    setContentView(R.layout.main);
    mTextView = (TextView)findViewById(R.id.text);
    setDefaultOrientation();        
}

private void setDefaultOrientation(){
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);

    Display display;         
    display = getWindow().getWindowManager().getDefaultDisplay();
    int rotation = display.getRotation();
    int width = 0;
    int height = 0;
    switch (rotation) {
    case Surface.ROTATION_0:
    case Surface.ROTATION_180:
        Log.i(TAG, "Rotation is: 0 or 180");
        width = display.getWidth();
        height = display.getHeight();
        break;
    case Surface.ROTATION_90:       
    case Surface.ROTATION_270:
        Log.i(TAG, "Rotation is: 90 or 270");
        width = display.getHeight();
        height = display.getWidth();
        break;
    default:
        break;
    }

    if(width > height){
        Log.i(TAG, "Natural Orientation is landscape");
        mTextView.setText("Natural Orientation is landscape");
        mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    } else {
        Log.i(TAG, "Natural Orientation is portrait");
        mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        mTextView.setText("Natural Orientation is portrait");
    } 

    setRequestedOrientation(mNaturalOrientation);
}

Display.getRotation() is only supported in API level 8 or higher so if you need to support older devices you'll need to call Display.getOrientation().

public static boolean isDeviceDefaultOrientationLandscape(Activity a) {

    WindowManager windowManager = (WindowManager) a.getSystemService(Context.WINDOW_SERVICE);

    Configuration config = a.getResources().getConfiguration();

    int rotation = windowManager.getDefaultDisplay().getRotation();

    boolean defaultLandsacpeAndIsInLandscape = (rotation == Surface.ROTATION_0 ||
            rotation == Surface.ROTATION_180) &&
            config.orientation == Configuration.ORIENTATION_LANDSCAPE;

    boolean defaultLandscapeAndIsInPortrait = (rotation == Surface.ROTATION_90 ||
            rotation == Surface.ROTATION_270) &&
            config.orientation == Configuration.ORIENTATION_PORTRAIT;

    return defaultLandsacpeAndIsInLandscape || defaultLandscapeAndIsInPortrait;
}

@Urboss, it can't. You need to know the default orientation of the device first, because both methods return the changes based on it (I mean, if the default is portrait, the result you are looking for will be 1 or ROTATE_90 -so it is landscape-, but, if the default is landscape, the result is 0).

And as far as I know, finding the default orientation of the device is not trivial :(

Anybody can throw some light in this topic?

You can define by using rotation and orientation. No need to use sensors or any listeners, just call isDefaultLandscape method whenever you wish.

private boolean isDefaultLandscape(final Context context)
{
    Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    int rotation = display.getRotation();
    int orientation = context.getResources().getConfiguration().orientation;

    switch (rotation)
    {
        case Surface.ROTATION_180:
        case Surface.ROTATION_0:
        {
            return orientation == Configuration.ORIENTATION_LANDSCAPE;
        }
        default:
        {
            return orientation == Configuration.ORIENTATION_PORTRAIT;
        }
    }
}

My solution(tested at HTC desire and SamSung galaxy tab 10.1):

    private class compass_listener implements SensorEventListener
            {public void onAccuracyChanged(Sensor sensor, int accuracy) {}

             public void onSensorChanged(SensorEvent event)
                    {float roll=0;
                     float pitch=0;
                     switch (((Activity)context).getWindowManager().getDefaultDisplay().getRotation())
                            {case Surface.ROTATION_0:
                                  roll=event.values[2];
                                  pitch=event.values[1];
                             break;
                             case Surface.ROTATION_90:
                                  roll=event.values[1];
                                  pitch=-event.values[2];
                             break;
                             case Surface.ROTATION_180:
                                  roll=-event.values[2];
                                  pitch=-event.values[1];
                             break;
                             case Surface.ROTATION_270:
                                  roll=-event.values[1];
                                  pitch=event.values[2];
                             break;
                            }
                     JSONObject json=new JSONObject();
                     try
                         {json.put("roll", roll);
                          json.put("pitch", pitch);
                          json.put("azimuth", event.values[0]);
                         }
                     catch (JSONException e)
                           {throw new RuntimeException(e);
                           }
                     java_2_js(webview, "intent_compass_change", json);
                    }
            }

For fellow Xamarin developers, here is a version of this check in C#:

var orientation = ContextHelper.Current.Resources.Configuration.Orientation;
if (orientation == Android.Content.Res.Orientation.Undefined)
{
    //unknown, you can provide special handling for this case
}

var isLandscape = false;
var rotation = windowManager.DefaultDisplay.Rotation;           

switch (rotation)
{
    case SurfaceOrientation.Rotation0:
    case SurfaceOrientation.Rotation180:
        isLandscape = orientation == Android.Content.Res.Orientation.Landscape;
        break;
    default:
        isLandscape = orientation == Android.Content.Res.Orientation.Portrait;
        break;
}

Here's what I've been using:

 /**
     * returns the natural orientation of the device: Configuration.ORIENTATION_LANDSCAPE or Configuration.ORIENTATION_PORTRAIT .<br/>
     * The result should be consistent no matter the orientation of the device
     */
    public static int getScreenNaturalOrientation(@NonNull final Context context) {
        //based on : http://stackoverflow.com/a/9888357/878126
        final WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        final Configuration config = context.getResources().getConfiguration();
        final int rotation = windowManager.getDefaultDisplay().getRotation();
        if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
                config.orientation == Configuration.ORIENTATION_LANDSCAPE)
                || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
                config.orientation == Configuration.ORIENTATION_PORTRAIT))
            return Configuration.ORIENTATION_LANDSCAPE;
        else
            return Configuration.ORIENTATION_PORTRAIT;
    }

You can also get the natural resolution as such:

/**
 * returns the natural screen size (in pixels). The result should be consistent no matter the orientation of the device
 */
public static
@NonNull
Point getScreenNaturalSize(@NonNull final Context context) {
    if (sNaturalScreenSize != null)
        return sNaturalScreenSize;
    final int screenNaturalOrientation = getScreenNaturalOrientation(context);
    final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    final int currentOrientation = context.getResources().getConfiguration().orientation;
    if (currentOrientation == screenNaturalOrientation)
        return sNaturalScreenSize = new Point(displayMetrics.widthPixels, displayMetrics.heightPixels);
    //noinspection SuspiciousNameCombination
    return sNaturalScreenSize = new Point(displayMetrics.heightPixels, displayMetrics.widthPixels);
}

After some googling, I found a blog mentioned that while executing wm size command through adb shell, it will always return the unrotated "natural" screen resolution, and then the author hunted down to here :

        mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
                        Context.WINDOW_SERVICE));

and here :

                mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);

So, it seems that Android actually knows the initial/unrotated/"natural" screen size, but, it just doesn't want the app to know it? I'm confused...

its very simple to solve this

int orient=this.getResources().getConfiguration().orientation;

if it return 1 or 2

1 is portrait 2 is landscape

可以使用Display.getOrientation()Display.getRotation() (对于 API 级别 >= 8)来完成。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM