Dynamically create Presentations when displays are added/removed
This commit is contained in:
parent
f9b7db0e44
commit
96404488f1
|
@ -5,9 +5,9 @@ import android.content.Intent
|
|||
import android.graphics.PorterDuff
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.hardware.display.DisplayManager.DisplayListener
|
||||
import android.media.MediaRouter
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.Display
|
||||
import android.view.Menu
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
|
@ -33,12 +33,11 @@ class MainActivity : AppCompatActivity() {
|
|||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var displayManager: DisplayManager
|
||||
private lateinit var mediaRouter: MediaRouter
|
||||
private val thumbnailWidth = 500
|
||||
private val thumbnailHeight = 700
|
||||
private var renderAutoCrop = true
|
||||
private var pagesPerLandscape = 3F
|
||||
private var presentation: MyPresentation? = null
|
||||
private val presentations = mutableMapOf<Int, MyPresentation>()
|
||||
private lateinit var pdfDocument: PdfDocument
|
||||
private val showPages = mutableListOf<Boolean>()
|
||||
private val thumbnailImageViews = mutableListOf<ImageView>()
|
||||
|
@ -46,18 +45,27 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
private val displayListener = object: DisplayListener {
|
||||
override fun onDisplayAdded(p0: Int) {
|
||||
updateDisplayText()
|
||||
reevaluateDisplay(p0)
|
||||
}
|
||||
|
||||
override fun onDisplayChanged(p0: Int) {
|
||||
updateDisplayText()
|
||||
reevaluateDisplay(p0)
|
||||
}
|
||||
|
||||
override fun onDisplayRemoved(p0: Int) {
|
||||
updateDisplayText()
|
||||
reevaluateDisplay(p0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reevaluateDisplay(p0: Int) {
|
||||
presentations.remove(p0)?.cancel() // Pop any presentation associated with this display index, and clean it up
|
||||
displayManager.getDisplay(p0)?.let { display ->
|
||||
if (display.flags and Display.FLAG_PRESENTATION == 0) return
|
||||
makePresentationView(display)
|
||||
}
|
||||
updateDisplayText()
|
||||
}
|
||||
|
||||
private fun inputStreamToCache(outputFilename: String, inputStream: InputStream): File {
|
||||
val fileCached = File(cacheDir, outputFilename)
|
||||
val output = FileOutputStream(fileCached)
|
||||
|
@ -69,30 +77,34 @@ class MainActivity : AppCompatActivity() {
|
|||
return fileCached
|
||||
}
|
||||
|
||||
private fun updatePresentationImages(reRender: Boolean = true) {
|
||||
presentation?.let { p ->
|
||||
if (reRender) {
|
||||
println(p.displayMetrics)
|
||||
val maxHeight: Int = p.displayMetrics.heightPixels
|
||||
val maxWidth: Int = min(maxHeight * 5 / 7, (p.displayMetrics.widthPixels / pagesPerLandscape).toInt())
|
||||
println("Rendering pages with maxHeight=$maxHeight maxWidth=$maxWidth")
|
||||
pdfDocument.renderPagesPresentation(maxWidth, maxHeight, renderAutoCrop)
|
||||
}
|
||||
val bitmaps = showPages.withIndex()
|
||||
.mapNotNull { (i, show) -> if (show) pdfDocument.bitmapPagesPresentation[i] else null }
|
||||
.toList()
|
||||
p.updateImages(bitmaps)
|
||||
}
|
||||
private fun updateBitmaps(maxWidth: Int, maxHeight: Int) {
|
||||
println("Rendering pages with maxHeight=$maxHeight maxWidth=$maxWidth")
|
||||
pdfDocument.renderPages(maxWidth, maxHeight, renderAutoCrop)
|
||||
}
|
||||
|
||||
private fun makePresentationView() {
|
||||
presentation = null
|
||||
mediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO)?.presentationDisplay?.let { display ->
|
||||
presentation = MyPresentation(this, display)
|
||||
updatePresentationImages()
|
||||
presentation?.setOnCancelListener { presentation = null }
|
||||
presentation?.show()
|
||||
}
|
||||
private fun updatePresentationImages(p: MyPresentation) {
|
||||
val maxHeight: Int = p.displayMetrics.heightPixels
|
||||
val maxWidth: Int = min(maxHeight * 5 / 7, (p.displayMetrics.widthPixels / pagesPerLandscape).toInt())
|
||||
updateBitmaps(maxWidth, maxHeight)
|
||||
val key = Pair(maxWidth, maxHeight)
|
||||
val bitmaps = showPages.withIndex()
|
||||
.mapNotNull { (i, show) -> if (show) pdfDocument.bitmapPages[key]?.get(i) else null }
|
||||
.toList()
|
||||
p.updateImages(bitmaps)
|
||||
}
|
||||
|
||||
private fun updatePresentations(reRender: Boolean = true) {
|
||||
if (reRender) pdfDocument.invalidateCache()
|
||||
presentations.values.forEach(::updatePresentationImages)
|
||||
}
|
||||
|
||||
private fun makePresentationView(display: Display) {
|
||||
val id = display.displayId
|
||||
val presentation = MyPresentation(this, display)
|
||||
updatePresentationImages(presentation)
|
||||
//presentation.setOnCancelListener { presentations.remove(id) }
|
||||
presentations[id] = presentation
|
||||
presentation.show()
|
||||
}
|
||||
|
||||
private fun reLayoutThumbnails() {
|
||||
|
@ -103,11 +115,10 @@ class MainActivity : AppCompatActivity() {
|
|||
showPages.map { if (it) container else disabledContainer }.zip(thumbnailImageViews).forEach { (cont, img) ->
|
||||
cont.addView(img)
|
||||
}
|
||||
updatePresentationImages(false)
|
||||
updatePresentations(false)
|
||||
}
|
||||
|
||||
private fun populateThumbnails() {
|
||||
val container = binding.appBarMain.contentMain.thumbnailsLayout
|
||||
for ((index, bitmap) in pdfDocument.bitmapThumbnails) {
|
||||
val img = ImageView(this)
|
||||
img.setImageBitmap(bitmap)
|
||||
|
@ -125,7 +136,7 @@ class MainActivity : AppCompatActivity() {
|
|||
private fun updateDisplayText() {
|
||||
val displayText = binding.appBarMain.contentMain.textDisplays
|
||||
val text = StringBuilder()
|
||||
//displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION).forEach {
|
||||
|
||||
displayManager.displays.forEach {
|
||||
val displayMetrics = DisplayMetrics()
|
||||
@Suppress("DEPRECATION")
|
||||
|
@ -135,6 +146,7 @@ class MainActivity : AppCompatActivity() {
|
|||
text.append(s)
|
||||
text.append("\n")
|
||||
}
|
||||
text.append(presentations)
|
||||
displayText.text = text.toString()
|
||||
}
|
||||
|
||||
|
@ -142,14 +154,12 @@ class MainActivity : AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
|
||||
mediaRouter = getSystemService(Context.MEDIA_ROUTER_SERVICE) as MediaRouter
|
||||
//val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
|
||||
//windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) //Doesn't seem to actually fill the vacant space by default
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
updateDisplayText()
|
||||
displayManager.registerDisplayListener(displayListener, null)
|
||||
|
||||
setSupportActionBar(binding.appBarMain.toolbar)
|
||||
|
@ -164,13 +174,14 @@ class MainActivity : AppCompatActivity() {
|
|||
handleIntent(intent)
|
||||
|
||||
pdfDocument.renderThumbnails(thumbnailWidth, thumbnailHeight)
|
||||
makePresentationView()
|
||||
displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION).forEach(::makePresentationView)
|
||||
populateThumbnails()
|
||||
|
||||
val container = binding.appBarMain.contentMain.thumbnailsLayout
|
||||
val containerScroll = binding.appBarMain.contentMain.thumbnailsScroll
|
||||
containerScroll.viewTreeObserver.addOnScrollChangedListener {
|
||||
presentation?.setScrollProgress(containerScroll.scrollX.toFloat() / (container.width - containerScroll.width))
|
||||
val progress = containerScroll.scrollX.toFloat() / (container.width - containerScroll.width)
|
||||
presentations.values.forEach {it.setScrollProgress(progress)}
|
||||
}
|
||||
|
||||
binding.appBarMain.crop.setOnClickListener { view ->
|
||||
|
@ -179,21 +190,21 @@ class MainActivity : AppCompatActivity() {
|
|||
Snackbar.make(view, "Toggling Auto Crop $s", Snackbar.LENGTH_LONG)
|
||||
.setAction("Action", null)
|
||||
.setAnchorView(R.id.crop).show()
|
||||
updatePresentationImages()
|
||||
updatePresentations()
|
||||
}
|
||||
binding.appBarMain.zoomIn.setOnClickListener { view ->
|
||||
pagesPerLandscape = max(pagesPerLandscape - 0.5F, 1F)
|
||||
Snackbar.make(view, "Aiming for $pagesPerLandscape pages at a time", Snackbar.LENGTH_LONG)
|
||||
.setAction("Action", null)
|
||||
.setAnchorView(R.id.zoom_in).show()
|
||||
updatePresentationImages()
|
||||
updatePresentations()
|
||||
}
|
||||
binding.appBarMain.zoomOut.setOnClickListener { view ->
|
||||
pagesPerLandscape = min(pagesPerLandscape + 0.5F, 10F)
|
||||
Snackbar.make(view, "Aiming for $pagesPerLandscape pages at a time", Snackbar.LENGTH_LONG)
|
||||
.setAction("Action", null)
|
||||
.setAnchorView(R.id.zoom_out).show()
|
||||
updatePresentationImages()
|
||||
updatePresentations()
|
||||
}
|
||||
val drawerLayout: DrawerLayout = binding.drawerLayout
|
||||
val navView: NavigationView = binding.navView
|
||||
|
@ -207,6 +218,7 @@ class MainActivity : AppCompatActivity() {
|
|||
)
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
navView.setupWithNavController(navController)
|
||||
updateDisplayText()
|
||||
}
|
||||
|
||||
private fun handleIntent(intent: Intent?) {
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.graphics.Rect
|
|||
import android.graphics.RectF
|
||||
import android.graphics.pdf.PdfRenderer
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.core.graphics.times
|
||||
import java.io.File
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
@ -16,8 +15,7 @@ class PdfDocument(private val fileCached: File, private val autoCrop: Boolean =
|
|||
private val pfd = ParcelFileDescriptor.open(fileCached, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||
private val renderer = PdfRenderer(pfd)
|
||||
val bitmapThumbnails = mutableMapOf<Int, Bitmap>()
|
||||
val bitmapPagesMain = mutableMapOf<Int, Bitmap>()
|
||||
val bitmapPagesPresentation = mutableMapOf<Int, Bitmap>()
|
||||
val bitmapPages = mutableMapOf<Pair<Int, Int>, MutableMap<Int, Bitmap>>() // bitmapPages[<maxWidthPx, maxHeightPx>][pageId]
|
||||
private val pagePtWidths = mutableListOf<Int>()
|
||||
private val pagePtHeights = mutableListOf<Int>()
|
||||
private val pageAutoCropRects = mutableListOf<RectF>()
|
||||
|
@ -57,11 +55,11 @@ class PdfDocument(private val fileCached: File, private val autoCrop: Boolean =
|
|||
return bitmap
|
||||
}
|
||||
|
||||
private fun renderPagesToMap(map: MutableMap<Int, Bitmap>, width: Int, height: Int, crop: Boolean = false) {
|
||||
map.clear()
|
||||
private fun renderPagesToMap(map: MutableMap<Int, Bitmap>, width: Int, height: Int, crop: Boolean = false, overwrite: Boolean = true) {
|
||||
if (overwrite) map.clear()
|
||||
val numPages = renderer.pageCount
|
||||
for (i in 0..<numPages) {
|
||||
map[i] = renderPage(i, width, height, crop)
|
||||
map.computeIfAbsent(i) { renderPage(i, width, height, crop) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,11 +132,12 @@ class PdfDocument(private val fileCached: File, private val autoCrop: Boolean =
|
|||
}
|
||||
}
|
||||
|
||||
fun renderPagesMain(width: Int, height: Int, crop: Boolean = true) {
|
||||
renderPagesToMap(bitmapPagesMain, width, height, crop)
|
||||
fun invalidateCache() {
|
||||
bitmapPages.clear()
|
||||
}
|
||||
|
||||
fun renderPagesPresentation(width: Int, height: Int, crop: Boolean = true) {
|
||||
renderPagesToMap(bitmapPagesPresentation, width, height, crop)
|
||||
fun renderPages(maxWidth: Int, maxHeight: Int, crop: Boolean = true) {
|
||||
val key = Pair(maxWidth, maxHeight)
|
||||
val map = bitmapPages.computeIfAbsent(key) { mutableMapOf<Int, Bitmap>() }
|
||||
renderPagesToMap(map, maxWidth, maxHeight, crop, false)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue