Android: Detect Orientation Changed

How to detect orientation change in layout in Android?

Use the onConfigurationChanged method of Activity.
See the following code:

@Override
public void onConfigurationChanged(@NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);

// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}

You also have to edit the appropriate element in your manifest file to include the android:configChanges
Just see the code below:

<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name">

NOTE: with Android 3.2 (API level 13) or higher, the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher, you must declare android:configChanges="orientation|screenSize" for API level 13 or higher.

Hope this will help you... :)

Android: Detect Orientation Changed

Ok, after trying to use the Android API and not being able to do what I need, I implemented my own algorithm and actually it wasn't that complicated:
I used a OrientationEventListener, and calculated if the orientation is in the 4 orientation points (in my code I only detect LANDSCAPE_RIGHT and PORTRAIT_UP:

orientationListener = new OrientationEventListener(context, SensorManager.SENSOR_DELAY_UI) {
public void onOrientationChanged(int orientation) {
if(canShow(orientation)){
show();
} else if(canDismiss(orientation)){
dismiss();
}
}
};

@Override
public void onResume(){
super.onResume();
orientationListener.enable();
}

@Override
public void onPause(){
super.onPause();
orientationListener.disable();
}

private boolean isLandscape(int orientation){
return orientation >= (90 - THRESHOLD) && orientation <= (90 + THRESHOLD);
}

private boolean isPortrait(int orientation){
return (orientation >= (360 - THRESHOLD) && orientation <= 360) || (orientation >= 0 && orientation <= THRESHOLD);
}

public boolean canShow(int orientation){
return !visible && isLandscape(orientation);
}

public boolean canDismiss(int orientation){
return visible && !dismissing && isPortrait(orientation);
}

Detect orientation change, when only portrait is allowed on Android

When android:screenOrientation="portrait" or "landscape" are set in the menifest file no listeners are fired still if u want to do it try handling the portrait only mode in ur onConfigurationChanged() programatically and here u will also be able to start the activity again.

How to detect when the device switch from portrait to landscape mode?

See the official documentation http://developer.android.com/guide/topics/resources/runtime-changes.html

Changing it will actually create a new view and onCreate will be called again.

Furthermore you can check it via

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);

// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}

Detect rotation (orientation change) before activity destroyed

After a lot of searching before posting my question, I finally came up with a solution based off of this post. I very simply check the current orientation and compare it to the previous state.

getResources().getConfiguration().orientation

If it is the different, the activity is restarting due to a rotation.

Sample Solution

I start by having two member variables to track the previous configuration and to mark rotation:

private int previousOrientation = Configuration.ORIENTATION_UNDEFINED;
private boolean rotating = false;

When the activity is started, in onCreate, I call checkAndSetOrientationInfo() which is defined as:

private void checkAndSetOrientationInfo() {
int currentOrientation = getResources().getConfiguration().orientation;
debugDescribeOrientations(currentOrientation);
if(previousOrientation != Configuration.ORIENTATION_UNDEFINED // starts undefined
&& previousOrientation != currentOrientation) rotating = true;

previousOrientation = currentOrientation;
}

The supporting functions are:

private String getOrientationAsString(final int orientation) {
if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
return "Landscape";
} else if(orientation == Configuration.ORIENTATION_PORTRAIT) {
return "Portrait";
} else return "Undefined";
}

private void debugDescribeOrientations(final int currentOrientation) {
Log.v("Orientation", "previousOrientation: " + getOrientationAsString(previousOrientation));
Log.v("Orientation", "currentOrientation: " + getOrientationAsString(currentOrientation));
}

And finally, for onPause:

@Override
protected void onPause() {
super.onPause();
if (isFinishing()) {
Log.v("onPause", "Finishing");
} else {
checkAndSetOrientationInfo();
if (rotating) {
Log.v("onPause", "Rotating");
} else {
Log.v("onPause", "Not rotating (task switch / home etc)");
// TODO put code here to pause mediaPlayer etc...
}
}
}

I asked and answered this question to help others with the same problem. I am also interested to see any comments about situations where this code might fail or other better solutions.

How can I globally detect when the screen rotation changes?

Use the hidden API

You can do this using a hidden API called IWindowManager.watchRotation(IRotationWatcher). From my testing, it seems to take a callback that is called every time the screen rotation changes. The callback also seems to be given the current screen rotation.

Being a hidden API, you can't just call it directly. How to use hidden APIs is a topic of its own. And, of course, this might not be as reliable from a maintainability perspective as normal APIs.

Also, onRotationChanged isn't called in the same thread you used to call watchRotation. You'll probably want to delegate some work to a different thread such as the UI thread once you're in onRotationChanged.

Compatibility

Tested and working in API 14 - 28.

Example

Here's one way to get it to work:

  1. Copy android.view.IRotationWatcher into your app. Make sure to keep it in its original package. This seems to cause the development tools to think your code has access to it while also causing the operating system to still use the real one rather than your own copy.
  2. Use reflection to call watchRotation:

    try {
    Class<?> serviceManager = Class.forName("android.os.ServiceManager");
    IBinder serviceBinder = (IBinder)serviceManager.getMethod("getService", String.class).invoke(serviceManager, "window");
    Class<?> stub = Class.forName("android.view.IWindowManager$Stub");
    Object windowManagerService = stub.getMethod("asInterface", IBinder.class).invoke(stub, serviceBinder);
    Method watchRotation;
    if (Build.VERSION.SDK_INT >= 26)
    watchRotation = windowManagerService.getClass().getMethod("watchRotation", IRotationWatcher.class, int.class);
    else
    watchRotation = windowManagerService.getClass().getMethod("watchRotation", IRotationWatcher.class);

    //This method seems to have been introduced in Android 4.3, so don't expect to always find it
    Method removeRotationWatcher = null;
    try {
    removeRotationWatcher = windowManagerService.getClass().getMethod("removeRotationWatcher", IRotationWatcher.class);
    }
    catch (NoSuchMethodException ignored) {}

    IRotationWatcher.Stub screenRotationChanged = new IRotationWatcher.Stub() {
    @Override
    public void onRotationChanged(int rotation) throws RemoteException {
    //Do what you want here
    //WARNING: This isn't called in the same thread you were in when you called watchRotation
    }
    };

    //Start monitoring for changes
    if (Build.VERSION.SDK_INT >= 26)
    watchRotation.invoke(windowManagerService, screenRotationChanged, Display.DEFAULT_DISPLAY);
    else
    watchRotation.invoke(windowManagerService, screenRotationChanged);

    //Stop monitoring for changes when you're done
    if (removeRotationWatcher != null) {
    removeRotationWatcher.invoke(windowManagerService, screenRotationChanged);
    } catch (ClassNotFoundException | ClassCastException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
    throw new RuntimeException(e);
    }

Can android app detect orientation change while running in the background?

Create an android service, register a broadcast receiver for configuration changes and handle orientation changes inside.
https://developer.android.com/training/run-background-service/create-service

val filter = IntentFilter().apply {
addAction(android.intent.action.CONFIGURATION_CHANGED)
}
this.registerReceiver(broadcastReceiver, filter)


Related Topics



Leave a reply



Submit