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 default: 68 return "Unknown=" + reason; 69 } 70 } 71 72 /** 73 * Converts {@link UnbindReason} to {@link String} for debug logging. 74 * 75 * @param reason integer constant for {@link UnbindReason}. 76 * @return {@link String} message corresponds for the given {@code reason}. 77 */ unbindReasonToString(@nbindReason int reason)78 public static String unbindReasonToString(@UnbindReason int reason) { 79 switch (reason) { 80 case UnbindReason.UNSPECIFIED: 81 return "UNSPECIFIED"; 82 case UnbindReason.SWITCH_CLIENT: 83 return "SWITCH_CLIENT"; 84 case UnbindReason.SWITCH_IME: 85 return "SWITCH_IME"; 86 case UnbindReason.DISCONNECT_IME: 87 return "DISCONNECT_IME"; 88 case UnbindReason.NO_IME: 89 return "NO_IME"; 90 case UnbindReason.SWITCH_IME_FAILED: 91 return "SWITCH_IME_FAILED"; 92 case UnbindReason.SWITCH_USER: 93 return "SWITCH_USER"; 94 default: 95 return "Unknown=" + reason; 96 } 97 } 98 99 /** 100 * Converts {@link SoftInputModeFlags} to {@link String} for debug logging. 101 * 102 * @param softInputMode integer constant for {@link SoftInputModeFlags}. 103 * @return {@link String} message corresponds for the given {@code softInputMode}. 104 */ softInputModeToString(@oftInputModeFlags int softInputMode)105 public static String softInputModeToString(@SoftInputModeFlags int softInputMode) { 106 final StringJoiner joiner = new StringJoiner("|"); 107 final int state = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE; 108 final int adjust = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 109 final boolean isForwardNav = 110 (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0; 111 112 switch (state) { 113 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: 114 joiner.add("STATE_UNSPECIFIED"); 115 break; 116 case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: 117 joiner.add("STATE_UNCHANGED"); 118 break; 119 case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: 120 joiner.add("STATE_HIDDEN"); 121 break; 122 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: 123 joiner.add("STATE_ALWAYS_HIDDEN"); 124 break; 125 case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: 126 joiner.add("STATE_VISIBLE"); 127 break; 128 case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: 129 joiner.add("STATE_ALWAYS_VISIBLE"); 130 break; 131 default: 132 joiner.add("STATE_UNKNOWN(" + state + ")"); 133 break; 134 } 135 136 switch (adjust) { 137 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED: 138 joiner.add("ADJUST_UNSPECIFIED"); 139 break; 140 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE: 141 joiner.add("ADJUST_RESIZE"); 142 break; 143 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN: 144 joiner.add("ADJUST_PAN"); 145 break; 146 case WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING: 147 joiner.add("ADJUST_NOTHING"); 148 break; 149 default: 150 joiner.add("ADJUST_UNKNOWN(" + adjust + ")"); 151 break; 152 } 153 154 if (isForwardNav) { 155 // This is a special bit that is set by the system only during the window navigation. 156 joiner.add("IS_FORWARD_NAVIGATION"); 157 } 158 159 return joiner.setEmptyValue("(none)").toString(); 160 } 161 162 /** 163 * Converts {@link StartInputFlags} to {@link String} for debug logging. 164 * 165 * @param startInputFlags integer constant for {@link StartInputFlags}. 166 * @return {@link String} message corresponds for the given {@code startInputFlags}. 167 */ startInputFlagsToString(@tartInputFlags int startInputFlags)168 public static String startInputFlagsToString(@StartInputFlags int startInputFlags) { 169 final StringJoiner joiner = new StringJoiner("|"); 170 if ((startInputFlags & StartInputFlags.VIEW_HAS_FOCUS) != 0) { 171 joiner.add("VIEW_HAS_FOCUS"); 172 } 173 if ((startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) { 174 joiner.add("IS_TEXT_EDITOR"); 175 } 176 if ((startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0) { 177 joiner.add("INITIAL_CONNECTION"); 178 } 179 180 return joiner.setEmptyValue("(none)").toString(); 181 } 182 183 184 /** 185 * Converts {@link SoftInputShowHideReason} to {@link String} for history dump. 186 */ softInputDisplayReasonToString(@oftInputShowHideReason int reason)187 public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) { 188 switch (reason) { 189 case SoftInputShowHideReason.SHOW_SOFT_INPUT: 190 return "SHOW_SOFT_INPUT"; 191 case SoftInputShowHideReason.ATTACH_NEW_INPUT: 192 return "ATTACH_NEW_INPUT"; 193 case SoftInputShowHideReason.SHOW_MY_SOFT_INPUT: 194 return "SHOW_MY_SOFT_INPUT"; 195 case SoftInputShowHideReason.HIDE_SOFT_INPUT: 196 return "HIDE_SOFT_INPUT"; 197 case SoftInputShowHideReason.HIDE_MY_SOFT_INPUT: 198 return "HIDE_MY_SOFT_INPUT"; 199 case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV: 200 return "SHOW_AUTO_EDITOR_FORWARD_NAV"; 201 case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV: 202 return "SHOW_STATE_VISIBLE_FORWARD_NAV"; 203 case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE: 204 return "SHOW_STATE_ALWAYS_VISIBLE"; 205 case SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE: 206 return "SHOW_SETTINGS_ON_CHANGE"; 207 case SoftInputShowHideReason.HIDE_SWITCH_USER: 208 return "HIDE_SWITCH_USER"; 209 case SoftInputShowHideReason.HIDE_INVALID_USER: 210 return "HIDE_INVALID_USER"; 211 case SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW: 212 return "HIDE_UNSPECIFIED_WINDOW"; 213 case SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV: 214 return "HIDE_STATE_HIDDEN_FORWARD_NAV"; 215 case SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE: 216 return "HIDE_ALWAYS_HIDDEN_STATE"; 217 case SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND: 218 return "HIDE_RESET_SHELL_COMMAND"; 219 case SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE: 220 return "HIDE_SETTINGS_ON_CHANGE"; 221 case SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME: 222 return "HIDE_POWER_BUTTON_GO_HOME"; 223 case SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED: 224 return "HIDE_DOCKED_STACK_ATTACHED"; 225 case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: 226 return "HIDE_RECENTS_ANIMATION"; 227 case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR: 228 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; 229 case SoftInputShowHideReason.HIDE_REMOVE_CLIENT: 230 return "HIDE_REMOVE_CLIENT"; 231 case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY: 232 return "SHOW_RESTORE_IME_VISIBILITY"; 233 case SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT: 234 return "SHOW_TOGGLE_SOFT_INPUT"; 235 case SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT: 236 return "HIDE_TOGGLE_SOFT_INPUT"; 237 case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: 238 return "SHOW_SOFT_INPUT_BY_INSETS_API"; 239 default: 240 return "Unknown=" + reason; 241 } 242 } 243 244 /** 245 * Return a fixed size string of the object. 246 * TODO(b/151575861): Take & return with StringBuilder to make more memory efficient. 247 */ 248 @NonNull 249 @AnyThread objToString(Object obj)250 public static String objToString(Object obj) { 251 if (obj == null) { 252 return "null"; 253 } 254 StringBuilder sb = new StringBuilder(64); 255 sb.setLength(0); 256 sb.append(obj.getClass().getName()); 257 sb.append("@"); 258 sb.append(Integer.toHexString(obj.hashCode())); 259 return sb.toString(); 260 } 261 } 262