/* * 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 {ChangeDetectorRef, Component, Inject} from '@angular/core'; import {FunctionUtils} from 'common/function_utils'; import { Message, MessageBugReport, MessagePing, MessageTimestamp, MessageType, } from 'cross_tool/messages'; @Component({ selector: 'app-root', template: ` Remote Tool Mock (simulates cross-tool protocol)

Open Winscope tab


Send bugreport


Send timestamp [ns]


Received timestamp:

`, }) export class AppComponent { static readonly TARGET = 'http://localhost:8080'; static readonly TIMESTAMP_IN_BUGREPORT_MESSAGE = 1670509911000000000n; private winscope: Window | null = null; private isWinscopeUp = false; private onMessagePongReceived = FunctionUtils.DO_NOTHING; constructor(@Inject(ChangeDetectorRef) private changeDetectorRef: ChangeDetectorRef) { window.addEventListener('message', (event) => { this.onMessageReceived(event); }); } async onButtonOpenWinscopeClick() { this.openWinscope(); await this.waitWinscopeUp(); } async onUploadBugreport(event: Event) { const [file, buffer] = await this.readInputFile(event); this.sendBugreport(file, buffer); } onButtonSendTimestampClick() { const inputTimestampElement = document.querySelector('.input-timestamp')! as HTMLInputElement; this.sendTimestamp(BigInt(inputTimestampElement.value)); } private openWinscope() { this.printStatus('OPENING WINSCOPE'); this.winscope = window.open(AppComponent.TARGET); if (!this.winscope) { throw new Error('Failed to open winscope'); } this.printStatus('OPENED WINSCOPE'); } private async waitWinscopeUp() { this.printStatus('WAITING WINSCOPE UP'); const promise = new Promise((resolve) => { this.onMessagePongReceived = () => { this.isWinscopeUp = true; resolve(); }; }); setTimeout(async () => { while (!this.isWinscopeUp) { this.winscope!.postMessage(new MessagePing(), AppComponent.TARGET); await this.sleep(10); } }, 0); await promise; this.printStatus('DONE WAITING (WINSCOPE IS UP)'); } private sendBugreport(file: File, buffer: ArrayBuffer) { this.printStatus('SENDING BUGREPORT'); this.winscope!.postMessage( new MessageBugReport(file, AppComponent.TIMESTAMP_IN_BUGREPORT_MESSAGE), AppComponent.TARGET ); this.printStatus('SENT BUGREPORT'); } private sendTimestamp(value: bigint) { this.printStatus('SENDING TIMESTAMP'); this.winscope!.postMessage(new MessageTimestamp(value), AppComponent.TARGET); this.printStatus('SENT TIMESTAMP'); } private onMessageReceived(event: MessageEvent) { const message = event.data as Message; if (!message.type) { console.log('Cross-tool protocol received unrecognized message:', message); return; } switch (message.type) { case MessageType.PING: console.log('Cross-tool protocol received unexpected ping message:', message); break; case MessageType.PONG: this.onMessagePongReceived(); break; case MessageType.BUGREPORT: console.log('Cross-tool protocol received unexpected bugreport message:', message); break; case MessageType.TIMESTAMP: console.log('Cross-tool protocol received timestamp message:', message); this.onMessageTimestampReceived(message as MessageTimestamp); break; case MessageType.FILES: console.log('Cross-tool protocol received unexpected files message:', message); break; default: console.log('Cross-tool protocol received unrecognized message:', message); break; } } private onMessageTimestampReceived(message: MessageTimestamp) { const paragraph = document.querySelector( '.paragraph-received-timestamp' ) as HTMLParagraphElement; paragraph.textContent = message.timestampNs.toString(); this.changeDetectorRef.detectChanges(); } private printStatus(status: string) { console.log('STATUS: ' + status); } private sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } private async readInputFile(event: Event): Promise<[File, ArrayBuffer]> { const files: FileList | null = (event?.target as HTMLInputElement)?.files; if (!files || !files[0]) { throw new Error('Failed to read input files'); } return [files[0], await files[0].arrayBuffer()]; } }