Reputation: 5460
I have come across a problem where the orientation sensorPortrait
does not work, i have tried enabling both through the manifest and within the activity itself with
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
But this seems to just be locked in normal portrait mode, however if i try `fullSensor'
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
which according to the docs
The orientation is determined by the device orientation sensor for any of the 4 orientations. This is similar to "sensor" except this allows any of the 4 possible screen orientations, regardless of what the device will normally do (for example, some devices won't normally use reverse portrait or reverse landscape, but this enables those). Added in API level 9.
and it does exactly that, all 4 orientations are possible. If i also try
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
I am able to achieve reverse portrait, which leads me back to my original question, why does sensorPortrait
not work? It looks like it has something to do with this line from the docs for `fullSensor'
regardless of what the device will normally do (for example, some devices won't normally use reverse portrait or reverse landscape, but this enables those)
So how do i enable it, is that possible and why does fullSensor
seem to override it but not sensorPortrait
? I can't seem to find any mention of how to do so. This question suggests that the PhoneWindowManager
is responsible for this.
Is the ideal solution just to create an OrientationEventListener()
and manually call setRequestedOrientation()
manually depending on the values returned via onOrientationChanged(int orientation)
?
Upvotes: 12
Views: 3578
Reputation: 641
Here is an updated class from the selected answer that you can extend from. It supports switching between:
setPortraitSensorMode()
setLandscapeSensorMode()
setAllSensorModes()
Below is the full class:
public class SensorOrientationActivity extends AppCompatActivity {
private static final String TAG = "SensorOrientation";
private OrientationEventListener mOrientationListener;
private OrientationChangeListener mListener;
private CurrentOrientation mCurrentOrientation = CurrentOrientation.PORTRAIT;
private SensorMode currentSensorMode = SensorMode.PORTRAIT_SENSOR;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOrientationListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int degrees) {
if (degrees != OrientationEventListener.ORIENTATION_UNKNOWN) {
orientationChanged(degrees);
}
}
};
mOrientationListener.enable();
}
@Override
protected void onResume() {
super.onResume();
mOrientationListener.enable();
}
@Override
protected void onPause() {
super.onPause();
mOrientationListener.disable();
}
public void setOrientationChangeListener(OrientationChangeListener listener) {
mListener = listener;
}
public void setPortraitSensorMode() {
currentSensorMode = SensorMode.PORTRAIT_SENSOR;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); // Let the OrientationEventListener handle it
Log.d(TAG, "Portrait Sensor Mode Set");
}
public void setLandscapeSensorMode() {
currentSensorMode = SensorMode.LANDSCAPE_SENSOR;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); // Let the OrientationEventListener handle it
Log.d(TAG, "Landscape Sensor Mode Set");
}
public void setAllSensorModes() {
currentSensorMode = SensorMode.ALL_SENSOR;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
Log.d(TAG, "All Sensor Modes Set");
}
private void orientationChanged(int degrees) {
//Log.d(TAG, "Orientation changed: " + degrees);
switch (currentSensorMode) {
case ALL_SENSOR:
handleAllSensorModes(degrees);
break;
case PORTRAIT_SENSOR:
handlePortraitSensorMode(degrees);
break;
case LANDSCAPE_SENSOR:
handleLandscapeSensorMode(degrees);
break;
}
}
private void handleAllSensorModes(int degrees) {
updateCurrentOrientation(degrees);
}
private void handlePortraitSensorMode(int degrees) {
if (isPortrait(degrees) || isReversePortrait(degrees)) {
updateCurrentOrientation(degrees);
}
}
private void handleLandscapeSensorMode(int degrees) {
if (isLandscape(degrees) || isReverseLandscape(degrees)) {
updateCurrentOrientation(degrees);
}
}
private void updateCurrentOrientation(int degrees) {
CurrentOrientation newOrientation = null;
if (isPortrait(degrees)) {
newOrientation = CurrentOrientation.PORTRAIT;
} else if (isReversePortrait(degrees)) {
newOrientation = CurrentOrientation.REVERSE_PORTRAIT;
} else if (isLandscape(degrees)) {
newOrientation = CurrentOrientation.LANDSCAPE;
} else if (isReverseLandscape(degrees)) {
newOrientation = CurrentOrientation.REVERSE_LANDSCAPE;
}
if (newOrientation != null && newOrientation != mCurrentOrientation) {
mCurrentOrientation = newOrientation;
applyOrientation(newOrientation);
notifyListener();
}
}
private void applyOrientation(CurrentOrientation orientation) {
switch (orientation) {
case PORTRAIT:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Log.d(TAG, "Orientation set to PORTRAIT");
break;
case REVERSE_PORTRAIT:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
Log.d(TAG, "Orientation set to REVERSE_PORTRAIT");
break;
case LANDSCAPE:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
Log.d(TAG, "Orientation set to LANDSCAPE");
break;
case REVERSE_LANDSCAPE:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
Log.d(TAG, "Orientation set to REVERSE_LANDSCAPE");
break;
}
}
private boolean isPortrait(int degrees) {
return (degrees >= 315 || degrees <= 45);
}
private boolean isReversePortrait(int degrees) {
return (degrees >= 135 && degrees <= 225);
}
private boolean isLandscape(int degrees) {
return (degrees > 45 && degrees < 135);
}
private boolean isReverseLandscape(int degrees) {
return (degrees > 225 && degrees < 315);
}
private void notifyListener() {
if (mListener == null) return;
switch (mCurrentOrientation) {
case PORTRAIT:
mListener.onPortrait();
break;
case REVERSE_PORTRAIT:
mListener.onReversePortrait();
break;
case LANDSCAPE:
mListener.onLandscape();
break;
case REVERSE_LANDSCAPE:
mListener.onReverseLandscape();
break;
}
}
interface OrientationChangeListener {
void onPortrait();
void onReversePortrait();
void onLandscape();
void onReverseLandscape();
}
enum CurrentOrientation {
PORTRAIT, REVERSE_PORTRAIT, LANDSCAPE, REVERSE_LANDSCAPE
}
enum SensorMode {
ALL_SENSOR, PORTRAIT_SENSOR, LANDSCAPE_SENSOR
}
}
Upvotes: 0
Reputation: 5460
As a work around i have created a SensorPortraitActivity
:
public class SensorPortraitActivity extends AppCompatActivity {
private static final int PORTRAIT = 0;
private static final int REVERSE_PORTRAIT = 180;
private static final int OFFSET = 45;
private static final int UNKNOWN = -1;
// account for 0 = 360 (eg. -1 = 359)
private static final int PORTRAIT_START = PORTRAIT - OFFSET + 360;
private static final int PORTRAIT_END = PORTRAIT + OFFSET;
private static final int REVERSE_PORTRAIT_START = REVERSE_PORTRAIT - OFFSET;
private static final int REVERSE_PORTRAIT_END = REVERSE_PORTRAIT + OFFSET;
private OrientationChangeListener mListener;
private OrientationEventListener mOrientationListener;
private CurrentOrientation mCurrentOrientation;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOrientationListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int i) {
orientationChanged(i);
}
};
}
@Override
protected void onResume() {
super.onResume();
mOrientationListener.enable();
}
@Override
protected void onPause() {
super.onPause();
mOrientationListener.disable();
}
//optional
public void setOrientationChangeListener(OrientationChangeListener listener){
mListener = listener;
}
private void orientationChanged(int degrees) {
if (degrees != UNKNOWN){
if (degrees >= PORTRAIT_START || degrees <= PORTRAIT_END){
if (mCurrentOrientation != CurrentOrientation.PORTRAIT){
mCurrentOrientation = CurrentOrientation.PORTRAIT;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
if (mListener != null){
mListener.onPortrait();
}
}
} else if (degrees >= REVERSE_PORTRAIT_START && degrees <= REVERSE_PORTRAIT_END){
if (mCurrentOrientation != CurrentOrientation.REVERSE_PORTRAIT){
mCurrentOrientation = CurrentOrientation.REVERSE_PORTRAIT;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
if (mListener != null) {
mListener.onReversePortrait();
}
}
}
}
}
interface OrientationChangeListener {
void onPortrait();
void onReversePortrait();
}
enum CurrentOrientation {
PORTRAIT, REVERSE_PORTRAIT
}
}
Although it does seem like overkill for something as simple as this.
To use it simple extend SensorPortraitActivity
public class ExampleActivity extends SensorPortraitActivity implements SensorPortraitView.OrientationChangeListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set listener if you want callbacks
super.setOrientationChangeListener(this);
}
@Override
public void onPortrait() {
//portrait orientation
}
@Override
public void onReversePortrait() {
//reverse portrait orientation
}
}
Upvotes: 12