blob: 21b296b64a086e6e38ce946865b0229553f98b91 [file] [log] [blame]
/*
* Copyright (C) 2023 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.
*/
import {Layer, LayerTraceEntry} from 'flickerlib/common';
import {ParserViewCapture} from 'parsers/parser_view_capture';
import {Rectangle, TransformMatrix} from 'viewers/components/rects/types2d';
import {UserOptions} from './user_options';
export class SurfaceFlingerUtils {
static makeRects(entry: LayerTraceEntry, hierarchyUserOptions: UserOptions): Rectangle[] {
const layerRects = SurfaceFlingerUtils.makeLayerRects(entry, hierarchyUserOptions);
const displayRects = SurfaceFlingerUtils.makeDisplayRects(entry);
return layerRects.concat(displayRects);
}
private static makeLayerRects(
entry: LayerTraceEntry,
hierarchyUserOptions: UserOptions
): Rectangle[] {
return entry.flattenedLayers
.filter((layer: Layer) => {
return SurfaceFlingerUtils.isLayerToRenderInRectsComponent(layer, hierarchyUserOptions);
})
.sort(SurfaceFlingerUtils.compareLayerZ)
.map((it: Layer) => {
const transform: TransformMatrix = it.rect.transform?.matrix ?? it.rect.transform;
const rect: Rectangle = {
topLeft: {x: it.rect.left, y: it.rect.top},
bottomRight: {x: it.rect.right, y: it.rect.bottom},
label: it.rect.label,
transform,
isVisible: it.isVisible,
isDisplay: false,
id: it.stableId,
displayId: it.stackId,
isVirtual: false,
isClickable: true,
cornerRadius: it.cornerRadius,
// TODO(b/291213403): should read this data from the trace instead of a global variable
hasContent: ParserViewCapture.packageNames.includes(
it.rect.label.substring(0, it.rect.label.indexOf('/'))
),
};
return rect;
});
}
private static makeDisplayRects(entry: LayerTraceEntry): Rectangle[] {
if (!entry.displays) {
return [];
}
return entry.displays?.map((display: any) => {
const transform: TransformMatrix = display.transform?.matrix ?? display.transform;
const rect: Rectangle = {
topLeft: {x: 0, y: 0},
bottomRight: {x: display.size.width, y: display.size.height},
label: 'Display',
transform,
isVisible: false,
isDisplay: true,
id: `Display - ${display.id}`,
displayId: display.layerStackId,
isVirtual: display.isVirtual ?? false,
isClickable: false,
cornerRadius: 0,
hasContent: false,
};
return rect;
});
}
private static isLayerToRenderInRectsComponent(
layer: Layer,
hierarchyUserOptions: UserOptions
): boolean {
const onlyVisible = hierarchyUserOptions['onlyVisible']?.enabled ?? false;
// Show only visible layers or Visible + Occluded layers. Don't show all layers
// (flattenedLayers) because container layers are never meant to be displayed
return layer.isVisible || (!onlyVisible && layer.occludedBy.length > 0);
}
static compareLayerZ(a: Layer, b: Layer): number {
const zipLength = Math.min(a.zOrderPath.length, b.zOrderPath.length);
for (let i = 0; i < zipLength; ++i) {
const zOrderA = a.zOrderPath[i];
const zOrderB = b.zOrderPath[i];
if (zOrderA > zOrderB) return -1;
if (zOrderA < zOrderB) return 1;
}
// When z-order is the same, the layer with larger ID is on top
return a.id > b.id ? -1 : 1;
}
}