blob: c1ea143cc4b9dce888317b4ea26b28c4237406c7 [file] [log] [blame]
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.camera2.pipe.integration.impl
import android.content.Context
import android.graphics.Point
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManager.DisplayListener
import android.os.Handler
import android.os.Looper
import android.util.Size
import android.view.Display
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.integration.compat.workaround.MaxPreviewSize
import javax.inject.Inject
import javax.inject.Singleton
@Suppress("DEPRECATION") // getRealSize
@Singleton
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
class DisplayInfoManager @Inject constructor(context: Context) {
private val MAX_PREVIEW_SIZE = Size(1920, 1080)
private val maxPreviewSize: MaxPreviewSize = MaxPreviewSize()
companion object {
private var lazyMaxDisplay: Display? = null
private var lazyPreviewSize: Size? = null
internal fun invalidateLazyFields() {
lazyMaxDisplay = null
lazyPreviewSize = null
}
internal val displayListener by lazy {
object : DisplayListener {
override fun onDisplayAdded(displayId: Int) {
invalidateLazyFields()
}
override fun onDisplayRemoved(displayId: Int) {
invalidateLazyFields()
}
override fun onDisplayChanged(displayId: Int) {
invalidateLazyFields()
}
}
}
}
private val displayManager: DisplayManager by lazy {
(context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager).also {
it.registerDisplayListener(displayListener, Handler(Looper.getMainLooper()))
}
}
val defaultDisplay: Display
get() = getMaxSizeDisplay()
private var previewSize: Size? = null
/**
* Update the preview size according to current display size.
*/
fun refresh() {
previewSize = calculatePreviewSize()
}
/**
* PREVIEW refers to the best size match to the device's screen resolution, or to 1080p
* (1920x1080), whichever is smaller.
*/
fun getPreviewSize(): Size {
// Use cached value to speed up since this would be called multiple times.
if (previewSize != null) {
return previewSize as Size
}
previewSize = calculatePreviewSize()
return previewSize as Size
}
private fun getMaxSizeDisplay(): Display {
lazyMaxDisplay?.let { return it }
val displays = displayManager.displays
var maxDisplayWhenStateNotOff: Display? = null
var maxDisplaySizeWhenStateNotOff = -1
var maxDisplay: Display? = null
var maxDisplaySize = -1
for (display: Display in displays) {
val displaySize = Point()
// TODO(b/230400472): Use WindowManager#getCurrentWindowMetrics(). Display#getRealSize()
// is deprecated since API level 31.
display.getRealSize(displaySize)
if (displaySize.x * displaySize.y > maxDisplaySize) {
maxDisplaySize = displaySize.x * displaySize.y
maxDisplay = display
}
if (display.state != Display.STATE_OFF) {
if (displaySize.x * displaySize.y > maxDisplaySizeWhenStateNotOff) {
maxDisplaySizeWhenStateNotOff = displaySize.x * displaySize.y
maxDisplayWhenStateNotOff = display
}
}
}
lazyMaxDisplay = maxDisplayWhenStateNotOff ?: maxDisplay
return checkNotNull(lazyMaxDisplay) {
"No displays found from ${displayManager.displays}!"
}
}
/**
* Calculates the device's screen resolution, or MAX_PREVIEW_SIZE, whichever is smaller.
*/
private fun calculatePreviewSize(): Size {
lazyPreviewSize?.let { return it }
val displaySize = Point()
val display: Display = defaultDisplay
// TODO(b/230400472): Use WindowManager#getCurrentWindowMetrics(). Display#getRealSize()
// is deprecated since API level 31.
display.getRealSize(displaySize)
var displayViewSize: Size
displayViewSize = if (displaySize.x > displaySize.y) {
Size(displaySize.x, displaySize.y)
} else {
Size(displaySize.y, displaySize.x)
}
if (displayViewSize.width * displayViewSize.height
> MAX_PREVIEW_SIZE.width * MAX_PREVIEW_SIZE.height
) {
displayViewSize = MAX_PREVIEW_SIZE
}
displayViewSize = maxPreviewSize.getMaxPreviewResolution(displayViewSize)
return displayViewSize.also { lazyPreviewSize = displayViewSize }
}
}