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 {FilterType, TreeUtils} from 'common/tree_utils'; 17import {WindowContainer} from 'trace/flickerlib/common'; 18import {Layer} from 'trace/flickerlib/layers/Layer'; 19import {LayerTraceEntry} from 'trace/flickerlib/layers/LayerTraceEntry'; 20import {Activity} from 'trace/flickerlib/windows/Activity'; 21import {WindowManagerState} from 'trace/flickerlib/windows/WindowManagerState'; 22import {WindowState} from 'trace/flickerlib/windows/WindowState'; 23 24class ProcessedWindowManagerState { 25 constructor( 26 public name: string, 27 public stableId: string, 28 public focusedApp: string, 29 public focusedWindow: WindowState, 30 public focusedActivity: Activity, 31 public isInputMethodWindowVisible: boolean, 32 public protoImeControlTarget: any, 33 public protoImeInputTarget: any, 34 public protoImeLayeringTarget: any, 35 public protoImeInsetsSourceProvider: any, 36 public proto: any 37 ) {} 38} 39 40class ImeLayers { 41 constructor( 42 public name: string, 43 public imeContainer: Layer, 44 public inputMethodSurface: Layer, 45 public focusedWindow: Layer | undefined, 46 public taskOfImeContainer: Layer | undefined, 47 public taskOfImeSnapshot: Layer | undefined 48 ) {} 49} 50 51class ImeUtils { 52 static processWindowManagerTraceEntry(entry: WindowManagerState): ProcessedWindowManagerState { 53 const displayContent = entry.root.children[0]; 54 55 return new ProcessedWindowManagerState( 56 entry.name, 57 entry.stableId, 58 entry.focusedApp, 59 entry.focusedWindow, 60 entry.focusedActivity, 61 ImeUtils.isInputMethodVisible(displayContent), 62 ImeUtils.getImeControlTargetProperty(displayContent.proto), 63 ImeUtils.getImeInputTargetProperty(displayContent.proto), 64 ImeUtils.getImeLayeringTargetProperty(displayContent.proto), 65 displayContent.proto.imeInsetsSourceProvider, 66 entry.proto 67 ); 68 } 69 70 static getImeLayers( 71 entry: LayerTraceEntry, 72 processedWindowManagerState: ProcessedWindowManagerState 73 ): ImeLayers | undefined { 74 const isImeContainer = TreeUtils.makeNodeFilter('ImeContainer'); 75 const imeContainer = TreeUtils.findDescendantNode(entry, isImeContainer); 76 if (!imeContainer) { 77 return undefined; 78 } 79 80 const isInputMethodSurface = TreeUtils.makeNodeFilter('InputMethod'); 81 const inputMethodSurface = TreeUtils.findDescendantNode(imeContainer, isInputMethodSurface); 82 83 let focusedWindowLayer: Layer = undefined; 84 const focusedWindowToken = processedWindowManagerState.focusedWindow?.token; 85 if (focusedWindowToken) { 86 const isFocusedWindow = TreeUtils.makeNodeFilter(focusedWindowToken); 87 focusedWindowLayer = TreeUtils.findDescendantNode(entry, isFocusedWindow); 88 } 89 90 // we want to see both ImeContainer and IME-snapshot if there are 91 // cases where both exist 92 const taskLayerOfImeContainer = ImeUtils.findAncestorTaskLayerOfImeLayer( 93 entry, 94 TreeUtils.makeNodeFilter('ImeContainer') 95 ); 96 97 const taskLayerOfImeSnapshot = ImeUtils.findAncestorTaskLayerOfImeLayer( 98 entry, 99 TreeUtils.makeNodeFilter('IME-snapshot') 100 ); 101 102 return new ImeLayers( 103 entry.name, 104 imeContainer, 105 inputMethodSurface, 106 focusedWindowLayer, 107 taskLayerOfImeContainer, 108 taskLayerOfImeSnapshot 109 ); 110 } 111 112 static transformInputConnectionCall(entry: any) { 113 const obj = Object.assign({}, entry); 114 if (obj.inputConnectionCall) { 115 Object.getOwnPropertyNames(obj.inputConnectionCall).forEach((name) => { 116 const value = Object.getOwnPropertyDescriptor(obj.inputConnectionCall, name); 117 if (!value?.value) delete obj.inputConnectionCall[name]; 118 }); 119 } 120 return obj; 121 } 122 123 private static findAncestorTaskLayerOfImeLayer( 124 entry: LayerTraceEntry, 125 isTargetImeLayer: FilterType 126 ): Layer { 127 const imeLayer = TreeUtils.findDescendantNode(entry, isTargetImeLayer); 128 if (!imeLayer) { 129 return undefined; 130 } 131 132 const isTaskLayer = TreeUtils.makeNodeFilter('Task|ImePlaceholder'); 133 const taskLayer = TreeUtils.findAncestorNode(imeLayer, isTaskLayer) as Layer; 134 if (!taskLayer) { 135 return undefined; 136 } 137 138 taskLayer.kind = 'SF subtree - ' + taskLayer.id; 139 return taskLayer; 140 } 141 142 private static getImeControlTargetProperty(displayContentProto: any): any { 143 const POSSIBLE_NAMES = ['inputMethodControlTarget', 'imeControlTarget']; 144 return ImeUtils.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); 145 } 146 147 private static getImeInputTargetProperty(displayContentProto: any): any { 148 const POSSIBLE_NAMES = ['inputMethodInputTarget', 'imeInputTarget']; 149 return ImeUtils.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); 150 } 151 152 private static getImeLayeringTargetProperty(displayContentProto: any): any { 153 const POSSIBLE_NAMES = ['inputMethodTarget', 'imeLayeringTarget']; 154 return ImeUtils.findAnyPropertyWithMatchingName(displayContentProto, POSSIBLE_NAMES); 155 } 156 157 private static findAnyPropertyWithMatchingName(object: any, possible_names: string[]): any { 158 const key = Object.keys(object).find((key) => possible_names.includes(key)); 159 return key ? object[key] : undefined; 160 } 161 162 private static isInputMethodVisible(displayContent: WindowContainer): boolean { 163 const isInputMethod = TreeUtils.makeNodeFilter('InputMethod'); 164 const inputMethodWindowOrLayer = TreeUtils.findDescendantNode( 165 displayContent, 166 isInputMethod 167 ) as WindowContainer; 168 return inputMethodWindowOrLayer?.isVisible === true; 169 } 170} 171 172export {ImeUtils, ProcessedWindowManagerState, ImeLayers}; 173