I would like to simulate youtube video-view behaviour in terms of handling screen orientation.
use cases:
p1. when user press maximise -> activity always goes into landscape
p2. when user press minimise -> activity always goes into portrait
p3. when user rotates the device -> screen orientation should change accordingly even if p1 or p2 was applied before.
Currently I use:
@Override
public void onClick(View view) {
if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
However this locks the orientation permanently and fails p3.
If you want to manually handle orientation changes in your app you must declare the "orientation" , "screenSize" , and "screenLayout" values in the android:configChanges attributes. You can declare multiple configuration values in the attribute by separating them with a pipe | character.
When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them . Android does this so that your application can reload resources based on the new configuration.
In AndroidManifest. xml file add the screenOrientation attribute in activity and provides its orientation. In this example, we provide "portrait" orientation for MainActivity and "landscape" for SecondActivity.
After playing around for a while I have found the right solution. First of all - the problem is that android locks the screen after setRequestedOrientation call, you can't have a mix of both, the only to do it is to do everything manually.
Here is how:
class PlayerOrientationListener extends OrientationEventListener {
PlayerOrientationListener() {
super(VideoPlayerActivity.this);
}
@Override
public void onOrientationChanged(int orientation) {
int threshold = 5;
if (Math.abs(orientation - 0) < threshold) orientation = 0;
else if (Math.abs(orientation - 90) < threshold) orientation = 90;
else if (Math.abs(orientation - 180) < threshold) orientation = 180;
else if (Math.abs(orientation - 270) < threshold) orientation = 270;
switch (orientation) {
case 0:
if (!orientationLandscapeLocked) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
orientationPortraitLocked = false;
}
break;
case 90:
if (!orientationPortraitLocked) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
orientationLandscapeLocked = false;
}
break;
case 180:
if (!orientationLandscapeLocked) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
orientationPortraitLocked = false;
}
break;
case 270:
if (!orientationPortraitLocked) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
orientationLandscapeLocked = false;
}
break;
}
}
}
and activity code:
View.OnClickListener onExpandClick = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
orientationLandscapeLocked = true;
orientationPortraitLocked = false;
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
orientationPortraitLocked = true;
orientationLandscapeLocked = false;
}
}
};
btnExpandVideo.setOnClickListener(onExpandClick);
orientationListener = new PlayerOrientationListener();
orientationListener.enable();
@Yuriy's answer worked great for me, here it is in Kotlin with some minor modifications so that it can live in a separate file:
class PlayerOrientationListener(val activity: Activity?) : OrientationEventListener(activity) {
companion object {
private const val ROT_THRESHOLD = 5
private const val ROT_0 = 0
private const val ROT_90 = 90
private const val ROT_180 = 180
private const val ROT_270 = 270
}
private var orientationLockedPortrait = false
private var orientationLockedLandscape = false
fun lockLandscape() {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
orientationLockedLandscape = true
orientationLockedPortrait = false
}
fun lockPortrait() {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
orientationLockedPortrait = true
orientationLockedLandscape = false
}
override fun onOrientationChanged(orientation: Int) {
if (orientation == ORIENTATION_UNKNOWN) {
return
}
val rotation: Int =
when {
Math.abs(orientation - ROT_0) < ROT_THRESHOLD -> ROT_0
Math.abs(orientation - ROT_90) < ROT_THRESHOLD -> ROT_90
Math.abs(orientation - ROT_180) < ROT_THRESHOLD -> ROT_180
Math.abs(orientation - ROT_270) < ROT_THRESHOLD -> ROT_270
else -> ORIENTATION_UNKNOWN
}
when (rotation) {
ROT_0 -> if (!orientationLockedLandscape) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
orientationLockedPortrait = false
}
ROT_90 -> if (!orientationLockedPortrait) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
orientationLockedLandscape = false
}
ROT_180 -> if (!orientationLockedLandscape) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
orientationLockedPortrait = false
}
ROT_270 -> if (!orientationLockedPortrait) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
orientationLockedLandscape = false
}
}
}
}
Then in your Fragment, something like:
val orientationListener = PlayerOrientationListener(activity)
orientationListener.enable()
menuItemMaximize?.setOnMenuItemClickListener {
orientationListener.lockLandscape()
true
}
menuItemMinimize?.setOnMenuItemClickListener {
orientationListener.lockPortrait()
true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With