Écran "Récents"

L'écran "Actions récentes", également appelé écran d'aperçu, liste des tâches récentes ou écran des applications récentes, est une interface utilisateur au niveau du système qui liste les activités et les tâches auxquelles l'utilisateur a accédé récemment. L'utilisateur peut parcourir la liste, sélectionner une tâche à reprendre ou supprimer une tâche de la liste en la balayant.

L'écran "Récents" utilise un modèle axé sur les documents, introduit dans Android 5.0 (niveau d'API 21), dans lequel plusieurs instances de la même activité contenant différents documents peuvent apparaître sous forme de tâches sur l'écran "Récents". Par exemple, Google Drive peut avoir une tâche pour chacun des nombreux documents Google. Chaque document apparaît sous forme de tâche sur l'écran "Récents" :

L'écran "Récents" affichant deux documents Google Drive, chacun représenté comme une tâche distincte.

Un autre exemple courant est celui où l'utilisateur utilise son navigateur et appuie sur Partager > Gmail. L'écran Composer de l'application Gmail s'affiche. Si vous appuyez sur le bouton "Récents" à ce moment-là, Chrome et Gmail s'affichent en tant que tâches distinctes :

L'écran "Récents" affichant Chrome et Gmail s'exécutant en tant que tâches distinctes.

Normalement, vous laissez le système définir la façon dont vos tâches et activités sont représentées sur l'écran "Récents". Vous n'avez pas besoin de modifier ce comportement. Toutefois, votre application peut déterminer comment et quand les activités apparaissent dans l'écran "Récents".

La classe ActivityManager.AppTask vous permet de gérer les tâches, et les indicateurs d'activité de la classe Intent vous permettent de spécifier quand une activité est ajoutée ou supprimée de l'écran "Récents". De plus, les attributs <activity> vous permettent de définir le comportement dans le fichier manifeste.

Ajouter des tâches à l'écran "Récents"

L'utilisation des indicateurs de la classe Intent pour ajouter une tâche vous permet de mieux contrôler le moment et la manière dont un document est ouvert ou rouvert sur l'écran "Récents". Lorsque vous utilisez les attributs <activity>, vous pouvez choisir d'ouvrir systématiquement le document dans une nouvelle tâche ou de réutiliser une tâche existante pour le document.

Utiliser l'option "Intent" pour ajouter une tâche

Lorsque vous créez un document pour votre activité, vous appelez la méthode startActivity() en lui transmettant l'intent qui lance l'activité. Pour insérer une pause logique afin que le système traite votre activité comme une nouvelle tâche dans l'écran "Récents", transmettez l'indicateur FLAG_ACTIVITY_NEW_DOCUMENT dans la méthode addFlags() de l'Intent qui lance l'activité.

Si vous définissez l'indicateur FLAG_ACTIVITY_MULTIPLE_TASK lorsque vous créez le document, le système crée toujours une tâche avec l'activité cible comme racine. Ce paramètre permet d'ouvrir le même document dans plusieurs tâches. Le code suivant montre comment l'activité principale procède et démarre la nouvelle activité à partir de votre composable :

private fun newDocumentIntent(context: Context): Intent =
    Intent(context, NewDocumentActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
        putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++)
    }

@Composable
fun CreateDocumentButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            val intent = newDocumentIntent(context)
            // Add FLAG_ACTIVITY_MULTIPLE_TASK if needed based on state
            context.startActivity(intent)
        }
    ) {
        Text("Create New Document")
    }
}

Lorsque l'activité principale lance une nouvelle activité, le système recherche dans les tâches existantes celle dont l'intent correspond au nom du composant d'intent et aux données d'intent de l'activité. Si la tâche n'est pas trouvée ou si l'intent contient l'indicateur FLAG_ACTIVITY_MULTIPLE_TASK, une nouvelle tâche est créée avec l'activité comme racine.

Si le système trouve une tâche dont l'intent correspond au nom du composant d'intent et aux données d'intent, il place cette tâche au premier plan et transmet le nouvel intent à onNewIntent(). La nouvelle activité obtient l'intent et crée un document dans l'écran "Récents", comme illustré dans l'exemple suivant :

class DocumentCentricActivity : ComponentActivity() {
    private var documentState by mutableStateOf(
        DocumentState(
            count = 0,
            textResId = R.string.hello_new_document_counter
        )
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val initialCount = intent.getIntExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0)

        documentState = documentState.copy(count = initialCount)

        setContent {
            MaterialTheme {
                DocumentScreen(
                    count = documentState.count,
                    textResId = documentState.textResId
                )
            }
        }
    }

    override fun onNewIntent(newIntent: Intent) {
        super.onNewIntent(newIntent)
        // If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this Activity is reused.
        documentState = documentState.copy(
            textResId = R.string.reusing_document_counter
        )
    }

    data class DocumentState(val count: Int, @StringRes val textResId: Int)

    companion object {
        const val KEY_EXTRA_NEW_DOCUMENT_COUNTER = "KEY_EXTRA_NEW_DOCUMENT_COUNTER"
    }
}

@Composable
fun DocumentScreen(count: Int, @StringRes textResId: Int) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center
    ) {
        // UI reacts to whichever string resource ID was passed down
        Text(text = stringResource(id = textResId))
        Spacer(modifier = Modifier.height(8.dp))
        Text(text = "Counter: $count")
    }
}

Dans le code précédent, l'activité gère le routage au niveau de l'OS (onCreate et onNewIntent), tandis que la fonction @Composable n'est responsable que du rendu de l'UI en fonction de l'état fourni.

Utiliser l'attribut d'activité pour ajouter une tâche

Une activité peut également spécifier dans son fichier manifeste qu'elle se lance toujours dans une nouvelle tâche en utilisant l'attribut <activity> android:documentLaunchMode. Cet attribut présente quatre valeurs qui entraînent les effets suivants lorsque l'utilisateur ouvre un document avec l'application :

intoExisting
L'activité réutilise une tâche existante pour le document. Cela revient à définir l'option FLAG_ACTIVITY_NEW_DOCUMENT sans définir l'option FLAG_ACTIVITY_MULTIPLE_TASK, comme décrit dans la section Utiliser l'option Intent pour ajouter une tâche.
always
L'activité crée une tâche pour le document, même s'il est déjà ouvert. Utiliser cette valeur revient à définir les indicateurs FLAG_ACTIVITY_NEW_DOCUMENT et FLAG_ACTIVITY_MULTIPLE_TASK.
none
L'activité ne crée pas de tâche pour le document. L'écran "Recents" (Éléments récents) traite l'activité comme il le ferait par défaut. Il n'affiche qu'une seule tâche pour l'application, qui reprend à partir de la dernière activité appelée par l'utilisateur.
never
L'activité ne crée pas de tâche pour le document. Si vous définissez cette valeur, le comportement des indicateurs FLAG_ACTIVITY_NEW_DOCUMENT et FLAG_ACTIVITY_MULTIPLE_TASK est remplacé. Si l'un de ces éléments est défini dans l'intent et que l'écran "Recents" (Éléments récents) affiche une seule tâche pour l'application, celle-ci reprend à partir de la dernière activité appelée par l'utilisateur.

Supprimer des tâches

Par défaut, une tâche de document quitte automatiquement l'écran "Recents" (Éléments récents) lorsque son activité se termine. Vous pouvez ignorer ce comportement avec la classe ActivityManager.AppTask, avec un indicateur Intent ou avec un attribut <activity>.

Vous pouvez toujours exclure complètement une tâche de l'écran "Récents" en définissant l'attribut <activity> android:excludeFromRecents sur true.

Vous pouvez définir le nombre maximal de tâches que votre application peut inclure dans l'écran "Récents" en définissant l'attribut <activity> android:maxRecents sur une valeur entière. Lorsque le nombre maximal de tâches est atteint, la tâche utilisée le moins récemment disparaît de l'écran "Récents". La valeur par défaut est 16 et la valeur maximale est 50 (25 sur les appareils à faible mémoire). Les valeurs inférieures à 1 ne sont pas valides.

Utiliser la classe AppTask pour supprimer des tâches

Dans l'activité qui crée une tâche dans l'écran "Récents", vous pouvez spécifier quand supprimer la tâche et terminer toutes les activités associées en appelant la méthode finishAndRemoveTask() :

@Composable
fun RemoveTaskButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            // It is good practice to remove a document from the overview stack if not needed anymore.
            (context as? Activity)?.finishAndRemoveTask()
        }
    ) {
        Text("Remove from Recents")
    }
}

Conserver les tâches terminées

Si vous souhaitez conserver une tâche dans l'écran "Recents" (Éléments récents), même si son activité est terminée, transmettez l'indicateur FLAG_ACTIVITY_RETAIN_IN_RECENTS dans la méthode addFlags() de l'intent qui lance l'activité.

private fun newDocumentIntent() =
        Intent(this, NewDocumentActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                    android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
            putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement())
        }

Pour obtenir le même effet, définissez l'attribut <activity> android:autoRemoveFromRecents sur false. La valeur par défaut est true pour les activités liées aux documents et false pour les activités standards. L'utilisation de cet attribut remplace l'option FLAG_ACTIVITY_RETAIN_IN_RECENTS.

Activer le partage d'URL récentes (Pixel uniquement)

Sur les appareils Pixel équipés d'Android 12 ou version ultérieure, les utilisateurs peuvent partager des liens vers du contenu Web consulté récemment directement depuis l'écran "Récents". Après avoir consulté le contenu dans une application, l'utilisateur peut balayer l'écran pour accéder à l'écran "Récents" et trouver l'application dans laquelle il a consulté le contenu. Il peut ensuite appuyer sur le bouton de lien pour copier ou partager l'URL.

L'écran "Récents" avec un lien permettant de partager le contenu Web consulté récemment.

N'importe quelle application peut activer l'association aux applications récentes pour les utilisateurs en fournissant une UI Web et en remplaçant onProvideAssistContent(), comme illustré dans l'exemple suivant :

class MainActivity : ComponentActivity() {

    // Track the current URL as state so the UI can update it during navigation
    private var currentWebUri by mutableStateOf("https://example.com/home")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AppTheme {
                // Pass a lambda to your Compose UI so it can update the URL state
                // as the user navigates through your app.
                MainScreen(
                    onPageChanged = { newUrl -> currentWebUri = newUrl }
                )
            }
        }
    }

    override fun onProvideAssistContent(outContent: AssistContent) {
        super.onProvideAssistContent(outContent)

        // The system calls this when the user enters the Recents screen.
        // Provide the active URI tracked by the Compose state.
        outContent.webUri = Uri.parse(currentWebUri)
    }
}