1/* 2 * Copyright (C) 2022 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 RemoteToolDownloadStart, 20 RemoteToolFilesReceived, 21 WinscopeEvent, 22 WinscopeEventType, 23} from 'messaging/winscope_event'; 24import { 25 EmitEvent, 26 WinscopeEventEmitter, 27} from 'messaging/winscope_event_emitter'; 28import {WinscopeEventListener} from 'messaging/winscope_event_listener'; 29import { 30 MessageType, 31 OpenBuganizerResponse, 32 OpenRequest, 33 WebCommandMessage, 34} from './messages'; 35 36export class AbtChromeExtensionProtocol 37 implements WinscopeEventEmitter, WinscopeEventListener 38{ 39 static readonly ABT_EXTENSION_ID = 'mbbaofdfoekifkfpgehgffcpagbbjkmj'; 40 41 private emitEvent: EmitEvent = FunctionUtils.DO_NOTHING_ASYNC; 42 43 setEmitEvent(callback: EmitEvent) { 44 this.emitEvent = callback; 45 } 46 47 async onWinscopeEvent(event: WinscopeEvent) { 48 await event.visit(WinscopeEventType.APP_INITIALIZED, async () => { 49 const urlParams = new URLSearchParams(window.location.search); 50 if (urlParams.get('source') !== 'openFromExtension' || !chrome) { 51 return; 52 } 53 54 await this.emitEvent(new RemoteToolDownloadStart()); 55 56 const openRequestMessage: OpenRequest = { 57 action: MessageType.OPEN_REQUEST, 58 }; 59 60 chrome.runtime.sendMessage( 61 AbtChromeExtensionProtocol.ABT_EXTENSION_ID, 62 openRequestMessage, 63 async (message) => await this.onMessageReceived(message), 64 ); 65 }); 66 } 67 68 private async onMessageReceived(message: WebCommandMessage) { 69 if (this.isOpenFromBuganizerResponseMessage(message)) { 70 await this.onOpenFromBuganizerResponseMessageReceived(message); 71 } else { 72 console.warn( 73 'ABT chrome extension protocol received unexpected message:', 74 message, 75 ); 76 } 77 } 78 79 private async onOpenFromBuganizerResponseMessageReceived( 80 message: OpenBuganizerResponse, 81 ) { 82 console.log( 83 'ABT chrome extension protocol received OpenBuganizerResponse message:', 84 message, 85 ); 86 87 if (message.attachments.length === 0) { 88 console.warn('ABT chrome extension protocol received no attachments'); 89 } 90 91 const filesBlobPromises = message.attachments.map(async (attachment) => { 92 const fileQueryResponse = await fetch(attachment.objectUrl); 93 const blob = await fileQueryResponse.blob(); 94 95 // Note: the received blob's media type is wrong. It is always set to "image/png". 96 // Context: http://google3/javascript/closure/html/safeurl.js?g=0&l=256&rcl=273756987 97 // Cloning the blob clears the media type. 98 const file = new File([blob], attachment.name); 99 100 return file; 101 }); 102 103 const files = await Promise.all(filesBlobPromises); 104 await this.emitEvent(new RemoteToolFilesReceived(files)); 105 } 106 107 private isOpenFromBuganizerResponseMessage( 108 message: WebCommandMessage, 109 ): message is OpenBuganizerResponse { 110 return message.action === MessageType.OPEN_BUGANIZER_RESPONSE; 111 } 112} 113