Mark
Mark

Reputation: 7718

How to detect screen rotation through 180 degrees from landscape to landscape orientation?

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?

Upvotes: 22

Views: 11060

Answers (4)

S. Messick
S. Messick

Reputation: 11

You'd still want to use the display listener class: Google recommends it for handling 180-degree device rotations from an unlocked orientation. You cannot simply treat all callbacks to onDisplayChanged as 180 degree rotations. A more complete implementation from Google shows how to gather the Display rotation from the Display manager during the onDisplayChanged callback that superuser mentioned.

/** DisplayManager to listen to display changes */
private val displayManager: DisplayManager by lazy {
    applicationContext.getSystemService(DISPLAY_SERVICE) as DisplayManager
}

/** Keeps track of display rotations */
private var displayRotation = 0

...

override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    displayManager.registerDisplayListener(displayListener, mainLooperHandler)
}

override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    displayManager.unregisterDisplayListener(displayListener)
}

private val displayListener = object : DisplayManager.DisplayListener {
    override fun onDisplayAdded(displayId: Int) {}
    override fun onDisplayRemoved(displayId: Int) {}
    override fun onDisplayChanged(displayId: Int) {
        val difference = displayManager.getDisplay(displayId).rotation - displayRotation
        displayRotation = displayManager.getDisplay(displayId).rotation

        if (difference == 2 || difference == -2) {
            createCaptureSession()
        }
    }
}

Upvotes: 1

superuser
superuser

Reputation: 768

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);

Upvotes: 15

superuser
superuser

Reputation: 768

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();
  }

Upvotes: 3

c0ming
c0ming

Reputation: 3543

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();
}

Upvotes: 6

Related Questions