- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
来自 Multi-Window documentation :
Disabled features in multi-window mode
Certain features are disabled or ignored when a device is in multi-window mode, because they don’t make sense for an activity which may be sharing the device screen with other activities or apps. Such features include:
- Some System UI customization options are disabled; for example, apps cannot hide the status bar if they are not running in full-screen mode.
- The system ignores changes to the android:screenOrientation attribute.
我知道对于大多数应用来说,区分纵向和横向模式是没有意义的,但是我正在开发包含相机 View 的 SDK,用户可以进行他们希望的任何 Activity - 包括支持多窗口的 Activity 模式。问题是相机 View 包含显示相机预览的 SurfaceView/TextureView,为了在所有 Activity 方向上正确显示预览,需要了解正确的 Activity 方向,以便可以正确旋转相机预览。
问题是我的代码通过检查当前配置方向(纵向或横向)和当前屏幕旋转来计算正确的 Activity 方向。问题是在多窗口模式下,当前配置方向并不能反射(reflect)真实的 Activity 方向。这会导致相机预览旋转 90 度,因为 Android 报告的配置与方向不同。
我目前的解决方法是检查请求的 Activity 方向并将其用作基础,但这有两个问题:
即使在多窗口配置中,是否有任何方法可以稳健地计算正确的 Activity 方向?
这是我目前使用的代码(请参阅有问题的部分的注释):
protected int calculateHostScreenOrientation() {
int hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
int rotation = getDisplayOrientation(wm);
boolean activityInPortrait;
if ( !isInMultiWindowMode() ) {
activityInPortrait = (mConfigurationOrientation == Configuration.ORIENTATION_PORTRAIT);
} else {
// in multi-window mode configuration orientation can be landscape even if activity is actually in portrait and vice versa
// Try determining from requested orientation (not entirely correct, because the requested orientation does not have to
// be the same as actual orientation (when they differ, this means that OS will soon rotate activity into requested orientation)
// Also not correct because, according to https://developer.android.com/guide/topics/ui/multi-window.html#running this orientation
// is actually ignored.
int requestedOrientation = getHostActivity().getRequestedOrientation();
if ( requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT ) {
activityInPortrait = true;
} else if ( requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE ) {
activityInPortrait = false;
} else {
// what to do when requested orientation is 'behind', 'sensor', 'user', etc. ?!?
activityInPortrait = true; // just guess
}
}
if ( activityInPortrait ) {
Log.d(this, "Activity is in portrait");
if (rotation == Surface.ROTATION_0) {
Log.d(this, "Screen orientation is 0");
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else if (rotation == Surface.ROTATION_180) {
Log.d(this, "Screen orientation is 180");
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
} else if (rotation == Surface.ROTATION_270) {
Log.d(this, "Screen orientation is 270");
// natural display rotation is landscape (tablet)
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else {
Log.d(this, "Screen orientation is 90");
// natural display rotation is landscape (tablet)
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
}
} else {
Log.d(this, "Activity is in landscape");
if (rotation == Surface.ROTATION_90) {
Log.d(this, "Screen orientation is 90");
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (rotation == Surface.ROTATION_270) {
Log.d(this, "Screen orientation is 270");
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
} else if (rotation == Surface.ROTATION_0) {
Log.d(this, "Screen orientation is 0");
// natural display rotation is landscape (tablet)
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else {
Log.d(this, "Screen orientation is 180");
// natural display rotation is landscape (tablet)
hostScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
}
}
return hostScreenOrientation;
}
private int getDisplayOrientation(WindowManager wm) {
if (DeviceManager.getSdkVersion() < 8) {
return wm.getDefaultDisplay().getOrientation();
}
return wm.getDefaultDisplay().getRotation();
}
private boolean isInMultiWindowMode() {
return Build.VERSION.SDK_INT >= 24 && getHostActivity().isInMultiWindowMode();
}
protected Activity getHostActivity() {
Context context = getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
return null;
}
编辑:我也将此事报告给 Android issue tracker .
最佳答案
我不知道这是否应该被视为一种解决方案或只是一种解决方法。
正如您所说,您的问题来自 Android N 及其多窗口模式。当应用程序处于多窗口中时,您的 Activity
不会绑定(bind)到完整的显示尺寸。这重新定义了 Activity
方向的概念。报价 Ian Lake :
Turns out: “portrait” really just means the height is greater than the width and “landscape” means the width is greater than the height. So it certainly makes sense, with that definition in mind, that your app could transition from one to the other while being resized.
所以 Activity
方向改变和设备物理旋转之间不再存在联系。 (我认为现在唯一合理使用 Activity 方向更改是为了更新您的资源。)
由于您对设备尺寸感兴趣,just get its DisplayMetrics
.引用文档,
If requested from non-Activity context metrics will report the size of the entire display based on current rotation and with subtracted system decoration areas.
所以解决办法是:
final Context app = context.getApplicationContext();
WindowManager manager = (WindowManager) app.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
boolean portrait = height >= width;
当设备倾斜时,宽度和高度值将交换(或多或少)。
如果可行,我会每次都亲自运行它,删除 isInMultiWindowMode()
分支,因为
isInMultiWindowMode()
described by CommonsWare 的竞争条件关于android - 如何在 Android N 多窗口模式下确定正确的设备方向?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41304917/
我是一名优秀的程序员,十分优秀!