1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {FunctionUtils} from 'common/function_utils'; 18import { 19 ActiveTraceChanged, 20 WinscopeEvent, 21 WinscopeEventType, 22} from 'messaging/winscope_event'; 23import {EmitEvent} from 'messaging/winscope_event_emitter'; 24import {MediaBasedTraceEntry} from 'trace/media_based_trace_entry'; 25import {Trace, TraceEntry} from 'trace/trace'; 26import {TraceEntryFinder} from 'trace/trace_entry_finder'; 27import {ViewerEvents} from 'viewers/common/viewer_events'; 28import {UiData} from './ui_data'; 29 30export type NotifyHierarchyViewCallbackType<UiData> = (uiData: UiData) => void; 31 32export class Presenter { 33 private readonly uiData: UiData; 34 private emitWinscopeEvent: EmitEvent = FunctionUtils.DO_NOTHING_ASYNC; 35 36 constructor( 37 private readonly traces: Array<Trace<MediaBasedTraceEntry>>, 38 private readonly notifyViewCallback: NotifyHierarchyViewCallbackType<UiData>, 39 ) { 40 this.uiData = new UiData( 41 this.traces.map((trace) => trace.getDescriptors().join(', ')), 42 ); 43 this.notifyViewCallback(this.uiData); 44 } 45 46 setEmitEvent(callback: EmitEvent) { 47 this.emitWinscopeEvent = callback; 48 } 49 50 addEventListeners(htmlElement: HTMLElement) { 51 htmlElement.addEventListener( 52 ViewerEvents.OverlayDblClick, 53 async (event) => { 54 this.onOverlayDblClick((event as CustomEvent).detail); 55 }, 56 ); 57 } 58 59 async onAppEvent(event: WinscopeEvent) { 60 await event.visit( 61 WinscopeEventType.TRACE_POSITION_UPDATE, 62 async (event) => { 63 const traceEntries = this.traces 64 .map((trace) => 65 TraceEntryFinder.findCorrespondingEntry(trace, event.position), 66 ) 67 .filter((entry) => entry !== undefined) as Array< 68 TraceEntry<MediaBasedTraceEntry> 69 >; 70 const entries: MediaBasedTraceEntry[] = await Promise.all( 71 traceEntries.map((entry) => { 72 return entry.getValue(); 73 }), 74 ); 75 this.uiData.currentTraceEntries = entries; 76 this.notifyViewCallback(this.uiData); 77 }, 78 ); 79 await event.visit( 80 WinscopeEventType.EXPANDED_TIMELINE_TOGGLED, 81 async (event) => { 82 this.uiData.forceMinimize = event.isTimelineExpanded; 83 this.notifyViewCallback(this.uiData); 84 }, 85 ); 86 } 87 88 async onOverlayDblClick(index: number) { 89 const currTrace = this.traces.at(index); 90 if (currTrace) { 91 this.emitWinscopeEvent(new ActiveTraceChanged(currTrace)); 92 } 93 } 94} 95