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 */ 16import {Component, EventEmitter, Input, Output} from '@angular/core'; 17import {Download} from 'common/download'; 18import {UrlUtils} from 'common/url_utils'; 19import {ConnectionState} from 'trace_collection/connection_state'; 20import {ProxyConnection} from 'trace_collection/proxy_connection'; 21 22@Component({ 23 selector: 'adb-proxy', 24 template: ` 25 <ng-container [ngSwitch]="state"> 26 <ng-container *ngSwitchCase="${ConnectionState.NOT_FOUND}"> 27 <div class="further-adb-info-text"> 28 <p class="mat-body-1"> 29 Launch the Winscope ADB Connect proxy to capture traces directly from your browser. 30 </p> 31 <p class="mat-body-1">Python 3.10+ and ADB are required. Run this command:</p> 32 <mat-form-field class="proxy-command-form" appearance="outline"> 33 <input matInput readonly [value]="proxyCommand" /> 34 <button 35 mat-icon-button 36 matSuffix 37 [cdkCopyToClipboard]="proxyCommand" 38 matTooltip="Copy command"> 39 <mat-icon>content_copy</mat-icon> 40 </button> 41 </mat-form-field> 42 <p class="mat-body-1">Or download below.</p> 43 </div> 44 45 <div class="further-adb-info-actions"> 46 <button 47 class="download-proxy-btn" 48 color="primary" 49 mat-stroked-button 50 (click)="onDownloadProxyClick()"> 51 Download Proxy 52 </button> 53 <button color="primary" mat-stroked-button class="retry" (click)="onRetryButtonClick()"> 54 Retry 55 </button> 56 </div> 57 </ng-container> 58 59 <ng-container *ngSwitchCase="${ConnectionState.INVALID_VERSION}"> 60 <div class="further-adb-info-text"> 61 <p class="icon-information mat-body-1"> 62 <mat-icon class="adb-icon">update</mat-icon> 63 <span class="adb-info">Your local proxy version is incompatible with Winscope.</span> 64 </p> 65 <p class="mat-body-1"> 66 Please update the proxy to version {{ proxyVersion }}. Run this command: 67 </p> 68 <mat-form-field class="proxy-command-container" appearance="outline"> 69 <input matInput readonly [value]="proxyCommand" /> 70 <button 71 mat-icon-button 72 matSuffix 73 [cdkCopyToClipboard]="proxyCommand" 74 matTooltip="Copy command"> 75 <mat-icon>content_copy</mat-icon> 76 </button> 77 </mat-form-field> 78 <p class="mat-body-1">Or download below.</p> 79 </div> 80 81 <div class="further-adb-info-actions"> 82 <button 83 class="download-proxy-btn" 84 color="primary" 85 mat-stroked-button 86 (click)="onDownloadProxyClick()"> 87 Download Proxy 88 </button> 89 <button color="primary" mat-stroked-button class="retry" (click)="onRetryButtonClick()"> 90 Retry 91 </button> 92 </div> 93 </ng-container> 94 95 <ng-container *ngSwitchCase="${ConnectionState.UNAUTH}"> 96 <div class="further-adb-info-text"> 97 <p class="icon-information mat-body-1"> 98 <mat-icon class="adb-icon">lock</mat-icon> 99 <span class="adb-info">Proxy authorization required.</span> 100 </p> 101 <p class="mat-body-1">Enter Winscope proxy token:</p> 102 <mat-form-field 103 class="proxy-token-input-field" 104 (keydown.enter)="onKeydownEnterProxyTokenInput($event)"> 105 <input matInput [(ngModel)]="proxyToken" name="proxy-token" /> 106 </mat-form-field> 107 <p class="mat-body-1"> 108 The proxy token is printed to console on proxy launch, copy and paste it above. 109 </p> 110 </div> 111 112 <div class="further-adb-info-actions"> 113 <button color="primary" mat-stroked-button class="retry" (click)="onRetryButtonClick()"> 114 Connect 115 </button> 116 </div> 117 </ng-container> 118 119 <ng-container *ngSwitchDefault></ng-container> 120 </ng-container> 121 `, 122 styles: [ 123 ` 124 .icon-information { 125 display: flex; 126 flex-direction: row; 127 align-items: center; 128 } 129 .further-adb-info-text { 130 display: flex; 131 flex-direction: column; 132 overflow-wrap: break-word; 133 gap: 10px; 134 margin-bottom: 10px; 135 } 136 .further-adb-info-actions { 137 display: flex; 138 flex-direction: row; 139 flex-wrap: wrap; 140 gap: 10px; 141 } 142 /* TODO(b/300063426): remove after migration to angular 15, replace with subscriptSizing */ 143 ::ng-deep .proxy-command-form .mat-form-field-wrapper { 144 padding: 0; 145 } 146 .proxy-command-text { 147 user-select: all; 148 overflow: auto; 149 } 150 .adb-info { 151 margin-left: 5px; 152 } 153 `, 154 ], 155}) 156export class AdbProxyComponent { 157 @Input() state: ConnectionState | undefined; 158 @Output() readonly retryConnection = new EventEmitter<string>(); 159 160 readonly downloadProxyUrl: string = 161 UrlUtils.getRootUrl() + 'winscope_proxy.py'; 162 readonly proxyCommand: string = 163 'python3 $ANDROID_BUILD_TOP/development/tools/winscope/src/adb/winscope_proxy.py'; 164 readonly proxyVersion = ProxyConnection.VERSION; 165 proxyToken = ''; 166 167 onRetryButtonClick() { 168 if (this.state !== ConnectionState.UNAUTH || this.proxyToken.length > 0) { 169 this.retryConnection.emit(this.proxyToken); 170 } 171 } 172 173 onKeydownEnterProxyTokenInput(event: MouseEvent) { 174 (event.target as HTMLInputElement).blur(); 175 this.onRetryButtonClick(); 176 } 177 178 onDownloadProxyClick() { 179 Download.fromUrl(this.downloadProxyUrl, 'winscope_proxy.py'); 180 } 181} 182