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.SHOW_SOFT_INPUT: 193 return "SHOW_SOFT_INPUT"; 194 case SoftInputShowHideReason.ATTACH_NEW_INPUT: 195 return "ATTACH_NEW_INPUT"; 196 case SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME: 197 return "SHOW_SOFT_INPUT_FROM_IME"; 198 case SoftInputShowHideReason.HIDE_SOFT_INPUT: 199 return "HIDE_SOFT_INPUT"; 200 case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME: 201 return "HIDE_SOFT_INPUT_FROM_IME"; 202 case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: 203 return "SHOW_AUTO_EDITOR_FORWARD_NAV"; 204 case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: 205 return "SHOW_STATE_VISIBLE_FORWARD_NAV"; 206 case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE: 207 return "SHOW_STATE_ALWAYS_VISIBLE"; 208 case SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE: 209 return "SHOW_SETTINGS_ON_CHANGE"; 210 case SoftInputShowHideReason.HIDE_SWITCH_USER: 211 return "HIDE_SWITCH_USER"; 212 case SoftInputShowHideReason.HIDE_INVALID_USER: 213 return "HIDE_INVALID_USER"; 214 case SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW: 215 return "HIDE_UNSPECIFIED_WINDOW"; 216 case SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV: 217 return "HIDE_STATE_HIDDEN_FORWARD_NAV"; 218 case SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE: 219 return "HIDE_ALWAYS_HIDDEN_STATE"; 220 case SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND: 221 return "HIDE_RESET_SHELL_COMMAND"; 222 case SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE: 223 return "HIDE_SETTINGS_ON_CHANGE"; 224 case SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME: 225 return "HIDE_POWER_BUTTON_GO_HOME"; 226 case SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED: 227 return "HIDE_DOCKED_STACK_ATTACHED"; 228 case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: 229 return "HIDE_RECENTS_ANIMATION"; 230 case SoftInputShowHideReason.HIDE_BUBBLES: 231 return "HIDE_BUBBLES"; 232 case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR: 233 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; 234 case SoftInputShowHideReason.HIDE_REMOVE_CLIENT: 235 return "HIDE_REMOVE_CLIENT"; 236 case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: 237 return "SHOW_RESTORE_IME_VISIBILITY"; 238 case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT: 239 return "SHOW_TOGGLE_SOFT_INPUT"; 240 case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT: 241 return "HIDE_TOGGLE_SOFT_INPUT"; 242 case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: 243 return "SHOW_SOFT_INPUT_BY_INSETS_API"; 244 case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE: 245 return "HIDE_DISPLAY_IME_POLICY_HIDE"; 246 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API: 247 return "HIDE_SOFT_INPUT_BY_INSETS_API"; 248 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY: 249 return "HIDE_SOFT_INPUT_BY_BACK_KEY"; 250 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT: 251 return "HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT"; 252 case SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED: 253 return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED"; 254 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION: 255 return "HIDE_SOFT_INPUT_IMM_DEPRECATION"; 256 case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR: 257 return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR"; 258 case SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS: 259 return "SHOW_IME_SCREENSHOT_FROM_IMMS"; 260 case SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS: 261 return "REMOVE_IME_SCREENSHOT_FROM_IMMS"; 262 case SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE: 263 return "HIDE_WHEN_INPUT_TARGET_INVISIBLE"; 264 default: 265 return "Unknown=" + reason; 266 } 267 } 268 269 /** 270 * Converts {@link HandwritingGesture.GestureTypeFlags} to {@link String} for debug logging. 271 * 272 * @param gestureTypeFlags integer constant for {@link HandwritingGesture.GestureTypeFlags}. 273 * @return {@link String} message corresponds for the given {@code gestureTypeFlags}. 274 */ handwritingGestureTypeFlagsToString( @andwritingGesture.GestureTypeFlags int gestureTypeFlags)275 public static String handwritingGestureTypeFlagsToString( 276 @HandwritingGesture.GestureTypeFlags int gestureTypeFlags) { 277 final StringJoiner joiner = new StringJoiner("|"); 278 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT) != 0) { 279 joiner.add("SELECT"); 280 } 281 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) != 0) { 282 joiner.add("SELECT_RANGE"); 283 } 284 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_INSERT) != 0) { 285 joiner.add("INSERT"); 286 } 287 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE) != 0) { 288 joiner.add("DELETE"); 289 } 290 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) != 0) { 291 joiner.add("DELETE_RANGE"); 292 } 293 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) != 0) { 294 joiner.add("REMOVE_SPACE"); 295 } 296 if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) != 0) { 297 joiner.add("JOIN_OR_SPLIT"); 298 } 299 return joiner.setEmptyValue("(none)").toString(); 300 } 301 302 /** 303 * Dumps the given {@link View} related to input method focus state for debugging. 304 */ dumpViewInfo(@ullable View view)305 public static String dumpViewInfo(@Nullable View view) { 306 if (view == null) { 307 return "null"; 308 } 309 final StringBuilder sb = new StringBuilder(); 310 sb.append(view); 311 sb.append(",focus=" + view.hasFocus()); 312 sb.append(",windowFocus=" + view.hasWindowFocus()); 313 sb.append(",window=" + view.getWindowToken()); 314 sb.append(",displayId=" + view.getContext().getDisplayId()); 315 sb.append(",temporaryDetach=" + view.isTemporarilyDetached()); 316 sb.append(",hasImeFocus=" + view.hasImeFocus()); 317 318 return sb.toString(); 319 } 320 } 321