Search code examples
imagebuttonscreen-orientationandroid-sensorssensormanagerrotateanimation

How to detect the device orientation with SensorEventListener?


I would like to detect the device screen orientation by implementing the SensorEventListener, because its current screen orientation is set to portrait by default. I need to do this, because my layout includes some buttons that should rotate independently from their layout and the only way to do this (as long as I know) is by overriding the onConfigurationChanged and adding the corresponding animation to each screen orientation. I don't think an OrientationEventListener would work since the set orientation is fixed to portrait. So how can I retrieve the screen orientation or angle rotations from the sensor itself?


Solution

  • An OrientationEventListener will work, even with fixed orientation; see https://stackoverflow.com/a/8260007/1382108. It monitors the sensor according to the documentation. Say you define the following constants:

    private static final int THRESHOLD = 40;
    public static final int PORTRAIT = 0;
    public static final int LANDSCAPE = 270;
    public static final int REVERSE_PORTRAIT = 180;
    public static final int REVERSE_LANDSCAPE = 90;
    private int lastRotatedTo = 0;
    

    The numbers correspond to what the OrientationEventListener returns, so if you have a natural landscape device (tablet) you have to take that into account, see How to check device natural (default) orientation on Android (i.e. get landscape for e.g., Motorola Charm or Flipout).

     @Override
    public void onOrientationChanged(int orientation) {
        int newRotateTo = lastRotatedTo;
        if(orientation >= 360 + PORTRAIT - THRESHOLD && orientation < 360 ||
                orientation >= 0 && orientation <= PORTRAIT + THRESHOLD)
            newRotateTo = 0;
        else if(orientation >= LANDSCAPE - THRESHOLD && orientation <= LANDSCAPE + THRESHOLD)
            newRotateTo = 90;
        else if(orientation >= REVERSE_PORTRAIT - THRESHOLD && orientation <= REVERSE_PORTRAIT + THRESHOLD)
            newRotateTo = 180;
        else if(orientation >= REVERSE_LANDSCAPE - THRESHOLD && orientation <= REVERSE_LANDSCAPE + THRESHOLD)
            newRotateTo = -90;
        if(newRotateTo != lastRotatedTo) {
            rotateButtons(lastRotatedTo, newRotateTo);
            lastRotatedTo = newRotateTo;
        }
    }
    

    The rotateButtons functions being something like:

    public void rotateButtons(int from, int to) {
    
        int buttons[] = {R.id.buttonA, R.id.buttonB};
        for(int i = 0; i < buttons.length; i++) {
            RotateAnimation rotateAnimation = new RotateAnimation(from, to, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rotateAnimation.setInterpolator(new LinearInterpolator());
            rotateAnimation.setDuration(200);
            rotateAnimation.setFillAfter(true);
            View v = findViewById(buttons[i]);
            if(v != null) {
                v.startAnimation(rotateAnimation);
            }
        }
    }