¿Cómo salimos del modo Picture-In-Picture?

8 minutos de lectura

Avatar de usuario de CommonsWare
CommonsWare

Tenemos enterPictureInPictureMode() para mover una actividad de su forma actual a una representación de imagen en imagen.

¿Cuál es el medio por el cual revertimos eso, devolviendo la actividad a su estado normal, además de destruir la actividad? No hay exitPictureInPictureMode(), leavePictureInPictureMode()o janeGetMeOffThisCrazyPictureInPictureModeThing() método en Activityy la documentación no parece cubrir una alternativa.

Estoy interesado en una solución para Android O, para el modo de imagen en imagen en dispositivos móviles, aunque si eso también funciona para Android TV, ¡maravilloso!

ACTUALIZACIÓN 2017-04-08: Si lo que quieres es volver al modo normal cuando el usuario haga clic en el botón X para salir del modo de imagen en imagen, puedes hacer algo como esto:

  @Override
  public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode);

    if (!isInPictureInPictureMode) {
      getApplication().startActivity(new Intent(this, getClass())
        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
    }
  }

Los bits clave son para llamar startActivity() para iniciar la actividad actual de nuevo con FLAG_ACTIVITY_REORDER_TO_FRONT. Con un singleTask actividad, necesita llamar a eso en algún no-Activity contexto, como el Application único. Esto no parece desencadenar onStop() o onStart()pero activa onNewIntent() (con lo que sea Intent pasas a startActivity()).

  • ¿Estás siguiendo el Uso de una sola actividad de reproducción para PIP ¿recomendación?

    – ianhanniballake

    02/04/2017 a las 23:11

  • @ianhanniballake: Sí. Sin embargo, eso no resuelve mi preocupación. No estoy buscando cambiar el contenido. Simplemente quiero volver a expandir el contenido a su tamaño original, sin interrumpir lo que está pasando. Por ejemplo, el usuario decide ingresar al modo PiP, se da cuenta de que el video es demasiado pequeño y desea expandirlo nuevamente.

    – CommonsWare

    02/04/2017 a las 23:13


  • Sí, no existen métodos como los que mencionaste. No trabajé mucho en PiP, pero podrías usar onPictureInPictureModeChanged para rastrear eventos de cambio de modo normal y PIP.

    -Pravin Divraniya

    5 de abril de 2017 a las 9:18


  • gran pregunta, me hizo visitar — Soporte multiventana menciona imagen en imagen en la televisión y ventana dividida para dispositivos portátiles, como sinónimos… también, me preguntaba, ¿no se volvería loca Jane si Tom, Dick y Harry desarrollaran aplicaciones que anulen entre sí forzando/abusando de JaneEscapeLoopPiP, entonces? Probablemente sea mejor dejar esa parte a la entrada/acción del usuario. suena como proporcionar un método ‘disconnectCall’ a la API de telefonía, cuando el usuario está en una conferencia

    – Pararth

    7 de abril de 2017 a las 7:06


  • @CommonsWare, suerte para resolver su problema.

    – Anchit Mittal

    27 de agosto de 2018 a las 10:44

  1. Mover la actividad al fondo

    activity.moveTaskToBack(false /* nonRoot */);
    
  2. restaurar la actividad al frente

    Intent startIntent = new Intent(PipActivity.this, PipActivity.class);
    startIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    activity.startActivity(startIntent);
    

  • Este patrón parece usarse para ventanas múltiples. Espero que esto ayude, no pude probarlo yo mismo porque todas las imágenes de mi emulador están fallando con “IllegalStateException: enterPictureInPictureMode: Device not support picture-in-picture mode”…

    – rds

    7 abr 2017 a las 23:37

  • ¡Eso es tortuoso! Desafortunadamente, estoy teniendo dificultades para obtener moveTaskToBack() trabajar. La actividad de PiP es singleTask (según los documentos). moveTaskToBack() parece afectar la tarea original de la aplicación, no la tarea de la actividad de imágenes incrustadas. Probablemente también necesite hacer este truco. Seguiré investigando esto, ya que su enfoque parece prometedor. ¡Gracias!

    – CommonsWare

    8 de abril de 2017 a las 0:17

  • Acabo de probar esta solución, y onDestroy() se llama, por lo tanto, no responde a su pregunta. De hecho, se llama dos veces: una vez en enterPictureInPicture, una vez cuando se inicia la intención, a pesar de singleTask y FLAG_ACTIVITY_REORDER_TO_FRONT.

    – rds

    10 de abril de 2017 a las 8:36

  • Le concedo a esta respuesta la recompensa, ya que es lo más cercano a tener una solución. No lo acepto, ya que no es realmente una solución. 🙂 ¡Gracias de nuevo!

    – CommonsWare

    11 de abril de 2017 a las 22:43

  • Tengo un problema, estoy en el modo de imagen en imagen, ahora hago clic en pip y luego se muestra un cuadrado blanco para maximizarlo, pero en la parte inferior, el botón de reproducción y pausa muestra el lado del video/exoplayer, cómo mostrar el botón de reproducción y pausa en el centro como blanco caja para mezclar.

    –Gyan Swaroop Awasthi

    15 de septiembre a las 11:33

Avatar de usuario de Saeed Masoumi
saeed masoumi

Yo tuve el mismo problema:

  • MainActivity abre VideoPlayerActivity que tiene el modo PIP habilitado.
  • Presione el botón Atrás para ir al modo PIP.
  • Vuelva a pulsar el botón Atrás hasta que salga de MainActivity.
  • Presiona cerrar (X) en la ventana PIP.
  • Abrir aplicación, se abrirá VideoPlayerActivity.

Si bien ninguna de las soluciones anteriores funciona para mí, descubrí que la única forma de escuchar X el botón es anular onStop.

Cuando la actividad se restablece desde PIP, onResume y onPictureInPictureModeChanged son llamados, cuando el X se hace clic en el botón, el onStop y onPictureInPictureModeChanged son llamados.

Así que traté de llamar finish() en el interior onPictureInPictureModeChanged cuando el onStop ya se llama.

override fun onStop() {
    super.onStop()
    onStopCalled = true
}

override fun onResume() {
    super.onResume()
    onStopCalled = false
}

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
        if (isInPictureInPictureMode) {
            // ...
        } else {
            if (onStopCalled) {
                finish()
            }
        }
    }

  • ¿Está garantizado? onStop el método será llamado antesonPictureInPictureModeChanged ? De alguna manera, en algunos dispositivos (con android 8 y 9), el onPictureInPictureModeChanged se llama antes onStop, impidiéndonos terminar la actividad. He estado luchando con esto durante días.

    – Tiago Pereira17

    22 de abril de 2020 a las 8:58

  • @ TiagoPereira17 Sé que ha pasado un tiempo, pero ¿alguna idea de si pudo encontrar alguna solución para esos dispositivos?

    – mehul bisht

    20 de abril a las 6:04

No creo que la actividad pueda decidir salir del modo Imagen en imagen.

Desde el Documento de vista previa de Android O API:

La actividad que ingresa al modo PIP pasa al estado de pausa, pero permanece iniciada. Si el usuario toca la actividad PIP, el sistema muestra un menú para que el usuario interactúe; los eventos sin contacto llegan a la actividad mientras está en el estado PIP.

La actividad será notificada por onPictureInPictureModeChanged().

  • Nota: trabajo en Google (aunque no en Android) y tampoco pude encontrar ninguna llamada en el janeGetMeOffThisCrazyPictureInPictureModeThing() o método similar.

    – rds

    7 abr 2017 a las 17:42


  • La actividad debería poder salir del modo PiP: simplemente finish() la actividad y crear una nueva instancia. Incluso con las transiciones, es probable que esto provoque problemas en la interfaz de usuario, que es lo que espero que tengamos una API para evitar. ¡Gracias, sin embargo!

    – CommonsWare

    07/04/2017 a las 17:51

  • Y realmente no considero que destruir/recrear instancias sea lo mismo que cambiar de modo.

    – rds

    12 de abril de 2017 a las 16:19

  • FWIW, yo presentó una solicitud para agregar algo para este caso.

    – CommonsWare

    12 de abril de 2017 a las 16:21

  • @GustavoForeroCarvajal: Google rechazó la solicitud de función y no he jugado con PiP en un par de años, así que no sé si apareció algo. ¡Lo siento!

    – CommonsWare

    23 de julio de 2020 a las 17:01

He encontrado una manera 100% confiable de hacer esto.

  1. Selecciona el taskAffinity atributo para su actividad PIP en el manifiesto a algo como “com.package.pip”. No importa qué, solo tiene que ser diferente del nombre de su paquete, que es la afinidad de tarea predeterminada. Esto hará que se inicie en una pila completamente separada como si fuera otra aplicación.
  2. Siempre que desee salir de PIP, inícielo con startActivity(new Intent(this, PipActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) desde dentro de otra actividad.

Acabo de ver lo que sucede cuando la actividad principal de la aplicación está actualmente en modo PIP y la inicia desde el lanzador y pensé que podría replicar esto, y de hecho podría hacerlo.

Documentación oficial dice que la ventana PIP aparece con un menú que le permite cambiar a pantalla completa.

La ventana PIP es de 240×135 dp y se muestra en la capa superior en una de las cuatro esquinas de la pantalla, elegida por el sistema. El usuario puede abrir una Menú PIP que les permite alternar la ventana PIP a pantalla completa, o cierre la ventana PIP, manteniendo presionado el botón Inicio en el control remoto. Si comienza a reproducirse otro video en la pantalla principal, la ventana PIP se cierra automáticamente.

Y puede anular el evento de cambio de PIP para manejar los elementos de la interfaz de usuario cada vez que el usuario cambia el modo PIP.

enlace a onPictureInPictureModeChanged

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    if (isInPictureInPictureMode) {
        // Hide the controls in picture-in-picture mode.
        ...
    } else {
        // Restore the playback UI based on the playback status.
        ...
    }
}

  • Esas parecen ser las instrucciones para la TV. En un teléfono Android O (Nexus 5X), hay un botón de cierre que destruye la actividad. No hay control remoto. Mantener presionada la ventana le permite moverla. No parece haber un medio accesible para el usuario de restaurar la actividad al modo normal. Y nada de eso indica cómo, programáticamente, dejo el modo PiP, que es el núcleo de esta pregunta. ¡Gracias, sin embargo!

    – CommonsWare

    3 de abril de 2017 a las 0:21

Según las últimas respuestas de otro blog de stackoverflow https://stackoverflow.com/a/71797433/3842263, debería ser así. Funciona bien para mí.

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {

    if (getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
        //when user click on Close button of PIP this will trigger.
        finishAndRemoveTask();

    }
    else if (getLifecycle().getCurrentState() == Lifecycle.State.STARTED){
        //when PIP maximize this will trigger
    }
    super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}

  • Esas parecen ser las instrucciones para la TV. En un teléfono Android O (Nexus 5X), hay un botón de cierre que destruye la actividad. No hay control remoto. Mantener presionada la ventana le permite moverla. No parece haber un medio accesible para el usuario de restaurar la actividad al modo normal. Y nada de eso indica cómo, programáticamente, dejo el modo PiP, que es el núcleo de esta pregunta. ¡Gracias, sin embargo!

    – CommonsWare

    3 de abril de 2017 a las 0:21

¿Ha sido útil esta solución?