plus pantalla moto dividida desactivar android camera android-camera android-7.0-nougat multi-window

pantalla - ¿Cómo determinar la orientación correcta del dispositivo en el modo multiventana de Android N?



pantalla dividida moto g5 (2)

No sé si esto debería considerarse una solución o simplemente una solución alternativa.

Como dices, tus problemas vienen con Android N y su modo de ventanas múltiples. Cuando la aplicación está en una ventana múltiple, su Activity no está vinculada a las dimensiones de la pantalla completa. Esto redefine el concepto de orientación de la Activity . Citando el lago Ian :

Resulta que: "retrato" realmente significa que la altura es mayor que el ancho y "paisaje" significa que el ancho es mayor que la altura. Por lo tanto, ciertamente tiene sentido, con esa definición en mente, que su aplicación podría pasar de una a otra mientras se redimensiona.

Por lo tanto, ya no existe un vínculo entre el cambio de orientación de la Activity y la rotación física del dispositivo. ( Creo que el único uso razonable de los cambios de orientación de la actividad ahora es actualizar sus recursos ) .

Ya que está interesado en las dimensiones del dispositivo, getMetrics() . Citando documentos,

Si se solicita desde un contexto que no sea de Actividad, las métricas informarán el tamaño de toda la pantalla en función de la rotación actual y con áreas de decoración del sistema restadas.

Así que la solución es:

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;

Los valores de ancho y alto se intercambiarán (más o menos) cuando se incline el dispositivo.

Si esto funciona, personalmente lo ejecutaría cada vez, eliminando la rama isInMultiWindowMode() , porque

  • no es caro
  • Nuestras suposiciones se ubican también en el modo sin ventanas múltiples
  • Presumiblemente funcionará bien con cualquier otro tipo de modo futuro
  • evita la condición de carrera de isInMultiWindowMode() descrita por CommonsWare

De la documentación de ventanas múltiples :

Funciones deshabilitadas en modo multi-ventana

Ciertas funciones se desactivan o ignoran cuando un dispositivo está en modo de ventanas múltiples, porque no tienen sentido para una actividad que puede estar compartiendo la pantalla del dispositivo con otras actividades o aplicaciones. Tales características incluyen:

  • Algunas opciones de personalización de la IU del sistema están deshabilitadas; por ejemplo, las aplicaciones no pueden ocultar la barra de estado si no se ejecutan en modo de pantalla completa.
  • El sistema ignora los cambios en el atributo android: screenOrientation.

Entiendo que para la mayoría de las aplicaciones no tiene sentido distinguir entre los modos vertical y horizontal, sin embargo, estoy trabajando en el SDK que contiene la vista de la cámara que el usuario puede poner en cualquier actividad que desee, incluida la actividad que admite el modo de ventanas múltiples. El problema es que la vista de la cámara contiene SurfaceView / TextureView que muestra la vista previa de la cámara y para mostrarla correctamente en todas las orientaciones de actividad, se requiere conocimiento sobre la orientación correcta de la actividad para que la vista previa de la cámara se gire correctamente.

El problema es que mi código que calcula la orientación correcta de la actividad mediante el examen de la orientación de la configuración actual (vertical u horizontal) y la rotación actual de la pantalla. El problema es que en el modo de ventanas múltiples, la orientación de la configuración actual no refleja la orientación de la actividad real. Esto se traduce entonces en que la vista previa de la cámara se gira 90 grados porque Android informa una configuración diferente a la orientación.

Mi solución actual es verificar la orientación de la actividad solicitada y usar eso como base, pero hay dos problemas con eso:

  1. la orientación de la actividad solicitada no tiene que reflejar la orientación de la actividad real (es decir, la solicitud aún puede no cumplirse)
  2. la orientación de la actividad solicitada puede ser ''atrás'', ''sensor'', ''usuario'', etc. que no revela ninguna información sobre la orientación de la actividad actual.
  3. Según la documentation , la orientación de la pantalla se ignora en el modo de ventanas múltiples, por lo que 1. y 2. simplemente no funcionan

¿Hay alguna forma de calcular de forma robusta la orientación correcta de la actividad incluso en la configuración de múltiples ventanas?

Aquí está mi código que utilizo actualmente (ver comentarios para partes problemáticas):

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; }

EDITAR: He reportado esto también al rastreador de problemas de Android .


Pensé que podría utilizar el acelerómetro para detectar dónde está "abajo" y, por lo tanto, la orientación del teléfono. El ingeniero Guy explica que esa es la forma en que el teléfono lo hace.

Busqué aquí en SO para encontrar una forma de hacerlo y encontré esta respuesta . Básicamente, debe verificar cuál de los 3 acelerómetros detecta el componente más significativo de la fuerza gravitacional, que usted sabe es aproximadamente 9.8 m / s² cerca del suelo de la tierra. Aquí está el fragmento de código de él:

private boolean isLandscape; mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER),1000000); private final SensorEventListener mSensorListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent mSensorEvent) { float X_Axis = mSensorEvent.values[0]; float Y_Axis = mSensorEvent.values[1]; if((X_Axis <= 6 && X_Axis >= -6) && Y_Axis > 5){ isLandscape = false; } else if(X_Axis >= 6 || X_Axis <= -6){ isLandscape = true; } } public void onAccuracyChanged(Sensor sensor, int accuracy) { } };

Tenga cuidado ya que este código podría no funcionar en todas las situaciones, ya que debe tener en cuenta situaciones como estar en un tren de parada / aceleración o mover el teléfono rápidamente en un juego. Aquí tiene una página de órdenes de magnitud en la wiki para comenzar. Parece que estás a salvo con los valores que Khalil puso en su código (en su respuesta), pero tomaría precauciones adicionales e investigaría qué valores podrían generarse en los diferentes escenarios.

No es una idea perfecta, pero creo que siempre y cuando la API se construya de la manera en que lo es, sin permitirte obtener su orientación calculada, creo que es una solución alternativa beneficiosa.