gpt4 book ai didi

android - 如何在 Android N 多窗口模式下确定正确的设备方向?

转载 作者:IT老高 更新时间:2023-10-28 22:22:59 25 4
gpt4 key购买 nike

来自 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 方向并将其用作基础,但这有两个问题:

  1. 请求的 Activity 方向不必反射(reflect)实际的 Activity 方向(即请求可能仍未完成)
  2. 请求的 Activity 方向可以是“后面”、“传感器”、“用户”等,不会透露有关当前 Activity 方向的任何信息。
  3. 根据documentation , 屏幕方向实际上在多窗口模式下被忽略了,所以 1. 和 2. 不起作用

即使在多窗口配置中,是否有任何方法可以稳健地计算正确的 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() 分支,因为

  • 不贵
  • 我们的假设也适用于非多窗口模式
  • 它可能会很好地与任何其他 future 类型的模式
  • 您避免了 isInMultiWindowMode() described by CommonsWare 的竞争条件

关于android - 如何在 Android N 多窗口模式下确定正确的设备方向?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41304917/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com