This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. AI Assistant (Multiple Documents, ViewPager)

AI-powered document chat across multiple documents using ViewPager2 and PdfFragment. Requires the AI Assistant demo server running locally.


/*
* Copyright © 2025-2026 PSPDFKit GmbH. All rights reserved.
*
* The PSPDFKit Sample applications are licensed with a modified BSD license.
* Please see License for details. This notice may not be removed from this file.
*/
package com.pspdfkit.catalog.examples.kotlin
import android.content.Context
import android.content.Intent
import android.graphics.RectF
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import com.pspdfkit.ai.showAiAssistant
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.catalog.SdkExample.Companion.WELCOME_DOC
import com.pspdfkit.catalog.examples.kotlin.AiAssistantComposeActivity.Companion.PREFERENCES_NAME
import com.pspdfkit.catalog.examples.kotlin.AiAssistantComposeActivity.Companion.PREF_AI_IP_ADDRESS
import com.pspdfkit.catalog.examples.kotlin.AiAssistantViewPagerActivity.Companion.EXTRA_CONFIGURATION
import com.pspdfkit.catalog.utils.JwtGenerator
import com.pspdfkit.configuration.PdfConfiguration
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.document.providers.AssetDataProvider
import com.pspdfkit.document.providers.getDataProviderFromDocumentSource
import com.pspdfkit.ui.DocumentDescriptor
import com.pspdfkit.ui.PdfFragment
import com.pspdfkit.utils.getSupportParcelableExtra
import io.nutrient.domain.ai.AiAssistant
import io.nutrient.domain.ai.AiAssistantProvider
/**
* Shows how to implement AI Assistant chat supporting multiple documents analysis and interaction inside a ViewPager.
*/
class AiAssistantViewPagerExample(context: Context) :
SdkExample(
context,
R.string.aiAssistantViewPagerExampleTitle,
R.string.aiAssistantViewPagerExampleDescription,
) {
override val launchRequirements = setOf(SdkExample.LaunchRequirement.AI_ASSISTANT_SERVER)
override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
val intent = Intent(context, AiAssistantViewPagerActivity::class.java)
configuration.setAiAssistantEnabled(true)
intent.putExtra(
EXTRA_CONFIGURATION,
configuration.build().configuration,
)
context.startActivity(intent)
}
}
class AiAssistantViewPagerActivity :
AppCompatActivity(),
AiAssistantProvider {
private lateinit var pager: ViewPager2
private lateinit var fragmentAdapter: ViewPagerPdfFragmentAdapter
private var selectedPage = 0
private val sessionId = AiAssistantViewPagerActivity::class.java.simpleName
var ipAddressValue = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_pager_ai_assistant)
findViewById<Toolbar>(R.id.main_toolbar).let {
it.setOnMenuItemClickListener { _ ->
showAiAssistant(this@AiAssistantViewPagerActivity)
true
}
}
val preferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE)
ipAddressValue = preferences.getString(PREF_AI_IP_ADDRESS, "") ?: ""
fragmentAdapter = ViewPagerPdfFragmentAdapter(this@AiAssistantViewPagerActivity, documentDescriptors)
pager =
findViewById<ViewPager2>(R.id.view_pager).apply {
this.adapter = fragmentAdapter
isUserInputEnabled = false
registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
selectedPage = position // Save the selected page.
}
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
// Refresh the fragment when the user stops scrolling.
if (state == 0) {
supportFragmentManager.findFragmentByTag("f$selectedPage")?.let {
if (it is PdfFragment) it.refreshPages()
}
}
}
},
)
}
TabLayoutMediator(findViewById(R.id.tab_layout), pager) { tab, position ->
tab.text = "Tab ${position + 1}"
}.attach()
}
companion object {
val assetFiles = listOf(WELCOME_DOC, "Scientific-paper.pdf", "Teacher.pdf", "The-Cosmic-Context-for-Life.pdf")
internal const val EXTRA_CONFIGURATION = "Nutrient.AIAssistantViewPagerActivity.configuration"
}
var assistant: AiAssistant? = null
override fun getAiAssistant(): AiAssistant = assistant ?: initialiseAiAssistant().also {
assistant = it
}
val documentDescriptors =
assetFiles.map {
DocumentDescriptor.fromDataProviders(listOf(AssetDataProvider(it)), listOf(), listOf())
}
fun initialiseAiAssistant(): AiAssistant = com.pspdfkit.ai.createAiAssistant(
context = this,
documentsDescriptors = documentDescriptors,
serverUrl = "http://$ipAddressValue:4000",
sessionId = sessionId,
jwtToken = { documentIds ->
JwtGenerator.generateJwtToken(
this@AiAssistantViewPagerActivity,
claims =
mapOf(
"document_ids" to documentIds,
"session_ids" to listOf(sessionId),
"request_limit" to
mapOf(
"requests" to 160,
"time_period_s" to 1000 * 60 * 10,
),
),
)
},
)
@OptIn(ExperimentalStdlibApi::class)
override fun navigateTo(documentRect: List<RectF>, pageIndex: Int, documentIndex: Int) {
val fragment = fragmentAdapter.fragments[documentIndex]
pager.setCurrentItem(documentIndex, true)
fragment.highlight(this@AiAssistantViewPagerActivity, documentRect, pageIndex)
}
}
/** Minimal [FragmentStateAdapter] to provide [PdfFragment] for each page. */
class ViewPagerPdfFragmentAdapter(val activity: AiAssistantViewPagerActivity, descriptors: List<DocumentDescriptor>) :
FragmentStateAdapter(activity) {
val configuration =
activity.intent.getSupportParcelableExtra(EXTRA_CONFIGURATION, PdfConfiguration::class.java)
?: throw IllegalStateException("Activity Intent was missing configuration extra!")
override fun getItemCount(): Int = fragments.size
val fragments =
descriptors.map {
val dataProvider = it.documentSource.getDataProviderFromDocumentSource()
PdfFragment.newInstance(dataProvider, null, configuration)
}
override fun createFragment(position: Int): Fragment = fragments[position]
}

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.