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.AnyThread; 20 import android.annotation.NonNull; 21 import android.view.WindowManager; 22 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 23 24 import java.util.StringJoiner; 25 26 /** 27 * Provides useful methods for debugging. 28 */ 29 public final class InputMethodDebug { 30 31 /** 32 * Not intended to be instantiated. 33 */ InputMethodDebug()34 private InputMethodDebug() { 35 } 36 37 /** 38 * Converts {@link StartInputReason} to {@link String} for debug logging. 39 * 40 * @param reason integer constant for {@link StartInputReason}. 41 * @return {@link String} message corresponds for the given {@code reason}. 42 */ startInputReasonToString(@tartInputReason int reason)43 public static String startInputReasonToString(@StartInputReason int reason) { 44 switch (reason) { 45 case StartInputReason.UNSPECIFIED: 46 return "UNSPECIFIED"; 47 case StartInputReason.WINDOW_FOCUS_GAIN: 48 return "WINDOW_FOCUS_GAIN"; 49 case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION: 50 return "WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION"; 51 case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION: 52 return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION"; 53 case StartInputReason.APP_CALLED_RESTART_INPUT_API: 54 return "APP_CALLED_RESTART_INPUT_API"; 55 case StartInputReason.CHECK_FOCUS: 56 return "CHECK_FOCUS"; 57 case StartInputReason.BOUND_TO_IMMS: 58 return "BOUND_TO_IMMS"; 59 case StartInputReason.UNBOUND_FROM_IMMS: 60 return "UNBOUND_FROM_IMMS"; 61 case StartInputReason.ACTIVATED_BY_IMMS: 62 return "ACTIVATED_BY_IMMS"; 63 case StartInputReason.DEACTIVATED_BY_IMMS: 64 return "DEACTIVATED_BY_IMMS"; 65 case StartInputReason.SESSION_CREATED_BY_IME: 66 return "SESSION_CREATED_BY_IME"; 67 case StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS: 68 return "BOUND_ACCESSIBILITY_SESSION_TO_IMMS"; 69 default: 70 return "Unknown=" + reason; 71 } 72 } 73 74 /** 75 * Converts {@link UnbindReason} to {@link String} for debug logging. 76 * 77 * @param reason integer constant for {@link UnbindReason}. 78 * @return {@link String} message corresponds for the given {@code reason}. 79 */ unbindReasonToString(@nbindReason int reason)80 public static String unbindReasonToString(@UnbindReason int reason) { 81 switch (reason) { 82 case UnbindReason.UNSPECIFIED: 83 return "UNSPECIFIED"; 84 case UnbindReason.SWITCH_CLIENT: 85 return "SWITCH_CLIENT"; 86 case UnbindReason.SWITCH_IME: 87 return "SWITCH_IME"; 88 case UnbindReason.DISCONNECT_IME: 89 return "DISCONNECT_IME"; 90 case UnbindReason.NO_IME: 91 return "NO_IME"; 92 case UnbindReason.SWITCH_IME_FAILED: 93 return "SWITCH_IME_FAILED"; 94 case UnbindReason.SWITCH_USER: 95 return "SWITCH_USER"; 96 case UnbindReason.ACCESSIBILITY_SERVICE_DISABLED: 97 return "ACCESSIBILITY_SERVICE_DISABLED"; 98 default: 99 return "Unknown=" + reason; 100 } 101 } 102 103 /** 104 * Converts {@link SoftInputModeFlags} to {@link String} for debug logging. 105 * 106 * @param softInputMode integer constant for {@link SoftInputModeFlags}. 107 * @return {@link String} message corresponds for the given {@code softInputMode}. 108 */ softInputModeToString(@oftInputModeFlags int softInputMode)109 public static String softInputModeToString(@SoftInputModeFlags int softInputMode) { 110 final StringJoiner joiner = new StringJoiner("|"); 111 final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; 112 final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 113 final boolean isForwardNav = 114 (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; 115 116 switch (state) { 117 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: 118 joiner.add("STATE_UNSPECIFIED"); 119 break; 120 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: 121 joiner.add("STATE_UNCHANGED"); 122 break; 123 case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: 124 joiner.add("STATE_HIDDEN"); 125 break; 126 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: 127 joiner.add("STATE_ALWAYS_HIDDEN"); 128 break; 129 case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: 130 joiner.add("STATE_VISIBLE"); 131 break; 132 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: 133 joiner.add("STATE_ALWAYS_VISIBLE"); 134 break; 135 default: 136 joiner.add("STATE_UNKNOWN(" + state + ")"); 137 break; 138 } 139 140 switch (adjust) { 141 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: 142 joiner.add("ADJUST_UNSPECIFIED"); 143 break; 144 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE: 145 joiner.add("ADJUST_RESIZE"); 146 break; 147 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN: 148 joiner.add("ADJUST_PAN"); 149 break; 150 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING: 151 joiner.add("ADJUST_NOTHING"); 152 break; 153 default: 154 joiner.add("ADJUST_UNKNOWN(" + adjust + ")"); 155 break; 156 } 157 158 if (isForwardNav) { 159 // This is a special bit that is set by the system only during the window navigation. 160 joiner.add("IS_FORWARD_NAVIGATION"); 161 } 162 163 return joiner.setEmptyValue("(none)").toString(); 164 } 165 166 /** 167 * Converts {@link StartInputFlags} to {@link String} for debug logging. 168 * 169 * @param startInputFlags integer constant for {@link StartInputFlags}. 170 * @return {@link String} message corresponds for the given {@code startInputFlags}. 171 */ startInputFlagsToString(@tartInputFlags int startInputFlags)172 public static String startInputFlagsToString(@StartInputFlags int startInputFlags) { 173 final StringJoiner joiner = new StringJoiner("|"); 174 if ((startInputFlags & StartInputFlags.VIEW_HAS_FOCUS) != 0) { 175 joiner.add("VIEW_HAS_FOCUS"); 176 } 177 if ((startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) { 178 joiner.add("IS_TEXT_EDITOR"); 179 } 180 if ((startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0) { 181 joiner.add("INITIAL_CONNECTION"); 182 } 183 184 return joiner.setEmptyValue("(none)").toString(); 185 } 186 187 188 /** 189 * Converts {@link SoftInputShowHideReason} to {@link String} for history dump. 190 */ softInputDisplayReasonToString(@oftInputShowHideReason int reason)191 public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) { 192 switch (reason) { 193 case SoftInputShowHideReason.SHOW_SOFT_INPUT: 194 return "SHOW_SOFT_INPUT"; 195 case SoftInputShowHideReason.ATTACH_NEW_INPUT: 196 return "ATTACH_NEW_INPUT"; 197 case SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME: 198 return "SHOW_SOFT_INPUT_FROM_IME"; 199 case SoftInputShowHideReason.HIDE_SOFT_INPUT: 200 return "HIDE_SOFT_INPUT"; 201 case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME: 202 return "HIDE_SOFT_INPUT_FROM_IME"; 203 case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: 204 return "SHOW_AUTO_EDITOR_FORWARD_NAV"; 205 case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: 206 return "SHOW_STATE_VISIBLE_FORWARD_NAV"; 207 case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE: 208 return "SHOW_STATE_ALWAYS_VISIBLE"; 209 case SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE: 210 return "SHOW_SETTINGS_ON_CHANGE"; 211 case SoftInputShowHideReason.HIDE_SWITCH_USER: 212 return "HIDE_SWITCH_USER"; 213 case SoftInputShowHideReason.HIDE_INVALID_USER: 214 return "HIDE_INVALID_USER"; 215 case SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW: 216 return "HIDE_UNSPECIFIED_WINDOW"; 217 case SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV: 218 return "HIDE_STATE_HIDDEN_FORWARD_NAV"; 219 case SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE: 220 return "HIDE_ALWAYS_HIDDEN_STATE"; 221 case SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND: 222 return "HIDE_RESET_SHELL_COMMAND"; 223 case SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE: 224 return "HIDE_SETTINGS_ON_CHANGE"; 225 case SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME: 226 return "HIDE_POWER_BUTTON_GO_HOME"; 227 case SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED: 228 return "HIDE_DOCKED_STACK_ATTACHED"; 229 case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: 230 return "HIDE_RECENTS_ANIMATION"; 231 case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR: 232 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; 233 case SoftInputShowHideReason.HIDE_REMOVE_CLIENT: 234 return "HIDE_REMOVE_CLIENT"; 235 case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: 236 return "SHOW_RESTORE_IME_VISIBILITY"; 237 case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT: 238 return "SHOW_TOGGLE_SOFT_INPUT"; 239 case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT: 240 return "HIDE_TOGGLE_SOFT_INPUT"; 241 case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: 242 return "SHOW_SOFT_INPUT_BY_INSETS_API"; 243 case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE: 244 return "HIDE_DISPLAY_IME_POLICY_HIDE"; 245 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API: 246 return "HIDE_SOFT_INPUT_BY_INSETS_API"; 247 case SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY: 248 return "HIDE_SOFT_INPUT_BY_BACK_KEY"; 249 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT: 250 return "HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT"; 251 case SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED: 252 return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED"; 253 case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION: 254 return "HIDE_SOFT_INPUT_IMM_DEPRECATION"; 255 default: 256 return "Unknown=" + reason; 257 } 258 } 259 260 /** 261 * Return a fixed size string of the object. 262 * TODO(b/151575861): Take & return with StringBuilder to make more memory efficient. 263 */ 264 @NonNull 265 @AnyThread objToString(Object obj)266 public static String objToString(Object obj) { 267 if (obj == null) { 268 return "null"; 269 } 270 StringBuilder sb = new StringBuilder(64); 271 sb.setLength(0); 272 sb.append(obj.getClass().getName()); 273 sb.append("@"); 274 sb.append(Integer.toHexString(obj.hashCode())); 275 return sb.toString(); 276 } 277 } 278