1 /* 2 * Copyright (C) 2018 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 17 package com.android.internal.inputmethod; 18 19 import android.annotation.Nullable; 20 import android.view.View; 21 import android.view.WindowManager; 22 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 23 import android.view.inputmethod.HandwritingGesture; 24 25 import java.util.StringJoiner; 26 27 /** 28 * Provides useful methods for debugging. 29 */ 30 public final class InputMethodDebug { 31 32 /** 33 * Not intended to be instantiated. 34 */ InputMethodDebug()35 private InputMethodDebug() { 36 } 37 38 /** 39 * Converts {@link StartInputReason} to {@link String} for debug logging. 40 * 41 * @param reason integer constant for {@link StartInputReason}. 42 * @return {@link String} message corresponds for the given {@code reason}. 43 */ startInputReasonToString(@tartInputReason int reason)44 public static String startInputReasonToString(@StartInputReason int reason) { 45 switch (reason) { 46 case StartInputReason.UNSPECIFIED: 47 return "UNSPECIFIED"; 48 case StartInputReason.WINDOW_FOCUS_GAIN: 49 return "WINDOW_FOCUS_GAIN"; 50 case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY: 51 return "WINDOW_FOCUS_GAIN_REPORT_ONLY"; 52 case StartInputReason.SCHEDULED_CHECK_FOCUS: 53 return "SCHEDULED_CHECK_FOCUS"; 54 case StartInputReason.APP_CALLED_RESTART_INPUT_API: 55 return "APP_CALLED_RESTART_INPUT_API"; 56 case StartInputReason.CHECK_FOCUS: 57 return "CHECK_FOCUS"; 58 case StartInputReason.BOUND_TO_IMMS: 59 return "BOUND_TO_IMMS"; 60 case StartInputReason.UNBOUND_FROM_IMMS: 61 return "UNBOUND_FROM_IMMS"; 62 case StartInputReason.ACTIVATED_BY_IMMS: 63 return "ACTIVATED_BY_IMMS"; 64 case StartInputReason.DEACTIVATED_BY_IMMS: 65 return "DEACTIVATED_BY_IMMS"; 66 case StartInputReason.SESSION_CREATED_BY_IME: 67 return "SESSION_CREATED_BY_IME"; 68 case StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS: 69 return "BOUND_ACCESSIBILITY_SESSION_TO_IMMS"; 70 default: 71 return "Unknown=" + reason; 72 } 73 } 74 75 /** 76 * Converts {@link UnbindReason} to {@link String} for debug logging. 77 * 78 * @param reason integer constant for {@link UnbindReason}. 79 * @return {@link String} message corresponds for the given {@code reason}. 80 */ unbindReasonToString(@nbindReason int reason)81 public static String unbindReasonToString(@UnbindReason int reason) { 82 switch (reason) { 83 case UnbindReason.UNSPECIFIED: 84 return "UNSPECIFIED"; 85 case UnbindReason.SWITCH_CLIENT: 86 return "SWITCH_CLIENT"; 87 case UnbindReason.SWITCH_IME: 88 return "SWITCH_IME"; 89 case UnbindReason.DISCONNECT_IME: 90 return "DISCONNECT_IME"; 91 case UnbindReason.NO_IME: 92 return "NO_IME"; 93 case UnbindReason.SWITCH_IME_FAILED: 94 return "SWITCH_IME_FAILED"; 95 case UnbindReason.SWITCH_USER: 96 return "SWITCH_USER"; 97 default: 98 return "Unknown=" + reason; 99 } 100 } 101 102 /** 103 * Converts {@link SoftInputModeFlags} to {@link String} for debug logging. 104 * 105 * @param softInputMode integer constant for {@link SoftInputModeFlags}. 106 * @return {@link String} message corresponds for the given {@code softInputMode}. 107 */ softInputModeToString(@oftInputModeFlags int softInputMode)108 public static String softInputModeToString(@SoftInputModeFlags int softInputMode) { 109 final StringJoiner joiner = new StringJoiner("|"); 110 final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; 111 final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 112 final boolean isForwardNav = 113 (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; 114 115 switch (state) { 116 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: 117 joiner.add("STATE_UNSPECIFIED"); 118 break; 119 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: 120 joiner.add("STATE_UNCHANGED"); 121 break; 122 case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: 123 joiner.add("STATE_HIDDEN"); 124 break; 125 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: 126 joiner.add("STATE_ALWAYS_HIDDEN"); 127 break; 128 case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: 129 joiner.add("STATE_VISIBLE"); 130 break; 131 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: 132 joiner.add("STATE_ALWAYS_VISIBLE"); 133 break; 134 default: 135 joiner.add("STATE_UNKNOWN(" + state + ")"); 136 break; 137 } 138 139 switch (adjust) { 140 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: 141 joiner.add("ADJUST_UNSPECIFIED"); 142 break; 143 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE: 144 joiner.add("ADJUST_RESIZE"); 145 break; 146 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN: 147 joiner.add("ADJUST_PAN"); 148 break; 149 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING: 150 joiner.add("ADJUST_NOTHING"); 151 break; 152 default: 153 joiner.add("ADJUST_UNKNOWN(" + adjust + ")"); 154 break; 155 } 156 157 if (isForwardNav) { 158 // This is a special bit that is set by the system only during the window navigation. 159 joiner.add("IS_FORWARD_NAVIGATION"); 160 } 161 162 return joiner.setEmptyValue("(none)").toString(); 163 } 164 165 /** 166 * Converts {@link StartInputFlags} to {@link String} for debug logging. 167 * 168 * @param startInputFlags integer constant for {@link StartInputFlags}. 169 * @return {@link String} message corresponds for the given {@code startInputFlags}. 170 */ startInputFlagsToString(@tartInputFlags int startInputFlags)171 public static String startInputFlagsToString(@StartInputFlags int startInputFlags) { 172 final StringJoiner joiner = new StringJoiner("|"); 173 if ((startInputFlags & StartInputFlags.VIEW_HAS_FOCUS) != 0) { 174 joiner.add("VIEW_HAS_FOCUS"); 175 } 176 if ((startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) { 177 joiner.add("IS_TEXT_EDITOR"); 178 } 179 if ((startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0) { 180 joiner.add("INITIAL_CONNECTION"); 181 } 182 183 return joiner.setEmptyValue("(none)").toString(); 184 } 185 186 187 /** 188 * Converts {@link SoftInputShowHideReason} to {@link String} for history dump. 189 */ softInputDisplayReasonToString(@oftInputShowHideReason int reason)190 public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) { 191 switch (reason) { 192 case SoftInputShowHideReason.NOT_SET: 193 return "NOT_SET"; 194 case SoftInputShowHideReason.SHOW_SOFT_INPUT: 195 return "SHOW_SOFT_INPUT"; 196 case SoftInputShowHideReason.ATTACH_NEW_INPUT: 197 return "ATTACH_NEW_INPUT"; 198 case SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME: 199 return "SHOW_SOFT_INPUT_FROM_IME"; 200 case SoftInputShowHideReason.HIDE_SOFT_INPUT: 201 return "HIDE_SOFT_INPUT"; 202 case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME: 203 return "HIDE_SOFT_INPUT_FROM_IME"; 204 case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: 205 return "SHOW_AUTO_EDITOR_FORWARD_NAV"; 206 case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: 207 return "SHOW_STATE_VISIBLE_FORWARD_NAV"; 208 case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE: 209 return "SHOW_STATE_ALWAYS_VISIBLE"; 210 case SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE: 211 return "SHOW_SETTINGS_ON_CHANGE"; 212 case SoftInputShowHideReason.HIDE_SWITCH_USER: 213 return "HIDE_SWITCH_USER"; 214 case SoftInputShowHideReason.HIDE_INVALID_USER: 215 return "HIDE_INVALID_USER"; 216 case SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW: 217 return "HIDE_UNSPECIFIED_WINDOW"; 218 case SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV: 219 return "HIDE_STATE_HIDDEN_FORWARD_NAV"; 220 case SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE: 221 return "HIDE_ALWAYS_HIDDEN_STATE"; 222 case SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND: 223 return "HIDE_RESET_SHELL_COMMAND"; 224 case SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE: 225 return "HIDE_SETTINGS_ON_CHANGE"; 226 case SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME: 227 return "HIDE_POWER_BUTTON_GO_HOME"; 228 case SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED: 229 return "HIDE_DOCKED_STACK_ATTACHED"; 230 case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: 231 return "HIDE_RECENTS_ANIMATION"; 232 case SoftInputShowHideReason.HIDE_BUBBLES: 233 return "HIDE_BUBBLES"; 234 case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR: 235 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; 236 case SoftInputShowHideReason.HIDE_REMOVE_CLIENT: 237 return "HIDE_REMOVE_CLIENT"; 238 case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: 239 return "SHOW_RESTORE_IME_VISIBILITY"; 240 case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT: 241 return "SHOW_TOGGLE_SOFT_INPUT"; 242 case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT: 243 return "HIDE_TOGGLE_SOFT_INPUT"; 244 case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: 245 return "SHOW_SOFT_INPUT_BY_INSETS_API"; 246 case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE: 247 return "HIDE_DISPLAY_IME_POLICY_HIDE"; 248 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API: 249 return "HIDE_SOFT_INPUT_BY_INSETS_API"; 250 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY: 251 return "HIDE_SOFT_INPUT_BY_BACK_KEY"; 252 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT: 253 return "HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT"; 254 case SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED: 255 return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED"; 256 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION: 257 return "HIDE_SOFT_INPUT_IMM_DEPRECATION"; 258 case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR: 259 return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR"; 260 case SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS: 261 return "SHOW_IME_SCREENSHOT_FROM_IMMS"; 262 case SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS: 263 return "REMOVE_IME_SCREENSHOT_FROM_IMMS"; 264 case SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE: 265 return "HIDE_WHEN_INPUT_TARGET_INVISIBLE"; 266 case SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION: 267 return "HIDE_SOFT_INPUT_CLOSE_CURRENT_SESSION"; 268 case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW: 269 return "HIDE_SOFT_INPUT_FROM_VIEW"; 270 case SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT: 271 return "SHOW_SOFT_INPUT_LEGACY_DIRECT"; 272 case SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT: 273 return "HIDE_SOFT_INPUT_LEGACY_DIRECT"; 274 case SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT: 275 return "SHOW_WINDOW_LEGACY_DIRECT"; 276 case SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT: 277 return "HIDE_WINDOW_LEGACY_DIRECT"; 278 case SoftInputShowHideReason.RESET_NEW_CONFIGURATION: 279 return "RESET_NEW_CONFIGURATION"; 280 case SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY: 281 return "UPDATE_CANDIDATES_VIEW_VISIBILITY"; 282 case SoftInputShowHideReason.CONTROLS_CHANGED: 283 return "CONTROLS_CHANGED"; 284 case SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED: 285 return "DISPLAY_CONFIGURATION_CHANGED"; 286 case SoftInputShowHideReason.DISPLAY_INSETS_CHANGED: 287 return "DISPLAY_INSETS_CHANGED"; 288 case SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED: 289 return "DISPLAY_CONTROLS_CHANGED"; 290 case SoftInputShowHideReason.UNBIND_CURRENT_METHOD: 291 return "UNBIND_CURRENT_METHOD"; 292 case SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED: 293 return "HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED"; 294 case SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL: 295 return "HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL"; 296 case SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT: 297 return "SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT"; 298 case SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION: 299 return "SHOW_SOFT_INPUT_IMM_DEPRECATION"; 300 case SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION: 301 return "CONTROL_WINDOW_INSETS_ANIMATION"; 302 default: 303 return "Unknown=" + reason; 304 } 305 } 306 307 /** 308 * Converts {@link HandwritingGesture.GestureTypeFlags} to {@link String} for debug logging. 309 * 310 * @param gestureTypeFlags integer constant for {@link HandwritingGesture.GestureTypeFlags}. 311 * @return {@link String} message corresponds for the given {@code gestureTypeFlags}. 312 */ handwritingGestureTypeFlagsToString( @andwritingGesture.GestureTypeFlags int gestureTypeFlags)313 public static String handwritingGestureTypeFlagsToString( 314 @HandwritingGesture.GestureTypeFlags int gestureTypeFlags) { 315 final StringJoiner joiner = new StringJoiner("|"); 316 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT) != 0) { 317 joiner.add("SELECT"); 318 } 319 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) != 0) { 320 joiner.add("SELECT_RANGE"); 321 } 322 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_INSERT) != 0) { 323 joiner.add("INSERT"); 324 } 325 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE) != 0) { 326 joiner.add("DELETE"); 327 } 328 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) != 0) { 329 joiner.add("DELETE_RANGE"); 330 } 331 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) != 0) { 332 joiner.add("REMOVE_SPACE"); 333 } 334 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) != 0) { 335 joiner.add("JOIN_OR_SPLIT"); 336 } 337 return joiner.setEmptyValue("(none)").toString(); 338 } 339 340 /** 341 * Dumps the given {@link View} related to input method focus state for debugging. 342 */ dumpViewInfo(@ullable View view)343 public static String dumpViewInfo(@Nullable View view) { 344 if (view == null) { 345 return "null"; 346 } 347 final StringBuilder sb = new StringBuilder(); 348 sb.append(view); 349 sb.append(",focus=" + view.hasFocus()); 350 sb.append(",windowFocus=" + view.hasWindowFocus()); 351 sb.append(",window=" + view.getWindowToken()); 352 sb.append(",displayId=" + view.getContext().getDisplayId()); 353 sb.append(",temporaryDetach=" + view.isTemporarilyDetached()); 354 sb.append(",hasImeFocus=" + view.hasImeFocus()); 355 356 return sb.toString(); 357 } 358 } 359