blob: 740b866c639a9bf317446a39d8c9927eb16113a0 [file] [log] [blame]
/*
* Copyright (C) 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 com.android.server.wm.traces.common.layers
import com.android.server.wm.traces.common.ITraceEntry
import com.android.server.wm.traces.common.Rect
import com.android.server.wm.traces.common.component.matchers.ComponentNameMatcher
import com.android.server.wm.traces.common.component.matchers.IComponentMatcher
import kotlin.js.JsName
/** Base class for SF trace entries */
abstract class BaseLayerTraceEntry : ITraceEntry {
@JsName("elapsedTimestamp") abstract val elapsedTimestamp: Long
@JsName("clockTimestamp") abstract val clockTimestamp: Long?
@JsName("hwcBlob") abstract val hwcBlob: String
@JsName("where") abstract val where: String
@JsName("displays") abstract val displays: Array<Display>
@JsName("vSyncId") abstract val vSyncId: Long
@JsName("stableId")
val stableId: String
get() = this::class.simpleName ?: error("Unable to determine class")
@JsName("flattenedLayers") abstract val flattenedLayers: Array<Layer>
@JsName("visibleLayers")
val visibleLayers: Array<Layer>
get() = flattenedLayers.filter { it.isVisible }.toTypedArray()
// for winscope
@JsName("isVisible") val isVisible: Boolean = true
@JsName("children")
val children: Array<Layer>
get() = flattenedLayers.filter { it.isRootLayer }.toTypedArray()
@JsName("physicalDisplay")
val physicalDisplay: Display?
get() = displays.firstOrNull { !it.isVirtual }
@JsName("physicalDisplayBounds")
val physicalDisplayBounds: Rect?
get() = physicalDisplay?.layerStackSpace
/**
* @return A [Layer] matching [componentMatcher] with a non-empty active buffer, or null if no
* layer matches [componentMatcher] or if the matching layer's buffer is empty
*
* @param componentMatcher Components to search
*/
@JsName("getLayerWithBuffer")
fun getLayerWithBuffer(componentMatcher: IComponentMatcher): Layer? {
return flattenedLayers.firstOrNull {
componentMatcher.layerMatchesAnyOf(it) && it.activeBuffer.isNotEmpty
}
}
/** @return The [Layer] with [layerId], or null if the layer is not found */
@JsName("getLayerById")
fun getLayerById(layerId: Int): Layer? = this.flattenedLayers.firstOrNull { it.id == layerId }
/**
* Checks if any layer matching [componentMatcher] in the screen is animating.
*
* The screen is animating when a layer is not simple rotation, of when the pip overlay layer is
* visible
*
* @param componentMatcher Components to search
*/
@JsName("isAnimating")
fun isAnimating(
prevState: BaseLayerTraceEntry?,
componentMatcher: IComponentMatcher? = null
): Boolean {
val curLayers =
visibleLayers.filter {
componentMatcher == null || componentMatcher.layerMatchesAnyOf(it)
}
val currIds = visibleLayers.map { it.id }
val prevStateLayers =
prevState?.visibleLayers?.filter { currIds.contains(it.id) } ?: emptyList()
val layersAnimating =
curLayers.any { currLayer ->
val prevLayer = prevStateLayers.firstOrNull { it.id == currLayer.id }
currLayer.isAnimating(prevLayer)
}
val pipAnimating = isVisible(ComponentNameMatcher.PIP_CONTENT_OVERLAY)
return layersAnimating || pipAnimating
}
/**
* Check if at least one window matching [componentMatcher] is visible.
*
* @param componentMatcher Components to search
*/
@JsName("isVisibleComponent")
fun isVisible(componentMatcher: IComponentMatcher): Boolean =
componentMatcher.layerMatchesAnyOf(visibleLayers)
/** @return A [LayersTrace] object containing this state as its only entry */
@JsName("asTrace") fun asTrace(): LayersTrace = LayersTrace(arrayOf(this))
override fun toString(): String {
return "${timestamp}ns"
}
override fun equals(other: Any?): Boolean {
return other is BaseLayerTraceEntry && other.timestamp == this.timestamp
}
override fun hashCode(): Int {
var result = timestamp.hashCode()
result = 31 * result + hwcBlob.hashCode()
result = 31 * result + where.hashCode()
result = 31 * result + displays.contentHashCode()
result = 31 * result + isVisible.hashCode()
result = 31 * result + flattenedLayers.contentHashCode()
return result
}
}