21

I've seen a few other questions similar to this but no answers.

Rotating from portrait to landscape (either direction) and back again, we get the helpful call to onConfigurationChanged().

However, when rotating from landscape to landscape (through 180 degrees) onConfigurationChanged() is not called.

I've seen mention of using OrientationEventListener but this seems flakey to me because you can rotate quickly around without triggering a display orientation change.

I've tried adding a layout change listener, but with no success.

So the question is, how to reliably detect such a change in landscape orientation?

Mark
  • 7,124
  • 4
  • 51
  • 70

3 Answers3

13

OrientationEventlistener won't work when the device isn't rotating/moving.

I find display listener is a better way to detect the change.

     DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
        @Override
        public void onDisplayAdded(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " added.");
        }

        @Override
        public void onDisplayChanged(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " changed.");
        }

        @Override
        public void onDisplayRemoved(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " removed.");
        }
     };
     DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
     displayManager.registerDisplayListener(mDisplayListener, UIThreadHandler);
superuser
  • 698
  • 6
  • 9
  • 1
    Note: this requires API Level 17+ – lapis May 14 '14 at 19:08
  • why do you need OrientationEventlistener to work when the device isn't rotating/moving ? – Jigar May 14 '14 at 19:32
  • My app need to provide fresh orientation status, but sometimes orientation could be changed by calling API. Finally I used a thread to pull its status.. No better solution indeed since this only works with API 17+. – superuser May 22 '14 at 14:57
  • 4
    THIS should be the accepted answer. `onDisplayChanged` triggers only exactly when `getRotation()` changes. `OrientationEventListener` on the other hand triggers constantly in real time and even before `getRotation()` changes, leading to completely wrong screen rotation values when doing a 180° turn. – 0101100101 Feb 21 '18 at 23:57
  • In my case DisplayListener doesnt work on Android TV Api 17. Any suggestions? – Aleksandr A Sep 14 '18 at 14:19
6

May be you should add some logical code in your OrientationEventListener like this:

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

OrientationEventListener orientationEventListener = new OrientationEventListener(this,
        SensorManager.SENSOR_DELAY_NORMAL) {
    @Override
    public void onOrientationChanged(int orientation) {

        Display display = mWindowManager.getDefaultDisplay();
        int rotation = display.getRotation();
        if ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && rotation != mLastRotation) {
            Log.i(TAG, "changed >>> " + rotation);

            // do something

            mLastRotation = rotation;
        }
    }
};

if (orientationEventListener.canDetectOrientation()) {
    orientationEventListener.enable();
}
c0ming
  • 3,169
  • 1
  • 20
  • 26
  • Why only 90 and 270 degrees? Phones usually cannot be upside down, but tablets do. The same problem is when you rotate 180deg. from portrait. – Oliv Mar 10 '16 at 13:37
  • 1
    Beware of this answer! `OrientationEventListener` is not the correct tool for 180° orientation changes, because it triggers constantly in real time and even before `getRotation()` changes! `DisplayListener` does a much better job as it triggers only exactly when `getRotation()` changes. – 0101100101 Feb 21 '18 at 23:52
  • @0101100101 VERY TRUE, sometimes rotation doesn't even happen when OrientationEventListener says that it happened – user924 May 02 '18 at 11:56
  • guys DON'T USE THIS, you can have delayed orientation changes or sometimes it when you rotate it won't change orientation, so this method won't tell the correct current orientation of your app – user924 May 02 '18 at 11:57
3

I use this code to have it work for my case.

  OrientationEventListener mOrientationEventListener = new OrientationEventListener(mActivity)
  {
     @Override
     public void onOrientationChanged(int orientation)
     {
        if (orientation == ORIENTATION_UNKNOWN) return;

        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
          case Surface.ROTATION_0:
             android.util.Log.i(TAG, "changed ROTATION_0 - " + orientation);
             break;
          case Surface.ROTATION_90:
             android.util.Log.i(TAG, "changed ROTATION_90 - " + orientation);
             break;
          case Surface.ROTATION_180:
             android.util.Log.i(TAG, "changed ROTATION_180 - " + orientation);
             break;
          case Surface.ROTATION_270:
             android.util.Log.i(TAG, "changed ROTATION_270 - " + orientation);
             break;
        }
        if ((rotation != mLastRotation) && (rotation & 0x1) == (mLastRotation & 0x1))
        {
           android.util.Log.i(TAG, "unhandled orientation changed >>> " + rotation);
        }
        mLastRotation = rotation;
     }
  };

  if (mOrientationEventListener.canDetectOrientation()){
     mOrientationEventListener.enable();
  }
superuser
  • 698
  • 6
  • 9
  • 1
    Beware of this answer! `OrientationEventListener` is not the correct tool for 180° orientation changes, because it triggers constantly in real time and even before `getRotation()` changes! `DisplayListener` does a much better job as it triggers only exactly when `getRotation()` changes. – 0101100101 Feb 21 '18 at 23:53
  • guys DON'T USE THIS, you can have delayed orientation changes or sometimes it when you rotate it won't change orientation, so this method won't tell the correct current orientation of your app – user924 May 02 '18 at 11:57
  • Not to mention in Android 9 they added the new button to allow the user to change the orientation of the app (or not), but this will still trigger the code to rotate – 1800 INFORMATION Feb 06 '20 at 22:28