I have an activity showing preview from camera, so it need to be set as landscape only. At the bottom (regardless of device rotation) I want to show a text view. I am using OrientationEventListener which gives device's orientation from its natural position. I can implement a solution which works well on portrait default devices but to make it work also on landscape default devices I need to be aware of running on such a device. Thus the question is how to check it?
It can be done using Display.getOrientation() or Display.getRotation() (for API level >= 8).
This method can help:--
public int getDeviceDefaultOrientation() {
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Configuration config = getResources().getConfiguration();
int rotation = windowManager.getDefaultDisplay().getRotation();
if ( ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
config.orientation == Configuration.ORIENTATION_LANDSCAPE)
|| ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
return Configuration.ORIENTATION_LANDSCAPE;
} else {
return Configuration.ORIENTATION_PORTRAIT;
}
}
config.orientation != Configuration.ORIENTATION_UNDEFINED
? –
Maraca orientation
and getRotation
are out of sync at some points in time. –
Shrader int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
–
Libradalibrarian Well, you can find out what current orientation is the way @Urboss said. You cannot get the layout (landscape/portrait) that way ofcourse, so you'll have to get the screen width/heigth to check if the current (be it changed or not, but you've checked that ;) ) position is landscape or portrait:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
wPix = dm.widthPixels;
hPix = dm.heightPixels;
(so if the rotation is 0 and you get landscape with above metrix, your device is default landscape. If the rotation is 90 degrees and you're portrait, the default is also landscape, and so on)
After hours and hours of trying to figure this out. It's not possible. However, the closest thing you can do is to set the orientation to "NOSENSOR"
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
What this will do is set your application to the natural orientation of the device. At this point you can get the height and width of the display using the DisplayMetrics class, and calculate if you are in landscape or portrait. After you then figure out if it's landscape or portrait, you can then do this
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_XXXXX);
Where XXXX is either LANDSCAPE or PORTRAIT.
The case where doing this may not work is if you have a slide out keyboard.
SCREEN_ORIENTATION_UNSPECIFIED
allows the activity orientation to be overridden by the user enabling auto screen rotation or by the system USER_ROTATION
setting value changing. –
Shrader Thanks to diyism's excellent answer above, I also added the logic to check the actual orientation position (landscape right, portrait, landscape left, portrait flipped): Here is the code:
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
//The coordinate-system is defined relative to the screen of the phone in its default orientation
int orientation = 0;
float roll=0;
float pitch=0;
switch (getWindowManager().getDefaultDisplay().getRotation()) {
case Surface.ROTATION_0:
roll=event.values[2];
pitch=event.values[1];
break;
case Surface.ROTATION_90:
roll=event.values[1];
pitch=-event.values[2];
break;
case Surface.ROTATION_180:
roll=-event.values[2];
pitch=-event.values[1];
break;
case Surface.ROTATION_270:
roll=-event.values[1];
pitch=event.values[2];
break;
}
if (pitch >= -45 && pitch < 45 && roll >= 45)
orientation = 0;
else if (pitch < -45 && roll >= -45 && roll < 45)
orientation = 1;
else if (pitch >= -45 && pitch < 45 && roll < -45)
orientation = 2;
else if (pitch >= 45 && roll >= -45 && roll < 45 )
orientation = 3;
if (m_nOrientation != orientation) { //orientation changed event
m_Inst.Debug(LOG_TAG,"onSensorChanged: orientation:" + orientation);
m_nOrientation = orientation;
// fire event for new notification, or update your interface here
}
}
This code is also posted here: http://www.pocketmagic.net/?p=2847
Here's my solution:
public class ActivityOrientationTest extends Activity {
private static final String TAG = "ActivityOrientationTest";
private int mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
private TextView mTextView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextView = (TextView)findViewById(R.id.text);
setDefaultOrientation();
}
private void setDefaultOrientation(){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
Display display;
display = getWindow().getWindowManager().getDefaultDisplay();
int rotation = display.getRotation();
int width = 0;
int height = 0;
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
Log.i(TAG, "Rotation is: 0 or 180");
width = display.getWidth();
height = display.getHeight();
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
Log.i(TAG, "Rotation is: 90 or 270");
width = display.getHeight();
height = display.getWidth();
break;
default:
break;
}
if(width > height){
Log.i(TAG, "Natural Orientation is landscape");
mTextView.setText("Natural Orientation is landscape");
mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
Log.i(TAG, "Natural Orientation is portrait");
mNaturalOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
mTextView.setText("Natural Orientation is portrait");
}
setRequestedOrientation(mNaturalOrientation);
}
Display.getRotation() is only supported in API level 8 or higher so if you need to support older devices you'll need to call Display.getOrientation().
public static boolean isDeviceDefaultOrientationLandscape(Activity a) {
WindowManager windowManager = (WindowManager) a.getSystemService(Context.WINDOW_SERVICE);
Configuration config = a.getResources().getConfiguration();
int rotation = windowManager.getDefaultDisplay().getRotation();
boolean defaultLandsacpeAndIsInLandscape = (rotation == Surface.ROTATION_0 ||
rotation == Surface.ROTATION_180) &&
config.orientation == Configuration.ORIENTATION_LANDSCAPE;
boolean defaultLandscapeAndIsInPortrait = (rotation == Surface.ROTATION_90 ||
rotation == Surface.ROTATION_270) &&
config.orientation == Configuration.ORIENTATION_PORTRAIT;
return defaultLandsacpeAndIsInLandscape || defaultLandscapeAndIsInPortrait;
}
@Urboss, it can't. You need to know the default orientation of the device first, because both methods return the changes based on it (I mean, if the default is portrait, the result you are looking for will be 1 or ROTATE_90 -so it is landscape-, but, if the default is landscape, the result is 0).
And as far as I know, finding the default orientation of the device is not trivial :(
Anybody can throw some light in this topic?
My solution(tested at HTC desire and SamSung galaxy tab 10.1):
private class compass_listener implements SensorEventListener
{public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event)
{float roll=0;
float pitch=0;
switch (((Activity)context).getWindowManager().getDefaultDisplay().getRotation())
{case Surface.ROTATION_0:
roll=event.values[2];
pitch=event.values[1];
break;
case Surface.ROTATION_90:
roll=event.values[1];
pitch=-event.values[2];
break;
case Surface.ROTATION_180:
roll=-event.values[2];
pitch=-event.values[1];
break;
case Surface.ROTATION_270:
roll=-event.values[1];
pitch=event.values[2];
break;
}
JSONObject json=new JSONObject();
try
{json.put("roll", roll);
json.put("pitch", pitch);
json.put("azimuth", event.values[0]);
}
catch (JSONException e)
{throw new RuntimeException(e);
}
java_2_js(webview, "intent_compass_change", json);
}
}
You can define by using rotation and orientation. No need to use sensors or any listeners, just call isDefaultLandscape method whenever you wish.
private boolean isDefaultLandscape(final Context context)
{
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = display.getRotation();
int orientation = context.getResources().getConfiguration().orientation;
switch (rotation)
{
case Surface.ROTATION_180:
case Surface.ROTATION_0:
{
return orientation == Configuration.ORIENTATION_LANDSCAPE;
}
default:
{
return orientation == Configuration.ORIENTATION_PORTRAIT;
}
}
}
For fellow Xamarin developers, here is a version of this check in C#:
var orientation = ContextHelper.Current.Resources.Configuration.Orientation;
if (orientation == Android.Content.Res.Orientation.Undefined)
{
//unknown, you can provide special handling for this case
}
var isLandscape = false;
var rotation = windowManager.DefaultDisplay.Rotation;
switch (rotation)
{
case SurfaceOrientation.Rotation0:
case SurfaceOrientation.Rotation180:
isLandscape = orientation == Android.Content.Res.Orientation.Landscape;
break;
default:
isLandscape = orientation == Android.Content.Res.Orientation.Portrait;
break;
}
Here's what I've been using:
/**
* returns the natural orientation of the device: Configuration.ORIENTATION_LANDSCAPE or Configuration.ORIENTATION_PORTRAIT .<br/>
* The result should be consistent no matter the orientation of the device
*/
public static int getScreenNaturalOrientation(@NonNull final Context context) {
//based on : https://mcmap.net/q/36886/-how-to-check-device-natural-default-orientation-on-android-i-e-get-landscape-for-e-g-motorola-charm-or-flipout
final WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Configuration config = context.getResources().getConfiguration();
final int rotation = windowManager.getDefaultDisplay().getRotation();
if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
config.orientation == Configuration.ORIENTATION_LANDSCAPE)
|| ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
config.orientation == Configuration.ORIENTATION_PORTRAIT))
return Configuration.ORIENTATION_LANDSCAPE;
else
return Configuration.ORIENTATION_PORTRAIT;
}
You can also get the natural resolution as such:
/**
* returns the natural screen size (in pixels). The result should be consistent no matter the orientation of the device
*/
public static
@NonNull
Point getScreenNaturalSize(@NonNull final Context context) {
if (sNaturalScreenSize != null)
return sNaturalScreenSize;
final int screenNaturalOrientation = getScreenNaturalOrientation(context);
final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
final int currentOrientation = context.getResources().getConfiguration().orientation;
if (currentOrientation == screenNaturalOrientation)
return sNaturalScreenSize = new Point(displayMetrics.widthPixels, displayMetrics.heightPixels);
//noinspection SuspiciousNameCombination
return sNaturalScreenSize = new Point(displayMetrics.heightPixels, displayMetrics.widthPixels);
}
After some googling, I found a blog mentioned that while executing wm size
command through adb shell, it will always return the unrotated "natural" screen resolution, and then the author hunted down to here:
mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
Context.WINDOW_SERVICE));
and here:
mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
So, it seems that Android actually knows the initial/unrotated/"natural" screen size, but, it just doesn't want the app to know it? I'm confused...
its very simple to solve this
int orient=this.getResources().getConfiguration().orientation;
if it return 1 or 2
1 is portrait 2 is landscape
It can be done using Display.getOrientation() or Display.getRotation() (for API level >= 8).
© 2022 - 2024 — McMap. All rights reserved.