diff --git a/tools/winscope-ng/src/app/components/app.component.ts b/tools/winscope-ng/src/app/components/app.component.ts index 1189dc4aa..826f12106 100644 --- a/tools/winscope-ng/src/app/components/app.component.ts +++ b/tools/winscope-ng/src/app/components/app.component.ts @@ -14,12 +14,22 @@ * limitations under the License. */ -import {Component, Injector, Inject, ViewEncapsulation, ChangeDetectorRef} from "@angular/core"; +import { + ChangeDetectorRef, + Component, + Injector, + Inject, + ViewChild, + ViewEncapsulation +} from "@angular/core"; import { createCustomElement } from "@angular/elements"; -import { TraceCoordinator } from "app/trace_coordinator"; +import { TimelineComponent} from "./timeline/timeline.component"; +import { Mediator } from "app/mediator"; +import { TraceData } from "app/trace_data"; import { PersistentStore } from "common/utils/persistent_store"; import { Timestamp } from "common/trace/timestamp"; import { FileUtils } from "common/utils/file_utils"; +import { FunctionUtils } from "common/utils/function_utils"; import { proxyClient, ProxyState } from "trace_collection/proxy_client"; import { ViewerInputMethodComponent } from "viewers/components/viewer_input_method.component"; import { View, Viewer } from "viewers/viewer"; @@ -29,12 +39,12 @@ import { ViewerWindowManagerComponent } from "viewers/viewer_window_manager/view import { ViewerTransactionsComponent } from "viewers/viewer_transactions/viewer_transactions.component"; import { ViewerScreenRecordingComponent } from "viewers/viewer_screen_recording/viewer_screen_recording.component"; import { TraceType } from "common/trace/trace_type"; -import { TimelineCoordinator } from "app/timeline_coordinator"; +import { TimelineData } from "app/timeline_data"; import { TracingConfig } from "trace_collection/tracing_config"; +import {TRACE_INFO} from "app/trace_info"; @Component({ selector: "app-root", - providers: [TimelineCoordinator, TraceCoordinator], template: ` Winscope @@ -76,7 +86,7 @@ import { TracingConfig } from "trace_collection/tracing_config"; + @@ -111,15 +123,15 @@ import { TracingConfig } from "trace_collection/tracing_config";
@@ -179,34 +191,24 @@ import { TracingConfig } from "trace_collection/tracing_config"; export class AppComponent { title = "winscope-ng"; changeDetectorRef: ChangeDetectorRef; - traceCoordinator: TraceCoordinator; - timelineCoordinator: TimelineCoordinator; + traceData = new TraceData(); + timelineData = new TimelineData(); + mediator = new Mediator(this.traceData, this.timelineData); states = ProxyState; store: PersistentStore = new PersistentStore(); currentTimestamp?: Timestamp; - currentTimestampIndex = 0; - allViewers: Viewer[] = []; + viewers: Viewer[] = []; isDarkModeOn!: boolean; dataLoaded = false; activeView: View|undefined; - collapsedTimelineHeight = 0; - - public onCollapsedTimelineSizeChanged(height: number) { - this.collapsedTimelineHeight = height; - this.changeDetectorRef.detectChanges(); - } + @ViewChild(TimelineComponent) timelineComponent?: TimelineComponent; constructor( @Inject(Injector) injector: Injector, - @Inject(ChangeDetectorRef) changeDetectorRef: ChangeDetectorRef, - @Inject(TimelineCoordinator) timelineCoordinator: TimelineCoordinator, - @Inject(TraceCoordinator) traceCoordinator: TraceCoordinator, + @Inject(ChangeDetectorRef) changeDetectorRef: ChangeDetectorRef ) { this.changeDetectorRef = changeDetectorRef; - this.timelineCoordinator = timelineCoordinator; - this.traceCoordinator = traceCoordinator; - this.timelineCoordinator.registerObserver(this.traceCoordinator); const storeDarkMode = this.store.get("dark-mode"); const prefersDarkQuery = window.matchMedia?.("(prefers-color-scheme: dark)"); @@ -240,17 +242,22 @@ export class AppComponent { TracingConfig.getInstance().initialize(localStorage); } - get availableTraces(): TraceType[] { - return this.traceCoordinator.getLoadedTraces().map((trace) => trace.type); + onCollapsedTimelineSizeChanged(height: number) { + this.collapsedTimelineHeight = height; + this.changeDetectorRef.detectChanges(); } - get videoData(): Blob|undefined { - return this.timelineCoordinator.getVideoData(); + getLoadedTraceTypes(): TraceType[] { + return this.traceData.getLoadedTraces().map((trace) => trace.type); + } + + getVideoData(): Blob|undefined { + return this.timelineData.getScreenRecordingVideo(); } public onUploadNewClick() { this.dataLoaded = false; - this.traceCoordinator.clearData(); + this.mediator.clearData(); proxyClient.adbData = []; this.changeDetectorRef.detectChanges(); } @@ -261,24 +268,18 @@ export class AppComponent { this.isDarkModeOn = enabled; } - public onDataLoadedChange(dataLoaded: boolean) { - if (dataLoaded && !(this.traceCoordinator.getViewers().length > 0)) { - this.traceCoordinator.createViewers(localStorage); - this.allViewers = this.traceCoordinator.getViewers(); - // TODO: Update to handle viewers with more than one dependency - if (this.allViewers[0].getDependencies().length !== 1) { - throw Error("Viewers with more than 1 dependency not yet handled."); - } - this.currentTimestampIndex = 0; - this.dataLoaded = dataLoaded; - this.changeDetectorRef.detectChanges(); - } + public onTraceDataLoaded() { + this.mediator.onTraceDataLoaded(localStorage); + this.viewers = this.mediator.getViewers(); + this.dataLoaded = true; + this.changeDetectorRef.detectChanges(); } async onDownloadTracesButtonClick() { - const traces = await this.traceCoordinator.getAllTracesForDownload(); - const zipFileBlob = await FileUtils.createZipArchive(traces); + const traceFiles = await this.makeTraceFilesForDownload(); + const zipFileBlob = await FileUtils.createZipArchive(traceFiles); const zipFileName = "winscope.zip"; + const a = document.createElement("a"); document.body.appendChild(a); const url = window.URL.createObjectURL(zipFileBlob); @@ -289,9 +290,17 @@ export class AppComponent { document.body.removeChild(a); } + private async makeTraceFilesForDownload(): Promise { + return this.traceData.getLoadedTraces().map(trace => { + const traceType = TRACE_INFO[trace.type].name; + const newName = traceType + "/" + FileUtils.removeDirFromFileName(trace.file.name); + return new File([trace.file], newName); + }); + } + handleActiveViewChanged(view: View) { this.activeView = view; - this.timelineCoordinator.setActiveTraceTypes(view.dependencies); + this.timelineData.setActiveViewTraceTypes(view.dependencies); } getActiveTraceType(): TraceType|undefined { diff --git a/tools/winscope-ng/src/app/components/collect_traces.component.ts b/tools/winscope-ng/src/app/components/collect_traces.component.ts index 547ac0140..37b29d384 100644 --- a/tools/winscope-ng/src/app/components/collect_traces.component.ts +++ b/tools/winscope-ng/src/app/components/collect_traces.component.ts @@ -14,11 +14,11 @@ * limitations under the License. */ import { Component, Input, Inject, Output, EventEmitter, OnInit, OnDestroy, ViewEncapsulation, ChangeDetectorRef } from "@angular/core"; +import { TraceData} from "app/trace_data"; import { ProxyConnection } from "trace_collection/proxy_connection"; import { Connection } from "trace_collection/connection"; import { ProxyState } from "trace_collection/proxy_client"; import { traceConfigurations, configMap, SelectionConfiguration, EnableConfiguration } from "trace_collection/trace_collection_utils"; -import { TraceCoordinator } from "app/trace_coordinator"; import { PersistentStore } from "common/utils/persistent_store"; import { MatSnackBar } from "@angular/material/snack-bar"; import { ParserError } from "parsers/parser_factory"; @@ -58,7 +58,7 @@ import { TracingConfig } from "trace_collection/tracing_config"; {{ connect.devices()[deviceId].authorised ? "smartphone" : "screen_lock_portrait" }}

- {{ connect.devices()[deviceId].authorised ? connect.devices()[deviceId].model : "unauthorised" }} ({{ deviceId }}) + {{ connect.devices()[deviceId].authorised ? connect.devices()[deviceId]?.model : "unauthorised" }} ({{ deviceId }})

@@ -70,7 +70,7 @@ import { TracingConfig } from "trace_collection/tracing_config"; smartphone

- {{ connect.selectedDevice().model }} ({{ connect.selectedDeviceId() }}) + {{ connect.selectedDevice()?.model }} ({{ connect.selectedDeviceId() }})

@@ -303,13 +303,12 @@ export class CollectTracesComponent implements OnInit, OnDestroy { traceConfigurations = traceConfigurations; connect: Connection; tracingConfig = TracingConfig.getInstance(); - dataLoaded = false; loadProgress = 0; @Input() store!: PersistentStore; - @Input() traceCoordinator!: TraceCoordinator; + @Input() traceData!: TraceData; - @Output() dataLoadedChange = new EventEmitter(); + @Output() traceDataLoaded = new EventEmitter(); constructor( @Inject(MatSnackBar) private snackBar: MatSnackBar, @@ -388,7 +387,7 @@ export class CollectTracesComponent implements OnInit, OnDestroy { if (dumpSuccessful) { await this.loadFiles(); } else { - this.traceCoordinator.clearData(); + this.traceData.clear(); } } @@ -478,14 +477,13 @@ export class CollectTracesComponent implements OnInit, OnDestroy { private async loadFiles() { console.log("loading files", this.connect.adbData()); - this.traceCoordinator.clearData(); + this.traceData.clear(); - const parserErrors = await this.traceCoordinator.setTraces(this.connect.adbData()); + const parserErrors = await this.traceData.loadTraces(this.connect.adbData()); if (parserErrors.length > 0) { this.openTempSnackBar(parserErrors); } - this.dataLoaded = true; - this.dataLoadedChange.emit(this.dataLoaded); + this.traceDataLoaded.emit(); console.log("finished loading data!"); } diff --git a/tools/winscope-ng/src/app/components/timeline/expanded_timeline.component.ts b/tools/winscope-ng/src/app/components/timeline/expanded_timeline.component.ts index 78b5fd4b4..432b06eb4 100644 --- a/tools/winscope-ng/src/app/components/timeline/expanded_timeline.component.ts +++ b/tools/winscope-ng/src/app/components/timeline/expanded_timeline.component.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Component, ElementRef, EventEmitter, HostListener, Inject, Input, Output, QueryList, ViewChild, ViewChildren } from "@angular/core"; -import { TimelineCoordinator } from "app/timeline_coordinator"; +import { Component, ElementRef, EventEmitter, HostListener, Input, Output, QueryList, ViewChild, ViewChildren } from "@angular/core"; +import { TimelineData } from "app/timeline_data"; import { TRACE_INFO } from "app/trace_info"; import { Timestamp } from "common/trace/timestamp"; import { SingleTimelineComponent } from "./single_timeline.component"; @@ -26,18 +26,20 @@ import { SingleTimelineComponent } from "./single_timeline.component";
- + {{ TRACE_INFO[timeline.key].icon }}
+
@@ -122,6 +124,7 @@ import { SingleTimelineComponent } from "./single_timeline.component"; `] }) export class ExpandedTimelineComponent { + @Input() timelineData!: TimelineData; @Input() currentTimestamp!: Timestamp; @Output() onTimestampChanged = new EventEmitter(); @@ -132,14 +135,12 @@ export class ExpandedTimelineComponent { TRACE_INFO = TRACE_INFO; - constructor(@Inject(TimelineCoordinator) public timelineCoordinator: TimelineCoordinator) {} - get canvas(): HTMLCanvasElement { return this.canvasRef.nativeElement; } get data() { - return this.timelineCoordinator.getTimelines(); + return this.timelineData.getTimelines(); } get sortedMergedTimestamps() { @@ -147,11 +148,11 @@ export class ExpandedTimelineComponent { } get start() { - return this.timelineCoordinator.selection.from; + return this.timelineData.getSelectionRange().from; } get end() { - return this.timelineCoordinator.selection.to; + return this.timelineData.getSelectionRange().to; } @HostListener("window:resize", ["$event"]) diff --git a/tools/winscope-ng/src/app/components/timeline/mini_timeline.component.ts b/tools/winscope-ng/src/app/components/timeline/mini_timeline.component.ts index 5066a06d8..d5ae0cdd2 100644 --- a/tools/winscope-ng/src/app/components/timeline/mini_timeline.component.ts +++ b/tools/winscope-ng/src/app/components/timeline/mini_timeline.component.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Component, ElementRef, EventEmitter, HostListener, Inject, Input, Output, SimpleChanges, ViewChild } from "@angular/core"; -import { TimelineCoordinator } from "app/timeline_coordinator"; +import { Component, ElementRef, EventEmitter, HostListener, Input, Output, SimpleChanges, ViewChild } from "@angular/core"; +import { TimelineData } from "app/timeline_data"; import { Timestamp } from "common/trace/timestamp"; import { TraceType } from "common/trace/trace_type"; import { MiniCanvasDrawer, MiniCanvasDrawerInput } from "./mini_canvas_drawer"; @@ -36,7 +36,7 @@ import { MiniCanvasDrawer, MiniCanvasDrawerInput } from "./mini_canvas_drawer"; `] }) export class MiniTimelineComponent { - + @Input() timelineData!: TimelineData; @Input() currentTimestamp!: Timestamp; @Input() selectedTraces!: TraceType[]; @@ -49,15 +49,13 @@ export class MiniTimelineComponent { return this.canvasRef.nativeElement; } - constructor(@Inject(TimelineCoordinator) private timelineCoordinator: TimelineCoordinator) {} - private drawer: MiniCanvasDrawer|undefined = undefined; ngAfterViewInit(): void { this.makeHiPPICanvas(); const updateTimestampCallback = (position: bigint) => { - const timestampType = this.timelineCoordinator.getTimestampType()!; + const timestampType = this.timelineData.getTimestampType()!; this.changeSeekTimestamp.emit(undefined); this.changeTimestamp.emit(new Timestamp(timestampType, position)); }; @@ -66,13 +64,13 @@ export class MiniTimelineComponent { this.canvas, () => this.getMiniCanvasDrawerInput(), (position) => { - const timestampType = this.timelineCoordinator.getTimestampType()!; + const timestampType = this.timelineData.getTimestampType()!; this.changeSeekTimestamp.emit(new Timestamp(timestampType, position)); }, updateTimestampCallback, (selection) => { - const timestampType = this.timelineCoordinator.getTimestampType()!; - this.timelineCoordinator.setSelection({ + const timestampType = this.timelineData.getTimestampType()!; + this.timelineData.setSelectionRange({ from: new Timestamp(timestampType, selection.from), to: new Timestamp(timestampType, selection.to) }); @@ -91,13 +89,13 @@ export class MiniTimelineComponent { private getMiniCanvasDrawerInput() { return new MiniCanvasDrawerInput( { - from: this.timelineCoordinator.fullRange.from.getValueNs(), - to: this.timelineCoordinator.fullRange.to.getValueNs() + from: this.timelineData.getFullRange().from.getValueNs(), + to: this.timelineData.getFullRange().to.getValueNs() }, this.currentTimestamp.getValueNs(), { - from: this.timelineCoordinator.selection.from.getValueNs(), - to: this.timelineCoordinator.selection.to.getValueNs() + from: this.timelineData.getSelectionRange().from.getValueNs(), + to: this.timelineData.getSelectionRange().to.getValueNs() }, this.getTimelinesToShow() ); @@ -106,7 +104,7 @@ export class MiniTimelineComponent { private getTimelinesToShow() { const timelines = new Map(); for (const type of this.selectedTraces) { - timelines.set(type, this.timelineCoordinator.getTimelines().get(type)!.map(it => it.getValueNs())); + timelines.set(type, this.timelineData.getTimelines().get(type)!.map(it => it.getValueNs())); } return timelines; } diff --git a/tools/winscope-ng/src/app/components/timeline/timeline.component.spec.ts b/tools/winscope-ng/src/app/components/timeline/timeline.component.spec.ts index 5821bb7c3..5c2804fba 100644 --- a/tools/winscope-ng/src/app/components/timeline/timeline.component.spec.ts +++ b/tools/winscope-ng/src/app/components/timeline/timeline.component.spec.ts @@ -25,13 +25,15 @@ import {MatDrawer, MatDrawerContainer, MatDrawerContent} from "app/components/bo import {TimelineComponent} from "./timeline.component"; import {ExpandedTimelineComponent} from "./expanded_timeline.component"; import {MiniTimelineComponent} from "./mini_timeline.component"; -import {TimelineCoordinator} from "app/timeline_coordinator"; +import {TimelineData} from "app/timeline_data"; import {TraceType} from "common/trace/trace_type"; import {RealTimestamp, Timestamp} from "common/trace/timestamp"; import {By} from "@angular/platform-browser"; import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; import {MatInputModule} from "@angular/material/input"; import { SingleTimelineComponent } from "./single_timeline.component"; +import {Mediator} from "app/mediator"; +import {TraceData} from "app/trace_data"; describe("TimelineComponent", () => { let fixture: ComponentFixture; @@ -40,9 +42,6 @@ describe("TimelineComponent", () => { beforeEach(async () => { await TestBed.configureTestingModule({ - providers: [ - TimelineCoordinator - ], imports: [ FormsModule, MatButtonModule, @@ -68,6 +67,11 @@ describe("TimelineComponent", () => { fixture = TestBed.createComponent(TimelineComponent); component = fixture.componentInstance; htmlElement = fixture.nativeElement; + + const traceData = new TraceData(); + const timelineData = new TimelineData(); + component.mediator = new Mediator(traceData, timelineData); + component.timelineData = timelineData; }); it("can be created", () => { @@ -76,10 +80,10 @@ describe("TimelineComponent", () => { it("can be expanded", () => { const timestamps = [timestamp(100), timestamp(110)]; - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: timestamps - }]); + }], undefined); fixture.detectChanges(); const button = htmlElement.querySelector(`.${component.TOGGLE_BUTTON_CLASS}`); @@ -100,10 +104,10 @@ describe("TimelineComponent", () => { it("handles no timestamps", () => { const timestamps: Timestamp[] = []; - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: timestamps - }]); + }], undefined); fixture.detectChanges(); // no expand button @@ -121,22 +125,22 @@ describe("TimelineComponent", () => { }); it("processes active trace input and updates selected traces", () => { - component.activeTrace = TraceType.SURFACE_FLINGER; + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; expect(component.wrappedActiveTrace).toEqual(TraceType.SURFACE_FLINGER); expect(component.selectedTraces).toEqual([TraceType.SURFACE_FLINGER]); - component.activeTrace = TraceType.SURFACE_FLINGER; + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; expect(component.wrappedActiveTrace).toEqual(TraceType.SURFACE_FLINGER); expect(component.selectedTraces).toEqual([TraceType.SURFACE_FLINGER]); - component.activeTrace = TraceType.TRANSACTIONS; + component.activeViewTraceTypes = [TraceType.TRANSACTIONS]; expect(component.wrappedActiveTrace).toEqual(TraceType.TRANSACTIONS); expect(component.selectedTraces).toEqual([ TraceType.SURFACE_FLINGER, TraceType.TRANSACTIONS ]); - component.activeTrace = TraceType.WINDOW_MANAGER; + component.activeViewTraceTypes = [TraceType.WINDOW_MANAGER]; expect(component.wrappedActiveTrace).toEqual(TraceType.WINDOW_MANAGER); expect(component.selectedTraces).toEqual([ TraceType.SURFACE_FLINGER, @@ -144,7 +148,7 @@ describe("TimelineComponent", () => { TraceType.WINDOW_MANAGER ]); - component.activeTrace = TraceType.PROTO_LOG; + component.activeViewTraceTypes = [TraceType.PROTO_LOG]; expect(component.wrappedActiveTrace).toEqual(TraceType.PROTO_LOG); expect(component.selectedTraces).toEqual([ TraceType.TRANSACTIONS, @@ -154,174 +158,178 @@ describe("TimelineComponent", () => { }); it("handles undefined active trace input", () => { - component.activeTrace = undefined; + component.activeViewTraceTypes = undefined; expect(component.wrappedActiveTrace).toBeUndefined(); expect(component.selectedTraces).toEqual([]); - component.activeTrace = TraceType.SURFACE_FLINGER; + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; expect(component.wrappedActiveTrace).toEqual(TraceType.SURFACE_FLINGER); expect(component.selectedTraces).toEqual([TraceType.SURFACE_FLINGER]); - component.activeTrace = undefined; + component.activeViewTraceTypes = undefined; expect(component.wrappedActiveTrace).toEqual(TraceType.SURFACE_FLINGER); expect(component.selectedTraces).toEqual([TraceType.SURFACE_FLINGER]); }); it("handles some traces with no timestamps", () => { - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: [] }, { traceType: TraceType.WINDOW_MANAGER, timestamps: [timestamp(100)] - }]); + }], undefined); fixture.detectChanges(); }); it("next button disabled if no next entry", () => { - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: [timestamp(100), timestamp(110)] }, { traceType: TraceType.WINDOW_MANAGER, timestamps: [timestamp(90), timestamp(101), timestamp(110), timestamp(112)] - }]); - component.activeTrace = TraceType.SURFACE_FLINGER; + }], undefined); + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); const nextEntryButton = fixture.debugElement.query(By.css("#next_entry_button")); expect(nextEntryButton).toBeTruthy(); expect(nextEntryButton.nativeElement.getAttribute("disabled")).toBeFalsy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(90)); + component.timelineData.setCurrentTimestamp(timestamp(90)); fixture.detectChanges(); expect(nextEntryButton.nativeElement.getAttribute("disabled")).toBeFalsy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(110)); + component.timelineData.setCurrentTimestamp(timestamp(110)); fixture.detectChanges(); expect(nextEntryButton.nativeElement.getAttribute("disabled")).toBeTruthy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(112)); + component.timelineData.setCurrentTimestamp(timestamp(112)); fixture.detectChanges(); expect(nextEntryButton.nativeElement.getAttribute("disabled")).toBeTruthy(); }); it("prev button disabled if no prev entry", () => { - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: [timestamp(100), timestamp(110)] }, { traceType: TraceType.WINDOW_MANAGER, timestamps: [timestamp(90), timestamp(101), timestamp(110), timestamp(112)] - }]); - component.activeTrace = TraceType.SURFACE_FLINGER; + }], undefined); + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); const prevEntryButton = fixture.debugElement.query(By.css("#prev_entry_button")); expect(prevEntryButton).toBeTruthy(); expect(prevEntryButton.nativeElement.getAttribute("disabled")).toBeTruthy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(90)); + component.timelineData.setCurrentTimestamp(timestamp(90)); fixture.detectChanges(); expect(prevEntryButton.nativeElement.getAttribute("disabled")).toBeTruthy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(110)); + component.timelineData.setCurrentTimestamp(timestamp(110)); fixture.detectChanges(); expect(prevEntryButton.nativeElement.getAttribute("disabled")).toBeFalsy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(112)); + component.timelineData.setCurrentTimestamp(timestamp(112)); fixture.detectChanges(); expect(prevEntryButton.nativeElement.getAttribute("disabled")).toBeFalsy(); }); it("changes timestamp on next entry button press", () => { - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: [timestamp(100), timestamp(110)] }, { traceType: TraceType.WINDOW_MANAGER, timestamps: [timestamp(90), timestamp(101), timestamp(110), timestamp(112)] - }]); - component.activeTrace = TraceType.SURFACE_FLINGER; + }], undefined); + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); const nextEntryButton = fixture.debugElement.query(By.css("#next_entry_button")); expect(nextEntryButton).toBeTruthy(); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(105)); + component.timelineData.setCurrentTimestamp(timestamp(105)); fixture.detectChanges(); nextEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(110n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(110n); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(100)); + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); nextEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(110n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(110n); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(90)); + component.timelineData.setCurrentTimestamp(timestamp(90)); fixture.detectChanges(); nextEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); // No change when we are already on the last timestamp of the active trace - component.timelineCoordinator.updateCurrentTimestamp(timestamp(110)); + component.timelineData.setCurrentTimestamp(timestamp(110)); fixture.detectChanges(); nextEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(110n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(110n); // No change when we are after the last entry of the active trace - component.timelineCoordinator.updateCurrentTimestamp(timestamp(112)); + component.timelineData.setCurrentTimestamp(timestamp(112)); fixture.detectChanges(); nextEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(112n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(112n); }); it("changes timestamp on previous entry button press", () => { - component.timelineCoordinator.setTimelines([{ + component.timelineData.initialize([{ traceType: TraceType.SURFACE_FLINGER, timestamps: [timestamp(100), timestamp(110)] }, { traceType: TraceType.WINDOW_MANAGER, timestamps: [timestamp(90), timestamp(101), timestamp(110), timestamp(112)] - }]); - component.activeTrace = TraceType.SURFACE_FLINGER; + }], undefined); + component.activeViewTraceTypes = [TraceType.SURFACE_FLINGER]; + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); const prevEntryButton = fixture.debugElement.query(By.css("#prev_entry_button")); expect(prevEntryButton).toBeTruthy(); // In this state we are already on the first entry at timestamp 100, so // there is no entry to move to before and we just don't update the timestamp - component.timelineCoordinator.updateCurrentTimestamp(timestamp(105)); + component.timelineData.setCurrentTimestamp(timestamp(105)); fixture.detectChanges(); prevEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(105n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(105n); - component.timelineCoordinator.updateCurrentTimestamp(timestamp(110)); + component.timelineData.setCurrentTimestamp(timestamp(110)); fixture.detectChanges(); prevEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); // Active entry here should be 110 so moving back means moving to 100. - component.timelineCoordinator.updateCurrentTimestamp(timestamp(112)); + component.timelineData.setCurrentTimestamp(timestamp(112)); fixture.detectChanges(); prevEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); // No change when we are already on the first timestamp of the active trace - component.timelineCoordinator.updateCurrentTimestamp(timestamp(100)); + component.timelineData.setCurrentTimestamp(timestamp(100)); fixture.detectChanges(); prevEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(100n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(100n); // No change when we are before the first entry of the active trace - component.timelineCoordinator.updateCurrentTimestamp(timestamp(90)); + component.timelineData.setCurrentTimestamp(timestamp(90)); fixture.detectChanges(); prevEntryButton.nativeElement.click(); - expect(component.timelineCoordinator.currentTimestamp?.getValueNs()).toEqual(90n); + expect(component.timelineData.getCurrentTimestamp()?.getValueNs()).toEqual(90n); }); }); 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 fa0372a77..895d4fdad 100644 --- a/tools/winscope-ng/src/app/components/timeline/timeline.component.ts +++ b/tools/winscope-ng/src/app/components/timeline/timeline.component.ts @@ -30,9 +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 { TimelineCoordinator, TimestampChangeObserver } from "app/timeline_coordinator"; +import { Mediator } from "app/mediator"; +import { TimelineData } from "app/timeline_data"; import { MiniTimelineComponent } from "./mini_timeline.component"; import { Timestamp, TimestampType } from "common/trace/timestamp"; +import { FunctionUtils } from "common/utils/function_utils"; import { TimeUtils } from "common/utils/time_utils"; @Component({ @@ -42,24 +44,25 @@ import { TimeUtils } from "common/utils/time_utils";
-
+

No screenrecording frame to show

Current timestamp before first screenrecording frame.