diff --git a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol.ts b/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol.ts index 05ab9454d..a8dad35f2 100644 --- a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol.ts +++ b/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol.ts @@ -14,29 +14,29 @@ * limitations under the License. */ -import { - AbtChromeExtensionProtocolDependencyInversion, - OnBugAttachmentsDownloadStart, - OnBugAttachmentsReceived -} from "./abt_chrome_extension_protocol_dependency_inversion"; import { MessageType, OpenBuganizerResponse, OpenRequest, WebCommandMessage} from "./messages"; import {FunctionUtils} from "common/utils/function_utils"; +import { + BuganizerAttachmentsDownloadEmitter, + OnBuganizerAttachmentsDownloadStart, + OnBuganizerAttachmentsDownloaded +} from "interfaces/buganizer_attachments_download_emitter"; -export class AbtChromeExtensionProtocol implements AbtChromeExtensionProtocolDependencyInversion { +export class AbtChromeExtensionProtocol implements BuganizerAttachmentsDownloadEmitter { static readonly ABT_EXTENSION_ID = "mbbaofdfoekifkfpgehgffcpagbbjkmj"; - private onBugAttachmentsDownloadStart: OnBugAttachmentsDownloadStart = FunctionUtils.DO_NOTHING; - private onBugAttachmentsReceived: OnBugAttachmentsReceived = FunctionUtils.DO_NOTHING_ASYNC; + private onAttachmentsDownloadStart: OnBuganizerAttachmentsDownloadStart = FunctionUtils.DO_NOTHING; + private onttachmentsDownloaded: OnBuganizerAttachmentsDownloaded = FunctionUtils.DO_NOTHING_ASYNC; - setOnBugAttachmentsDownloadStart(callback: OnBugAttachmentsDownloadStart) { - this.onBugAttachmentsDownloadStart = callback; + setOnBuganizerAttachmentsDownloadStart(callback: OnBuganizerAttachmentsDownloadStart) { + this.onAttachmentsDownloadStart = callback; } - setOnBugAttachmentsReceived(callback: OnBugAttachmentsReceived) { - this.onBugAttachmentsReceived = callback; + setOnBuganizerAttachmentsDownloaded(callback: OnBuganizerAttachmentsDownloaded) { + this.onttachmentsDownloaded = callback; } run() { @@ -45,7 +45,7 @@ export class AbtChromeExtensionProtocol implements AbtChromeExtensionProtocolDep return; } - this.onBugAttachmentsDownloadStart(); + this.onAttachmentsDownloadStart(); const openRequestMessage: OpenRequest = { action: MessageType.OPEN_REQUEST @@ -88,7 +88,7 @@ export class AbtChromeExtensionProtocol implements AbtChromeExtensionProtocolDep }); const files = await Promise.all(filesBlobPromises); - await this.onBugAttachmentsReceived(files); + await this.onttachmentsDownloaded(files); } private isOpenBuganizerResponseMessage(message: WebCommandMessage): diff --git a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_stub.ts b/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_stub.ts index 390752ecd..9c4b23f61 100644 --- a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_stub.ts +++ b/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_stub.ts @@ -14,23 +14,26 @@ * limitations under the License. */ +import {FunctionUtils} from "common/utils/function_utils"; import { - OnBugAttachmentsDownloadStart, - OnBugAttachmentsReceived, - AbtChromeExtensionProtocolDependencyInversion -} from "./abt_chrome_extension_protocol_dependency_inversion"; -import {FunctionUtils} from "../common/utils/function_utils"; + BuganizerAttachmentsDownloadEmitter, + OnBuganizerAttachmentsDownloadStart, + OnBuganizerAttachmentsDownloaded +} from "interfaces/buganizer_attachments_download_emitter"; +import {Runnable} from "interfaces/runnable"; -export class AbtChromeExtensionProtocolStub implements AbtChromeExtensionProtocolDependencyInversion { - onBugAttachmentsDownloadStart: OnBugAttachmentsDownloadStart = FunctionUtils.DO_NOTHING; - onBugAttachmentsReceived: OnBugAttachmentsReceived = FunctionUtils.DO_NOTHING_ASYNC; +export class AbtChromeExtensionProtocolStub implements + BuganizerAttachmentsDownloadEmitter, + Runnable { + onBuganizerAttachmentsDownloadStart: OnBuganizerAttachmentsDownloadStart = FunctionUtils.DO_NOTHING; + onBuganizerAttachmentsDownloaded: OnBuganizerAttachmentsDownloaded = FunctionUtils.DO_NOTHING_ASYNC; - setOnBugAttachmentsDownloadStart(callback: OnBugAttachmentsDownloadStart) { - this.onBugAttachmentsDownloadStart = callback; + setOnBuganizerAttachmentsDownloadStart(callback: OnBuganizerAttachmentsDownloadStart) { + this.onBuganizerAttachmentsDownloadStart = callback; } - setOnBugAttachmentsReceived(callback: OnBugAttachmentsReceived) { - this.onBugAttachmentsReceived = callback; + setOnBuganizerAttachmentsDownloaded(callback: OnBuganizerAttachmentsDownloaded) { + this.onBuganizerAttachmentsDownloaded = callback; } run() { diff --git a/tools/winscope-ng/src/app/components/app.component.ts b/tools/winscope-ng/src/app/components/app.component.ts index 59ba872e3..396c5d627 100644 --- a/tools/winscope-ng/src/app/components/app.component.ts +++ b/tools/winscope-ng/src/app/components/app.component.ts @@ -23,7 +23,6 @@ import { ViewEncapsulation } from "@angular/core"; import { createCustomElement } from "@angular/elements"; -import { AppComponentDependencyInversion } from "./app_component_dependency_inversion"; import { TimelineComponent} from "./timeline/timeline.component"; import {AbtChromeExtensionProtocol} from "abt_chrome_extension/abt_chrome_extension_protocol"; import {CrossToolProtocol} from "cross_tool/cross_tool_protocol"; @@ -45,6 +44,7 @@ import { TimelineData } from "app/timeline_data"; import { TracingConfig } from "trace_collection/tracing_config"; import {TRACE_INFO} from "app/trace_info"; import {UploadTracesComponent} from "./upload_traces.component"; +import {TraceDataListener} from "interfaces/trace_data_listener"; @Component({ selector: "app-root", @@ -65,7 +65,7 @@ import {UploadTracesComponent} from "./upload_traces.component"; @@ -198,7 +198,7 @@ import {UploadTracesComponent} from "./upload_traces.component"; ], encapsulation: ViewEncapsulation.None }) -export class AppComponent implements AppComponentDependencyInversion { +export class AppComponent implements TraceDataListener { title = "winscope-ng"; changeDetectorRef: ChangeDetectorRef; traceData = new TraceData(); @@ -285,19 +285,18 @@ export class AppComponent implements AppComponentDependencyInversion { return this.timelineData.getScreenRecordingVideo(); } - public onUploadNewClick() { - this.dataLoaded = false; - this.mediator.onWinscopeUploadNew(); - proxyClient.adbData = []; - this.changeDetectorRef.detectChanges(); - } - public onTraceDataLoaded(viewers: Viewer[]) { this.viewers = viewers; this.dataLoaded = true; this.changeDetectorRef.detectChanges(); } + public onTraceDataUnloaded() { + proxyClient.adbData = []; + this.dataLoaded = false; + this.changeDetectorRef.detectChanges(); + } + public setDarkMode(enabled: boolean) { document.body.classList.toggle("dark-mode", enabled); this.store.add("dark-mode", `${enabled}`); diff --git a/tools/winscope-ng/src/app/components/app_component_stub.ts b/tools/winscope-ng/src/app/components/app_component_stub.ts index 76246b5e2..dea90e16b 100644 --- a/tools/winscope-ng/src/app/components/app_component_stub.ts +++ b/tools/winscope-ng/src/app/components/app_component_stub.ts @@ -14,15 +14,15 @@ * limitations under the License. */ -import {AppComponentDependencyInversion} from "./app_component_dependency_inversion"; import {Viewer} from "viewers/viewer"; +import {TraceDataListener} from "interfaces/trace_data_listener"; -export class AppComponentStub implements AppComponentDependencyInversion { +export class AppComponentStub implements TraceDataListener { onTraceDataLoaded(viewers: Viewer[]) { // do nothing } - onUploadNewClick() { + onTraceDataUnloaded() { // do nothing } } diff --git a/tools/winscope-ng/src/app/components/timeline/timeline.component.ts b/tools/winscope-ng/src/app/components/timeline/timeline.component.ts index 4c2da711e..f86f8706e 100644 --- a/tools/winscope-ng/src/app/components/timeline/timeline.component.ts +++ b/tools/winscope-ng/src/app/components/timeline/timeline.component.ts @@ -30,11 +30,11 @@ import { FormControl, FormGroup, Validators} from "@angular/forms"; import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; import { TraceType } from "common/trace/trace_type"; import { TRACE_INFO } from "app/trace_info"; -import { TimelineComponentDependencyInversion } from "./timeline_component_dependency_inversion"; import { TimelineData } from "app/timeline_data"; import { MiniTimelineComponent } from "./mini_timeline.component"; import { ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType } from "common/trace/timestamp"; import { TimeUtils } from "common/utils/time_utils"; +import {TimestampChangeListener} from "interfaces/timestamp_change_listener"; @Component({ selector: "timeline", @@ -271,7 +271,7 @@ import { TimeUtils } from "common/utils/time_utils"; } `], }) -export class TimelineComponent implements TimelineComponentDependencyInversion { +export class TimelineComponent implements TimestampChangeListener { public readonly TOGGLE_BUTTON_CLASS: string = "button-toggle-expansion"; public readonly MAX_SELECTED_TRACES = 3; diff --git a/tools/winscope-ng/src/app/components/timeline/timeline_component_stub.ts b/tools/winscope-ng/src/app/components/timeline/timeline_component_stub.ts index bdba64a1a..a9b998da4 100644 --- a/tools/winscope-ng/src/app/components/timeline/timeline_component_stub.ts +++ b/tools/winscope-ng/src/app/components/timeline/timeline_component_stub.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import {TimelineComponentDependencyInversion} from "./timeline_component_dependency_inversion"; import {Timestamp} from "common/trace/timestamp"; +import {TimestampChangeListener} from "interfaces/timestamp_change_listener"; -export class TimelineComponentStub implements TimelineComponentDependencyInversion { +export class TimelineComponentStub implements TimestampChangeListener { onCurrentTimestampChanged(timestamp: Timestamp|undefined) { // do nothing } diff --git a/tools/winscope-ng/src/app/components/upload_traces.component.ts b/tools/winscope-ng/src/app/components/upload_traces.component.ts index 3998b17c1..336d900ff 100644 --- a/tools/winscope-ng/src/app/components/upload_traces.component.ts +++ b/tools/winscope-ng/src/app/components/upload_traces.component.ts @@ -23,12 +23,12 @@ import { Output } from "@angular/core"; import {MatSnackBar} from "@angular/material/snack-bar"; -import {UploadTracesComponentDependencyInversion} from "./upload_traces_component_dependency_inversion"; import {TraceData} from "app/trace_data"; import {TRACE_INFO} from "app/trace_info"; import {Trace, TraceFile} from "common/trace/trace"; import {FileUtils, OnFile} from "common/utils/file_utils"; import {ParserErrorSnackBarComponent} from "./parser_error_snack_bar_component"; +import {FilesDownloadListener} from "interfaces/files_download_listener"; @Component({ selector: "upload-traces", @@ -54,7 +54,7 @@ import {ParserErrorSnackBarComponent} from "./parser_error_snack_bar_component"; /> @@ -174,11 +174,11 @@ import {ParserErrorSnackBarComponent} from "./parser_error_snack_bar_component"; ` ] }) -export class UploadTracesComponent implements UploadTracesComponentDependencyInversion { +export class UploadTracesComponent implements FilesDownloadListener { TRACE_INFO = TRACE_INFO; isLoadingFiles = false; progressMessage = ""; - progresPercentage?: number; + progressPercentage?: number; @Input() traceData!: TraceData; @Output() traceDataLoaded = new EventEmitter(); @@ -197,52 +197,19 @@ export class UploadTracesComponent implements UploadTracesComponentDependencyInv public onFilesDownloadStart() { this.isLoadingFiles = true; this.progressMessage = "Downloading files..."; - this.progresPercentage = undefined; + this.progressPercentage = undefined; this.changeDetectorRef.detectChanges(); } + public async onFilesDownloaded(files: File[]) { + await this.processFiles(files); + } + public async onInputFiles(event: Event) { const files = this.getInputFiles(event); await this.processFiles(files); } - public async processFiles(files: File[]) { - const UI_PROGRESS_UPDATE_PERIOD_MS = 200; - let lastUiProgressUpdate = Date.now(); - - const onProgressUpdate = (progress: number) => { - const now = Date.now(); - if ((Date.now() - lastUiProgressUpdate) < UI_PROGRESS_UPDATE_PERIOD_MS) { - // Let's limit the amount of UI updates, because the progress bar component - // renders weird stuff when updated too frequently - return; - } - lastUiProgressUpdate = now; - - this.progresPercentage = progress; - this.changeDetectorRef.detectChanges(); - }; - - const traceFiles: TraceFile[] = []; - const onFile: OnFile = (file: File, parentArchive?: File) => { - traceFiles.push(new TraceFile(file, parentArchive)); - }; - - this.isLoadingFiles = true; - this.progressMessage = "Unzipping files..."; - this.changeDetectorRef.detectChanges(); - await FileUtils.unzipFilesIfNeeded(files, onFile, onProgressUpdate); - - this.progressMessage = "Parsing files..."; - this.changeDetectorRef.detectChanges(); - const parserErrors = await this.traceData.loadTraces(traceFiles, onProgressUpdate); - - this.isLoadingFiles = false; - this.changeDetectorRef.detectChanges(); - - ParserErrorSnackBarComponent.showIfNeeded(this.ngZone, this.snackBar, parserErrors); - } - public onViewTracesButtonClick() { this.traceDataLoaded.emit(); } @@ -277,6 +244,43 @@ export class UploadTracesComponent implements UploadTracesComponentDependencyInv this.changeDetectorRef.detectChanges(); } + private async processFiles(files: File[]) { + const UI_PROGRESS_UPDATE_PERIOD_MS = 200; + let lastUiProgressUpdate = Date.now(); + + const onProgressUpdate = (progress: number) => { + const now = Date.now(); + if ((Date.now() - lastUiProgressUpdate) < UI_PROGRESS_UPDATE_PERIOD_MS) { + // Let's limit the amount of UI updates, because the progress bar component + // renders weird stuff when updated too frequently + return; + } + lastUiProgressUpdate = now; + + this.progressPercentage = progress; + this.changeDetectorRef.detectChanges(); + }; + + const traceFiles: TraceFile[] = []; + const onFile: OnFile = (file: File, parentArchive?: File) => { + traceFiles.push(new TraceFile(file, parentArchive)); + }; + + this.isLoadingFiles = true; + this.progressMessage = "Unzipping files..."; + this.changeDetectorRef.detectChanges(); + await FileUtils.unzipFilesIfNeeded(files, onFile, onProgressUpdate); + + this.progressMessage = "Parsing files..."; + this.changeDetectorRef.detectChanges(); + const parserErrors = await this.traceData.loadTraces(traceFiles, onProgressUpdate); + + this.isLoadingFiles = false; + this.changeDetectorRef.detectChanges(); + + ParserErrorSnackBarComponent.showIfNeeded(this.ngZone, this.snackBar, parserErrors); + } + private getInputFiles(event: Event): File[] { const files: FileList | null = (event?.target as HTMLInputElement)?.files; if (!files || !files[0]) { diff --git a/tools/winscope-ng/src/app/components/upload_traces_component_stub.ts b/tools/winscope-ng/src/app/components/upload_traces_component_stub.ts index cea484dc4..7b68fd8b5 100644 --- a/tools/winscope-ng/src/app/components/upload_traces_component_stub.ts +++ b/tools/winscope-ng/src/app/components/upload_traces_component_stub.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import {UploadTracesComponentDependencyInversion} from "./upload_traces_component_dependency_inversion"; +import {FilesDownloadListener} from "interfaces/files_download_listener"; -export class UploadTracesComponentStub implements UploadTracesComponentDependencyInversion { +export class UploadTracesComponentStub implements FilesDownloadListener { onFilesDownloadStart() { // do nothing } - async processFiles(files: File[]) { + async onFilesDownloaded(files: File[]) { // do nothing } } diff --git a/tools/winscope-ng/src/app/mediator.spec.ts b/tools/winscope-ng/src/app/mediator.spec.ts index 746f93add..6aac6e7e7 100644 --- a/tools/winscope-ng/src/app/mediator.spec.ts +++ b/tools/winscope-ng/src/app/mediator.spec.ts @@ -93,18 +93,18 @@ describe("Mediator", () => { spyOn(uploadTracesComponent, "onFilesDownloadStart"); expect(uploadTracesComponent.onFilesDownloadStart).toHaveBeenCalledTimes(0); - abtChromeExtensionProtocol.onBugAttachmentsDownloadStart(); + abtChromeExtensionProtocol.onBuganizerAttachmentsDownloadStart(); expect(uploadTracesComponent.onFilesDownloadStart).toHaveBeenCalledTimes(1); }); it("handles empty downloaded files from ABT chrome extension", async () => { - spyOn(uploadTracesComponent, "processFiles"); - expect(uploadTracesComponent.processFiles).toHaveBeenCalledTimes(0); + spyOn(uploadTracesComponent, "onFilesDownloaded"); + expect(uploadTracesComponent.onFilesDownloaded).toHaveBeenCalledTimes(0); // Pass files even if empty so that the upload component will update the progress bar // and display error messages - await abtChromeExtensionProtocol.onBugAttachmentsReceived([]); - expect(uploadTracesComponent.processFiles).toHaveBeenCalledTimes(1); + await abtChromeExtensionProtocol.onBuganizerAttachmentsDownloaded([]); + expect(uploadTracesComponent.onFilesDownloaded).toHaveBeenCalledTimes(1); }); it("propagates current timestamp changed through timeline", async () => { diff --git a/tools/winscope-ng/src/app/mediator.ts b/tools/winscope-ng/src/app/mediator.ts index 19a575de8..ede1a1e53 100644 --- a/tools/winscope-ng/src/app/mediator.ts +++ b/tools/winscope-ng/src/app/mediator.ts @@ -14,21 +14,29 @@ * limitations under the License. */ -import {AppComponentDependencyInversion} from "./components/app_component_dependency_inversion"; -import {TimelineComponentDependencyInversion} - from "./components/timeline/timeline_component_dependency_inversion"; -import {UploadTracesComponentDependencyInversion} from "./components/upload_traces_component_dependency_inversion"; import {TimelineData} from "./timeline_data"; import {TraceData} from "./trace_data"; -import {AbtChromeExtensionProtocolDependencyInversion} - from "abt_chrome_extension/abt_chrome_extension_protocol_dependency_inversion"; -import {CrossToolProtocolDependencyInversion} - from "cross_tool/cross_tool_protocol_dependency_inversion"; import {Timestamp, TimestampType} from "common/trace/timestamp"; import {TraceType} from "common/trace/trace_type"; +import {BuganizerAttachmentsDownloadEmitter} from "interfaces/buganizer_attachments_download_emitter"; +import {FilesDownloadListener} from "interfaces/files_download_listener"; +import {RemoteBugreportReceiver} from "interfaces/remote_bugreport_receiver"; +import {RemoteTimestampReceiver} from "interfaces/remote_timestamp_receiver"; +import {RemoteTimestampSender} from "interfaces/remote_timestamp_sender"; +import {Runnable} from "interfaces/runnable"; +import {TimestampChangeListener} from "interfaces/timestamp_change_listener"; +import {TraceDataListener} from "interfaces/trace_data_listener"; import {Viewer} from "viewers/viewer"; import {ViewerFactory} from "viewers/viewer_factory"; +export type CrossToolProtocolDependencyInversion = + RemoteBugreportReceiver & RemoteTimestampReceiver & RemoteTimestampSender; +export type AbtChromeExtensionProtocolDependencyInversion = + BuganizerAttachmentsDownloadEmitter & Runnable; +export type AppComponentDependencyInversion = TraceDataListener; +export type TimelineComponentDependencyInversion = TimestampChangeListener; +export type UploadTracesComponentDependencyInversion = FilesDownloadListener; + export class Mediator { private abtChromeExtensionProtocol: AbtChromeExtensionProtocolDependencyInversion; private crossToolProtocol: CrossToolProtocolDependencyInversion; @@ -64,20 +72,19 @@ export class Mediator { }); this.crossToolProtocol.setOnBugreportReceived(async (bugreport: File, timestamp?: Timestamp) => { - await this.onRemoteToolBugreportReceived(bugreport, timestamp); + await this.onRemoteBugreportReceived(bugreport, timestamp); }); this.crossToolProtocol.setOnTimestampReceived(async (timestamp: Timestamp) => { - this.onRemoteToolTimestampReceived(timestamp); + this.onRemoteTimestampReceived(timestamp); }); - this.abtChromeExtensionProtocol.setOnBugAttachmentsReceived(async (attachments: File[]) => { - await this.onAbtChromeExtensionBugAttachmentsReceived(attachments); + this.abtChromeExtensionProtocol.setOnBuganizerAttachmentsDownloadStart(() => { + this.onBuganizerAttachmentsDownloadStart(); }); - this.abtChromeExtensionProtocol.setOnBugAttachmentsDownloadStart(() => { - console.log("Mediator notifying onFilesDownloadStart()"); - this.uploadTracesComponent?.onFilesDownloadStart(); + this.abtChromeExtensionProtocol.setOnBuganizerAttachmentsDownloaded(async (attachments: File[]) => { + await this.onBuganizerAttachmentsDownloaded(attachments); }); } @@ -95,21 +102,14 @@ export class Mediator { this.abtChromeExtensionProtocol.run(); } + public onWinscopeUploadNew() { + this.resetAppToInitialState(); + } + public onWinscopeTraceDataLoaded() { this.processTraceData(); } - public async onRemoteToolBugreportReceived(bugreport: File, timestamp?: Timestamp) { - await this.processRemoteFilesReceived([bugreport]); - if (timestamp !== undefined) { - this.onRemoteToolTimestampReceived(timestamp); - } - } - - public async onAbtChromeExtensionBugAttachmentsReceived(attachments: File[]) { - await this.processRemoteFilesReceived(attachments); - } - public onWinscopeCurrentTimestampChanged(timestamp: Timestamp|undefined) { this.executeIgnoringRecursiveTimestampNotifications(() => { const entries = this.traceData.getTraceEntries(timestamp); @@ -133,7 +133,23 @@ export class Mediator { }); } - public onRemoteToolTimestampReceived(timestamp: Timestamp) { + private onBuganizerAttachmentsDownloadStart() { + this.resetAppToInitialState(); + this.uploadTracesComponent?.onFilesDownloadStart(); + } + + private async onBuganizerAttachmentsDownloaded(attachments: File[]) { + await this.processRemoteFilesReceived(attachments); + } + + private async onRemoteBugreportReceived(bugreport: File, timestamp?: Timestamp) { + await this.processRemoteFilesReceived([bugreport]); + if (timestamp !== undefined) { + this.onRemoteTimestampReceived(timestamp); + } + } + + private onRemoteTimestampReceived(timestamp: Timestamp) { this.executeIgnoringRecursiveTimestampNotifications(() => { this.lastRemoteToolTimestampReceived = timestamp; @@ -164,15 +180,9 @@ export class Mediator { }); } - public onWinscopeUploadNew() { - this.reset(); - } - private async processRemoteFilesReceived(files: File[]) { - this.appComponent.onUploadNewClick(); - this.traceData.clear(); - this.uploadTracesComponent?.processFiles(files); // will notify back "trace data loaded" - this.isTraceDataVisualized = false; + this.resetAppToInitialState(); + this.uploadTracesComponent?.onFilesDownloaded(files); } private processTraceData() { @@ -185,7 +195,7 @@ export class Mediator { this.isTraceDataVisualized = true; if (this.lastRemoteToolTimestampReceived !== undefined) { - this.onRemoteToolTimestampReceived(this.lastRemoteToolTimestampReceived); + this.onRemoteTimestampReceived(this.lastRemoteToolTimestampReceived); } } @@ -211,12 +221,12 @@ export class Mediator { } } - private reset() { + private resetAppToInitialState() { this.traceData.clear(); this.timelineData.clear(); this.viewers = []; - this.isChangingCurrentTimestamp = false; this.isTraceDataVisualized = false; this.lastRemoteToolTimestampReceived = undefined; + this.appComponent.onTraceDataUnloaded(); } } diff --git a/tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts b/tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts index 31d7578d2..1ac19e66b 100644 --- a/tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts +++ b/tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts @@ -18,6 +18,7 @@ import { toSize, toActiveBuffer, toColor, toColor3, toPoint, toPointF, toRect, toRectF, toRegion, toMatrix22, toTransform, toInsets } from './common'; +import {ArrayUtils} from "common/utils/array_utils"; import { PropertiesDump } from "viewers/common/ui_tree_utils"; import intDefMapping from '../../../../../../../prebuilts/misc/common/winscope/intDefMapping.json'; @@ -176,6 +177,16 @@ export default class ObjectFormatter { } } + // Raw long number (no type name, no constructor name, no useful toString() method) + if (ArrayUtils.equal(Object.keys(obj).sort(), ["high_", "low_"])) { + const high = BigInt(obj.high_) << 32n; + let low = BigInt(obj.low_); + if (low < 0) { + low = -low; + } + return (high | low).toString(); + } + return null; } diff --git a/tools/winscope-ng/src/common/trace/flickerlib/layers/LayerTraceEntry.ts b/tools/winscope-ng/src/common/trace/flickerlib/layers/LayerTraceEntry.ts index fd60f3901..1a6d61eab 100644 --- a/tools/winscope-ng/src/common/trace/flickerlib/layers/LayerTraceEntry.ts +++ b/tools/winscope-ng/src/common/trace/flickerlib/layers/LayerTraceEntry.ts @@ -21,8 +21,8 @@ import { TimeUtils } from "common/utils/time_utils"; import { ElapsedTimestamp, RealTimestamp } from "common/trace/timestamp"; LayerTraceEntry.fromProto = function ( - protos: any[], - displayProtos: any[], + protos: object[], + displayProtos: object[], elapsedTimestamp: bigint, vSyncId: number, hwcBlob: string, @@ -49,7 +49,7 @@ LayerTraceEntry.fromProto = function ( return entry; } -function addAttributes(entry: LayerTraceEntry, protos: any, useElapsedTime = false) { +function addAttributes(entry: LayerTraceEntry, protos: object[], useElapsedTime = false) { entry.kind = "entry"; // Avoid parsing the entry root because it is an array of layers // containing all trace information, this slows down the property tree. diff --git a/tools/winscope-ng/src/cross_tool/cross_tool_protocol.ts b/tools/winscope-ng/src/cross_tool/cross_tool_protocol.ts index e249c1a25..3756ff052 100644 --- a/tools/winscope-ng/src/cross_tool/cross_tool_protocol.ts +++ b/tools/winscope-ng/src/cross_tool/cross_tool_protocol.ts @@ -16,12 +16,11 @@ import {Message, MessageBugReport, MessagePong, MessageTimestamp, MessageType} from "./messages"; import {OriginAllowList} from "./origin_allow_list"; -import { - CrossToolProtocolDependencyInversion, - OnBugreportReceived, - OnTimestampReceived} from "cross_tool/cross_tool_protocol_dependency_inversion"; import {RealTimestamp} from "common/trace/timestamp"; import {FunctionUtils} from "common/utils/function_utils"; +import {RemoteBugreportReceiver, OnBugreportReceived} from "interfaces/remote_bugreport_receiver"; +import {RemoteTimestampReceiver, OnTimestampReceived} from "interfaces/remote_timestamp_receiver"; +import {RemoteTimestampSender} from "interfaces/remote_timestamp_sender"; class RemoteTool { constructor( @@ -30,7 +29,10 @@ class RemoteTool { } } -export class CrossToolProtocol implements CrossToolProtocolDependencyInversion { +export class CrossToolProtocol implements + RemoteBugreportReceiver, + RemoteTimestampReceiver, + RemoteTimestampSender { private remoteTool?: RemoteTool; private onBugreportReceived: OnBugreportReceived = FunctionUtils.DO_NOTHING_ASYNC; private onTimestampReceived: OnTimestampReceived = FunctionUtils.DO_NOTHING; diff --git a/tools/winscope-ng/src/cross_tool/cross_tool_protocol_stub.ts b/tools/winscope-ng/src/cross_tool/cross_tool_protocol_stub.ts index 536117007..405ca3346 100644 --- a/tools/winscope-ng/src/cross_tool/cross_tool_protocol_stub.ts +++ b/tools/winscope-ng/src/cross_tool/cross_tool_protocol_stub.ts @@ -14,14 +14,16 @@ * limitations under the License. */ -import { - CrossToolProtocolDependencyInversion, - OnBugreportReceived, - OnTimestampReceived} from "cross_tool/cross_tool_protocol_dependency_inversion"; import {RealTimestamp} from "common/trace/timestamp"; import {FunctionUtils} from "common/utils/function_utils"; +import {RemoteBugreportReceiver, OnBugreportReceived} from "interfaces/remote_bugreport_receiver"; +import {RemoteTimestampReceiver, OnTimestampReceived} from "interfaces/remote_timestamp_receiver"; +import {RemoteTimestampSender} from "interfaces/remote_timestamp_sender"; -export class CrossToolProtocolStub implements CrossToolProtocolDependencyInversion { +export class CrossToolProtocolStub implements + RemoteBugreportReceiver, + RemoteTimestampReceiver, + RemoteTimestampSender { onBugreportReceived: OnBugreportReceived = FunctionUtils.DO_NOTHING_ASYNC; onTimestampReceived: OnTimestampReceived = FunctionUtils.DO_NOTHING; diff --git a/tools/winscope-ng/src/interfaces/buganizer_attachments_download_emitter.ts b/tools/winscope-ng/src/interfaces/buganizer_attachments_download_emitter.ts new file mode 100644 index 000000000..f62e57b2a --- /dev/null +++ b/tools/winscope-ng/src/interfaces/buganizer_attachments_download_emitter.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export type OnBuganizerAttachmentsDownloadStart = () => void; +export type OnBuganizerAttachmentsDownloaded = (attachments: File[]) => Promise; + +export interface BuganizerAttachmentsDownloadEmitter { + setOnBuganizerAttachmentsDownloadStart(callback: OnBuganizerAttachmentsDownloadStart): void; + setOnBuganizerAttachmentsDownloaded(callback: OnBuganizerAttachmentsDownloaded): void; +} diff --git a/tools/winscope-ng/src/app/components/upload_traces_component_dependency_inversion.ts b/tools/winscope-ng/src/interfaces/files_download_listener.ts similarity index 86% rename from tools/winscope-ng/src/app/components/upload_traces_component_dependency_inversion.ts rename to tools/winscope-ng/src/interfaces/files_download_listener.ts index d4f824908..8dd9101fb 100644 --- a/tools/winscope-ng/src/app/components/upload_traces_component_dependency_inversion.ts +++ b/tools/winscope-ng/src/interfaces/files_download_listener.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export interface UploadTracesComponentDependencyInversion { +export interface FilesDownloadListener { onFilesDownloadStart(): void; - processFiles(files: File[]): Promise; + onFilesDownloaded(files: File[]): Promise; } diff --git a/tools/winscope-ng/src/cross_tool/cross_tool_protocol_dependency_inversion.ts b/tools/winscope-ng/src/interfaces/remote_bugreport_receiver.ts similarity index 77% rename from tools/winscope-ng/src/cross_tool/cross_tool_protocol_dependency_inversion.ts rename to tools/winscope-ng/src/interfaces/remote_bugreport_receiver.ts index cba89cc02..cca7cb936 100644 --- a/tools/winscope-ng/src/cross_tool/cross_tool_protocol_dependency_inversion.ts +++ b/tools/winscope-ng/src/interfaces/remote_bugreport_receiver.ts @@ -17,10 +17,7 @@ import {RealTimestamp} from "common/trace/timestamp"; export type OnBugreportReceived = (bugreport: File, timestamp?: RealTimestamp) => Promise; -export type OnTimestampReceived = (timestamp: RealTimestamp) => void; -export interface CrossToolProtocolDependencyInversion { +export interface RemoteBugreportReceiver { setOnBugreportReceived(callback: OnBugreportReceived): void; - setOnTimestampReceived(callback: OnTimestampReceived): void; - sendTimestamp(timestamp: RealTimestamp): void; } diff --git a/tools/winscope-ng/src/interfaces/remote_timestamp_receiver.ts b/tools/winscope-ng/src/interfaces/remote_timestamp_receiver.ts new file mode 100644 index 000000000..1d480d83a --- /dev/null +++ b/tools/winscope-ng/src/interfaces/remote_timestamp_receiver.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +import {RealTimestamp} from "common/trace/timestamp"; + +export type OnTimestampReceived = (timestamp: RealTimestamp) => void; + +export interface RemoteTimestampReceiver { + setOnTimestampReceived(callback: OnTimestampReceived): void; +} diff --git a/tools/winscope-ng/src/interfaces/remote_timestamp_sender.ts b/tools/winscope-ng/src/interfaces/remote_timestamp_sender.ts new file mode 100644 index 000000000..80c922c75 --- /dev/null +++ b/tools/winscope-ng/src/interfaces/remote_timestamp_sender.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +import {RealTimestamp} from "common/trace/timestamp"; + +export interface RemoteTimestampSender { + sendTimestamp(timestamp: RealTimestamp): void; +} diff --git a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_dependency_inversion.ts b/tools/winscope-ng/src/interfaces/runnable.ts similarity index 64% rename from tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_dependency_inversion.ts rename to tools/winscope-ng/src/interfaces/runnable.ts index 790479d7c..e14beb83c 100644 --- a/tools/winscope-ng/src/abt_chrome_extension/abt_chrome_extension_protocol_dependency_inversion.ts +++ b/tools/winscope-ng/src/interfaces/runnable.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -export type OnBugAttachmentsDownloadStart = () => void; -export type OnBugAttachmentsReceived = (attachments: File[]) => Promise; - -export interface AbtChromeExtensionProtocolDependencyInversion { - setOnBugAttachmentsDownloadStart(callback: OnBugAttachmentsDownloadStart): void; - setOnBugAttachmentsReceived(callback: OnBugAttachmentsReceived): void; +export interface Runnable { run(): void; } diff --git a/tools/winscope-ng/src/app/components/timeline/timeline_component_dependency_inversion.ts b/tools/winscope-ng/src/interfaces/timestamp_change_listener.ts similarity index 92% rename from tools/winscope-ng/src/app/components/timeline/timeline_component_dependency_inversion.ts rename to tools/winscope-ng/src/interfaces/timestamp_change_listener.ts index 90fecd60f..137ec5979 100644 --- a/tools/winscope-ng/src/app/components/timeline/timeline_component_dependency_inversion.ts +++ b/tools/winscope-ng/src/interfaces/timestamp_change_listener.ts @@ -16,6 +16,6 @@ import {Timestamp} from "common/trace/timestamp"; -export interface TimelineComponentDependencyInversion { +export interface TimestampChangeListener { onCurrentTimestampChanged(timestamp: Timestamp|undefined): void; } diff --git a/tools/winscope-ng/src/app/components/app_component_dependency_inversion.ts b/tools/winscope-ng/src/interfaces/trace_data_listener.ts similarity index 89% rename from tools/winscope-ng/src/app/components/app_component_dependency_inversion.ts rename to tools/winscope-ng/src/interfaces/trace_data_listener.ts index 8f71dce77..19b8b9836 100644 --- a/tools/winscope-ng/src/app/components/app_component_dependency_inversion.ts +++ b/tools/winscope-ng/src/interfaces/trace_data_listener.ts @@ -16,7 +16,7 @@ import {Viewer} from "viewers/viewer"; -export interface AppComponentDependencyInversion { +export interface TraceDataListener { + onTraceDataUnloaded(): void; onTraceDataLoaded(viewers: Viewer[]): void; - onUploadNewClick(): void; } diff --git a/tools/winscope-ng/src/styles.css b/tools/winscope-ng/src/styles.css index 2b49ea3b7..fadb05262 100644 --- a/tools/winscope-ng/src/styles.css +++ b/tools/winscope-ng/src/styles.css @@ -39,7 +39,3 @@ app-root { flex-direction: row; overflow: auto; } - -viewer-surface-flinger .properties-view .view-header { - flex: 3; -} diff --git a/tools/winscope-ng/src/viewers/components/properties.component.ts b/tools/winscope-ng/src/viewers/components/properties.component.ts index 1a7cfec87..ced3b6271 100644 --- a/tools/winscope-ng/src/viewers/components/properties.component.ts +++ b/tools/winscope-ng/src/viewers/components/properties.component.ts @@ -22,7 +22,8 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils"; @Component({ selector: "properties-view", template: ` -
+

Properties

@@ -49,7 +50,7 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
@@ -58,7 +59,8 @@ import { PropertiesTreeNode, Terminal} from "viewers/common/ui_tree_utils";
-

Properties - Proto Dump

+

Properties - Proto Dump

= []; + + @Input() item?: UiTreeNode; @Input() store!: PersistentStore; @Input() isFlattened? = false; @Input() initialDepth = 0; @@ -117,7 +121,7 @@ export class TreeComponent { } constructor( - @Inject(ElementRef) public elementRef: ElementRef, + @Inject(ElementRef) public elementRef: ElementRef ) { this.nodeElement = elementRef.nativeElement.querySelector(".node"); this.nodeElement?.addEventListener("mousedown", this.nodeMouseDownEventListener); @@ -168,18 +172,14 @@ export class TreeComponent { } private updateHighlightedItems() { - if (this.item instanceof HierarchyTreeNode) { - if (this.item.stableId) { - this.highlightedItemChange.emit(`${this.item.stableId}`); - } else if (!this.item.stableId) { - //this.selectedTreeChange.emit(this.item); - } + if (this.item?.stableId) { + this.highlightedItemChange.emit(`${this.item.stableId}`); } } public isPinned() { if (this.item instanceof HierarchyTreeNode) { - return this.pinnedItems?.map(item => `${item.id}`).includes(`${this.item.id}`); + return this.pinnedItems?.map(item => `${item.stableId}`).includes(`${this.item.stableId}`); } return false; } diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts index c13445462..45767290a 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/presenter.ts @@ -1,4 +1,3 @@ - /* * Copyright (C) 2022 The Android Open Source Project * @@ -31,7 +30,7 @@ export class Presenter { constructor(notifyViewCallback: NotifyViewCallbackType, private storage: Storage) { this.notifyViewCallback = notifyViewCallback; this.uiData = new UiData([TraceType.SURFACE_FLINGER]); - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } public updatePinnedItems(pinnedItem: HierarchyTreeNode) { @@ -43,7 +42,7 @@ export class Presenter { } this.updatePinnedIds(pinnedId); this.uiData.pinnedItems = this.pinnedItems; - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } public updateHighlightedItems(id: string) { @@ -54,20 +53,20 @@ export class Presenter { this.highlightedItems.push(id); } this.uiData.highlightedItems = this.highlightedItems; - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } public updateHierarchyTree(userOptions: UserOptions) { this.hierarchyUserOptions = userOptions; this.uiData.hierarchyUserOptions = this.hierarchyUserOptions; this.uiData.tree = this.generateTree(); - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } public filterHierarchyTree(filterString: string) { this.hierarchyFilter = TreeUtils.makeNodeFilter(filterString); this.uiData.tree = this.generateTree(); - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } public updatePropertiesTree(userOptions: UserOptions) { @@ -101,7 +100,7 @@ export class Presenter { this.uiData.tree = this.generateTree(); } } - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } private generateRects(): Rectangle[] { @@ -162,8 +161,9 @@ export class Presenter { if (this.selectedHierarchyTree) { this.uiData.propertiesTree = this.getTreeWithTransformedProperties(this.selectedHierarchyTree); this.uiData.selectedLayer = this.selectedLayer; + this.uiData.displayPropertyGroups = this.shouldDisplayPropertyGroups(this.selectedLayer); } - this.notifyViewCallback(this.uiData); + this.copyUiDataAndNotifyView(); } private generateTree() { @@ -253,6 +253,20 @@ export class Presenter { return transformedTree; } + private shouldDisplayPropertyGroups(selectedLayer: Layer): boolean { + // Do not display property groups when the root layer is selected. The root layer doesn't + // provide property groups info (visibility, geometry transforms, ...). + const isRoot = selectedLayer === this.entry; + return !isRoot; + } + + private copyUiDataAndNotifyView() { + // Create a shallow copy of the data, otherwise the Angular OnPush change detection strategy + // won't detect the new input + const copy = Object.assign({}, this.uiData); + this.notifyViewCallback(copy); + } + private readonly notifyViewCallback: NotifyViewCallbackType; private uiData: UiData; private hierarchyFilter: FilterType = TreeUtils.makeNodeFilter(""); diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts index 6af67f615..18bc9b2b1 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/ui_data.ts @@ -30,6 +30,7 @@ export class UiData { tree: HierarchyTreeNode | null = null; propertiesTree: PropertiesTreeNode | null = null; selectedLayer: Layer = {}; + displayPropertyGroups = true; constructor(dependencies?: Array) { this.dependencies = dependencies ?? []; diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts index 55295bb24..35bc1bd76 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.component.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { + ChangeDetectionStrategy, Component, Input, } from "@angular/core"; @@ -24,6 +25,7 @@ import { PersistentStore } from "common/utils/persistent_store"; @Component({ selector: "viewer-surface-flinger", + changeDetection: ChangeDetectionStrategy.OnPush, template: `
@@ -67,7 +69,7 @@ import { PersistentStore } from "common/utils/persistent_store"; ] }) export class ViewerSurfaceFlingerComponent { - @Input() inputData: UiData | null = null; + @Input() inputData?: UiData; @Input() store: PersistentStore = new PersistentStore(); @Input() active = false; TRACE_INFO = TRACE_INFO; diff --git a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.ts b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.ts index 606cc4f5c..d605361f6 100644 --- a/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.ts +++ b/tools/winscope-ng/src/viewers/viewer_surface_flinger/viewer_surface_flinger.ts @@ -13,22 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {TraceType} from "common/trace/trace_type"; -import {View, Viewer, ViewType} from "viewers/viewer"; import {Presenter} from "./presenter"; import {UiData} from "./ui_data"; +import {TraceType} from "common/trace/trace_type"; +import {View, Viewer, ViewType} from "viewers/viewer"; import {ViewerEvents} from "viewers/common/viewer_events"; class ViewerSurfaceFlinger implements Viewer { + public static readonly DEPENDENCIES: TraceType[] = [TraceType.SURFACE_FLINGER]; + private htmlElement: HTMLElement; + private presenter: Presenter; + constructor(storage: Storage) { this.htmlElement = document.createElement("viewer-surface-flinger"); + this.presenter = new Presenter((uiData: UiData) => { - // Angular does not deep watch @Input properties. Clearing inputData to null before repopulating - // automatically ensures that the UI will change via the Angular change detection cycle. Without - // resetting, Angular does not auto-detect that inputData has changed. - (this.htmlElement as any).inputData = null; (this.htmlElement as any).inputData = uiData; }, storage); + this.htmlElement.addEventListener(ViewerEvents.HierarchyPinnedChange, (event) => this.presenter.updatePinnedItems(((event as CustomEvent).detail.pinnedItem))); this.htmlElement.addEventListener(ViewerEvents.HighlightedChange, (event) => this.presenter.updateHighlightedItems(`${(event as CustomEvent).detail.id}`)); this.htmlElement.addEventListener(ViewerEvents.HierarchyUserOptionsChange, (event) => this.presenter.updateHierarchyTree((event as CustomEvent).detail.userOptions)); @@ -49,10 +51,6 @@ class ViewerSurfaceFlinger implements Viewer { public getDependencies(): TraceType[] { return ViewerSurfaceFlinger.DEPENDENCIES; } - - public static readonly DEPENDENCIES: TraceType[] = [TraceType.SURFACE_FLINGER]; - private htmlElement: HTMLElement; - private presenter: Presenter; } export {ViewerSurfaceFlinger}; diff --git a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts index 023f03ac0..1869e3760 100644 --- a/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts +++ b/tools/winscope-ng/src/viewers/viewer_window_manager/viewer_window_manager.component.ts @@ -65,7 +65,7 @@ import { PersistentStore } from "common/utils/persistent_store"; ] }) export class ViewerWindowManagerComponent { - @Input() inputData: UiData | null = null; + @Input() inputData?: UiData; @Input() store: PersistentStore = new PersistentStore(); @Input() active = false; TRACE_INFO = TRACE_INFO;