От Multi-Window documentation:Как определить правильную ориентацию устройства в многоэкранном режиме Android N?
отключенные функции в режиме нескольких окон
Некоторые функции отключены или игнорируются, когда устройство находится в режиме нескольких окон, потому что они не имеют смысла для деятельности которые могут совместно использовать экран устройства с другими действиями или приложениями. Такие особенности включают в себя:
- Некоторые параметры настройки пользовательского интерфейса системы отключены; например, приложения не могут скрыть строку состояния, если они не работают в полноэкранном режиме.
- Система игнорирует изменения атрибута android: screenOrientation.
Я понимаю, что для большинства приложений это не имеет смысла отличие между портретным и ландшафтным режимами, однако я работаю над SDK, который содержит изображение с камеры, которые пользователь может поставить на любую деятельность, они хотят - в том числе деятельность который поддерживает многооконный режим. Проблема в том, что просмотр камеры содержит SurfaceView/TextureView, который отображает предварительный просмотр камеры и для правильного отображения предварительного просмотра во всех ориентациях деятельности, для правильного поворота камеры необходимо знать правильную ориентацию активности.
Проблема в том, что мой код, который вычисляет правильную ориентацию активности, исследует текущую конфигурационную ориентацию (портретную или альбомную) и текущее вращение экрана. Проблема в том, что в режиме многооконного режима ориентация текущей конфигурации не отражает реальную ориентацию активности. Это приводит к тому, что просмотр камеры поворачивается на 90 градусов, потому что Android сообщает о другой конфигурации, чем ориентация.
Мой текущий обходной путь состоит в проверке запрашиваемой ориентации деятельности и использовать его в качестве основы, но есть две проблемы с этим:
- запрашиваемый ориентационная деятельность не должна отражать фактическую ориентацию деятельности (то есть запрос может по-прежнему не выполняться)
- Запрошенная ориентация деятельности может быть «позади», «датчик», «пользователь» и т. д., которая не раскрывает никакой информации о текущей ориентации активности.
- Согласно documentation, ориентация экрана фактически игнорируется в режиме нескольких окон, так и 1. 2. просто не будет работать
Есть ли способ, чтобы решительно рассчитать правильную ориентацию деятельности даже в мульти-окна конфигурация?
Вот мой код, который я в настоящее время использую (см комментарии для проблемных частей):
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;
}
EDIT: Я сообщил об этом также Android issue tracker.
Обратите внимание, что ['isInMultiWindowMode()' имеет состояние гонки) (https://commonsware.com/blog/2016/06/07/isinmultiwindowmode-race-condition.html), добавляя к проблеме. – CommonsWare
Для полноты я добавляю здесь [отчет о проблеме в нашем SDK] (https://github.com/PDF417/pdf417-android/issues/19), который также содержит скриншоты и некоторые обсуждения по теме. – DoDo
Не могли бы вы просто посмотреть размеры экрана? [getMetrics()] (https://developer.android.com/reference/android/view/Display.html#getMetrics (android.util.DisplayMetrics)): «Если запрошено из показателей неактивности, будет сообщаться размер весь экран, основанный на текущем вращении и с вычитаемыми областями оформления системы ». Затем сравните ширину и высоту. – natario