1 /* 2 * Copyright (C) 2007 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 static java.lang.annotation.RetentionPolicy.SOURCE; 20 21 import android.annotation.IntDef; 22 import android.annotation.Nullable; 23 import android.content.ComponentName; 24 import android.content.Intent; 25 import android.content.ServiceConnection; 26 import android.graphics.Matrix; 27 import android.os.IBinder; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.util.SparseArray; 31 import android.view.InputChannel; 32 33 import com.android.internal.view.IInputMethodSession; 34 35 import java.lang.annotation.Retention; 36 37 /** 38 * Bundle of information returned by input method manager about a successful 39 * binding to an input method. 40 */ 41 public final class InputBindResult implements Parcelable { 42 43 @Retention(SOURCE) 44 @IntDef({ 45 ResultCode.SUCCESS_WITH_IME_SESSION, 46 ResultCode.SUCCESS_WAITING_IME_SESSION, 47 ResultCode.SUCCESS_WAITING_IME_BINDING, 48 ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY, 49 ResultCode.ERROR_NULL, 50 ResultCode.ERROR_NO_IME, 51 ResultCode.ERROR_INVALID_PACKAGE_NAME, 52 ResultCode.ERROR_SYSTEM_NOT_READY, 53 ResultCode.ERROR_IME_NOT_CONNECTED, 54 ResultCode.ERROR_INVALID_USER, 55 ResultCode.ERROR_NULL_EDITOR_INFO, 56 ResultCode.ERROR_NOT_IME_TARGET_WINDOW, 57 ResultCode.ERROR_NO_EDITOR, 58 ResultCode.ERROR_DISPLAY_ID_MISMATCH, 59 ResultCode.ERROR_INVALID_DISPLAY_ID, 60 ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION 61 }) 62 public @interface ResultCode { 63 /** 64 * Indicates that everything in this result object including {@link #method} is valid. 65 */ 66 int SUCCESS_WITH_IME_SESSION = 0; 67 /** 68 * Indicates that this is a temporary binding until the 69 * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session 70 * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS). 71 * 72 * <p>Note that in this state the IMS is already bound to IMMS but the logical session 73 * is not yet established on top of the IPC channel.</p> 74 * 75 * <p>Some of fields such as {@link #channel} is not yet available.</p> 76 * 77 * @see android.inputmethodservice.InputMethodService#onCreateInputMethodSessionInterface() 78 **/ 79 int SUCCESS_WAITING_IME_SESSION = 1; 80 /** 81 * Indicates that this is a temporary binding until the 82 * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session 83 * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS). 84 * 85 * <p>Note that in this state the IMMS has already initiated a connection to the IMS but 86 * the binding process is not completed yet.</p> 87 * 88 * <p>Some of fields such as {@link #channel} is not yet available.</p> 89 * @see android.content.ServiceConnection#onServiceConnected(ComponentName, IBinder) 90 */ 91 int SUCCESS_WAITING_IME_BINDING = 2; 92 /** 93 * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a 94 * pending operation to switch to a different user. 95 * 96 * <p>Note that in this state even what would be the next current IME is not determined.</p> 97 */ 98 int SUCCESS_WAITING_USER_SWITCHING = 3; 99 /** 100 * Indicates that this is not intended for starting input but just for reporting window 101 * focus change from the application process. 102 * 103 * <p>All other fields do not have meaningful value.</p> 104 */ 105 int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4; 106 /** 107 * Indicates somehow 108 * {@link 109 * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus} 110 * is trying to return null {@link InputBindResult}, which must never happen. 111 */ 112 int ERROR_NULL = 5; 113 /** 114 * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} 115 * recognizes no IME. 116 */ 117 int ERROR_NO_IME = 6; 118 /** 119 * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match 120 * the caller UID. 121 * 122 * @see android.view.inputmethod.EditorInfo#packageName 123 */ 124 int ERROR_INVALID_PACKAGE_NAME = 7; 125 /** 126 * Indicates that the system is still in an early stage of the boot process and any 3rd 127 * party application is not allowed to run. 128 * 129 * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START 130 */ 131 int ERROR_SYSTEM_NOT_READY = 8; 132 /** 133 * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to 134 * connect to an {@link android.inputmethodservice.InputMethodService} but failed. 135 * 136 * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, 137 * android.os.UserHandle) 138 */ 139 int ERROR_IME_NOT_CONNECTED = 9; 140 /** 141 * Indicates that the caller is not the foreground user, does not have 142 * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user 143 * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not 144 * running. 145 */ 146 int ERROR_INVALID_USER = 10; 147 /** 148 * Indicates that the caller should have specified non-null 149 * {@link android.view.inputmethod.EditorInfo}. 150 */ 151 int ERROR_NULL_EDITOR_INFO = 11; 152 /** 153 * Indicates that the target window the client specified cannot be the IME target right now. 154 * 155 * <p>Due to the asynchronous nature of Android OS, we cannot completely avoid this error. 156 * The client should try to restart input when its {@link android.view.Window} is focused 157 * again.</p> 158 * 159 * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int) 160 */ 161 int ERROR_NOT_IME_TARGET_WINDOW = 12; 162 /** 163 * Indicates that focused view in the current window is not an editor. 164 */ 165 int ERROR_NO_EDITOR = 13; 166 /** 167 * Indicates that there is a mismatch in display ID between IME client and focused Window. 168 */ 169 int ERROR_DISPLAY_ID_MISMATCH = 14; 170 /** 171 * Indicates that current IME client is no longer allowed to access to the associated 172 * display. 173 */ 174 int ERROR_INVALID_DISPLAY_ID = 15; 175 int SUCCESS_WITH_ACCESSIBILITY_SESSION = 16; 176 } 177 178 @ResultCode 179 public final int result; 180 181 /** 182 * The input method service. 183 */ 184 public final IInputMethodSession method; 185 186 /** 187 * The accessibility services. 188 */ 189 public SparseArray<IAccessibilityInputMethodSession> accessibilitySessions; 190 191 /** 192 * The input channel used to send input events to this IME. 193 */ 194 public final InputChannel channel; 195 196 /** 197 * The ID for this input method, as found in InputMethodInfo; null if 198 * no input method will be bound. 199 */ 200 public final String id; 201 202 /** 203 * Sequence number of this binding. 204 */ 205 public final int sequence; 206 207 @Nullable 208 private final float[] mVirtualDisplayToScreenMatrixValues; 209 210 /** 211 * {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}. 212 */ 213 public final boolean isInputMethodSuppressingSpellChecker; 214 215 /** 216 * @return {@link Matrix} that corresponds to {@link #mVirtualDisplayToScreenMatrixValues}. 217 * {@code null} if {@link #mVirtualDisplayToScreenMatrixValues} is {@code null}. 218 */ 219 @Nullable getVirtualDisplayToScreenMatrix()220 public Matrix getVirtualDisplayToScreenMatrix() { 221 if (mVirtualDisplayToScreenMatrixValues == null) { 222 return null; 223 } 224 final Matrix matrix = new Matrix(); 225 matrix.setValues(mVirtualDisplayToScreenMatrixValues); 226 return matrix; 227 } 228 229 /** 230 * Creates a new instance of {@link InputBindResult}. 231 * 232 * @param result A result code defined in {@link ResultCode}. 233 * @param method {@link IInputMethodSession} to interact with the IME. 234 * @param accessibilitySessions {@link IAccessibilityInputMethodSession} to interact with 235 * accessibility services. 236 * @param channel {@link InputChannel} to forward input events to the IME. 237 * @param id The {@link String} representations of the IME, which is the same as 238 * {@link android.view.inputmethod.InputMethodInfo#getId()} and 239 * {@link android.content.ComponentName#flattenToShortString()}. 240 * @param sequence A sequence number of this binding. 241 * @param isInputMethodSuppressingSpellChecker {@code true} if the IME explicitly specifies 242 * {@code suppressesSpellChecker="true"}. 243 */ InputBindResult(@esultCode int result, IInputMethodSession method, SparseArray<IAccessibilityInputMethodSession> accessibilitySessions, InputChannel channel, String id, int sequence, @Nullable Matrix virtualDisplayToScreenMatrix, boolean isInputMethodSuppressingSpellChecker)244 public InputBindResult(@ResultCode int result, 245 IInputMethodSession method, 246 SparseArray<IAccessibilityInputMethodSession> accessibilitySessions, 247 InputChannel channel, String id, int sequence, 248 @Nullable Matrix virtualDisplayToScreenMatrix, 249 boolean isInputMethodSuppressingSpellChecker) { 250 this.result = result; 251 this.method = method; 252 this.accessibilitySessions = accessibilitySessions; 253 this.channel = channel; 254 this.id = id; 255 this.sequence = sequence; 256 if (virtualDisplayToScreenMatrix == null) { 257 mVirtualDisplayToScreenMatrixValues = null; 258 } else { 259 mVirtualDisplayToScreenMatrixValues = new float[9]; 260 virtualDisplayToScreenMatrix.getValues(mVirtualDisplayToScreenMatrixValues); 261 } 262 this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker; 263 } 264 InputBindResult(Parcel source)265 private InputBindResult(Parcel source) { 266 result = source.readInt(); 267 method = IInputMethodSession.Stub.asInterface(source.readStrongBinder()); 268 int n = source.readInt(); 269 if (n < 0) { 270 accessibilitySessions = null; 271 } else { 272 accessibilitySessions = new SparseArray<>(n); 273 while (n > 0) { 274 int key = source.readInt(); 275 IAccessibilityInputMethodSession value = 276 IAccessibilityInputMethodSession.Stub.asInterface( 277 source.readStrongBinder()); 278 accessibilitySessions.append(key, value); 279 n--; 280 } 281 } 282 if (source.readInt() != 0) { 283 channel = InputChannel.CREATOR.createFromParcel(source); 284 } else { 285 channel = null; 286 } 287 id = source.readString(); 288 sequence = source.readInt(); 289 mVirtualDisplayToScreenMatrixValues = source.createFloatArray(); 290 isInputMethodSuppressingSpellChecker = source.readBoolean(); 291 } 292 293 /** 294 * {@inheritDoc} 295 */ 296 @Override toString()297 public String toString() { 298 return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id 299 + " sequence=" + sequence 300 + " virtualDisplayToScreenMatrix=" + getVirtualDisplayToScreenMatrix() 301 + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker 302 + "}"; 303 } 304 305 /** 306 * {@inheritDoc} 307 */ 308 @Override writeToParcel(Parcel dest, int flags)309 public void writeToParcel(Parcel dest, int flags) { 310 dest.writeInt(result); 311 dest.writeStrongInterface(method); 312 if (accessibilitySessions == null) { 313 dest.writeInt(-1); 314 } else { 315 int n = accessibilitySessions.size(); 316 dest.writeInt(n); 317 int i = 0; 318 while (i < n) { 319 dest.writeInt(accessibilitySessions.keyAt(i)); 320 dest.writeStrongInterface(accessibilitySessions.valueAt(i)); 321 i++; 322 } 323 } 324 if (channel != null) { 325 dest.writeInt(1); 326 channel.writeToParcel(dest, flags); 327 } else { 328 dest.writeInt(0); 329 } 330 dest.writeString(id); 331 dest.writeInt(sequence); 332 dest.writeFloatArray(mVirtualDisplayToScreenMatrixValues); 333 dest.writeBoolean(isInputMethodSuppressingSpellChecker); 334 } 335 336 /** 337 * Used to make this class parcelable. 338 */ 339 public static final Parcelable.Creator<InputBindResult> CREATOR = 340 new Parcelable.Creator<InputBindResult>() { 341 @Override 342 public InputBindResult createFromParcel(Parcel source) { 343 return new InputBindResult(source); 344 } 345 346 @Override 347 public InputBindResult[] newArray(int size) { 348 return new InputBindResult[size]; 349 } 350 }; 351 352 /** 353 * {@inheritDoc} 354 */ 355 @Override describeContents()356 public int describeContents() { 357 return channel != null ? channel.describeContents() : 0; 358 } 359 getResultString()360 private String getResultString() { 361 switch (result) { 362 case ResultCode.SUCCESS_WITH_IME_SESSION: 363 return "SUCCESS_WITH_IME_SESSION"; 364 case ResultCode.SUCCESS_WAITING_IME_SESSION: 365 return "SUCCESS_WAITING_IME_SESSION"; 366 case ResultCode.SUCCESS_WAITING_IME_BINDING: 367 return "SUCCESS_WAITING_IME_BINDING"; 368 case ResultCode.SUCCESS_WAITING_USER_SWITCHING: 369 return "SUCCESS_WAITING_USER_SWITCHING"; 370 case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY: 371 return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY"; 372 case ResultCode.ERROR_NULL: 373 return "ERROR_NULL"; 374 case ResultCode.ERROR_NO_IME: 375 return "ERROR_NO_IME"; 376 case ResultCode.ERROR_NO_EDITOR: 377 return "ERROR_NO_EDITOR"; 378 case ResultCode.ERROR_INVALID_PACKAGE_NAME: 379 return "ERROR_INVALID_PACKAGE_NAME"; 380 case ResultCode.ERROR_SYSTEM_NOT_READY: 381 return "ERROR_SYSTEM_NOT_READY"; 382 case ResultCode.ERROR_IME_NOT_CONNECTED: 383 return "ERROR_IME_NOT_CONNECTED"; 384 case ResultCode.ERROR_INVALID_USER: 385 return "ERROR_INVALID_USER"; 386 case ResultCode.ERROR_NULL_EDITOR_INFO: 387 return "ERROR_NULL_EDITOR_INFO"; 388 case ResultCode.ERROR_NOT_IME_TARGET_WINDOW: 389 return "ERROR_NOT_IME_TARGET_WINDOW"; 390 case ResultCode.ERROR_DISPLAY_ID_MISMATCH: 391 return "ERROR_DISPLAY_ID_MISMATCH"; 392 case ResultCode.ERROR_INVALID_DISPLAY_ID: 393 return "ERROR_INVALID_DISPLAY_ID"; 394 default: 395 return "Unknown(" + result + ")"; 396 } 397 } 398 error(@esultCode int result)399 private static InputBindResult error(@ResultCode int result) { 400 return new InputBindResult(result, null, null, null, null, -1, null, false); 401 } 402 403 /** 404 * Predefined error object for {@link ResultCode#ERROR_NULL}. 405 */ 406 public static final InputBindResult NULL = error(ResultCode.ERROR_NULL); 407 /** 408 * Predefined error object for {@link ResultCode#NO_IME}. 409 */ 410 public static final InputBindResult NO_IME = error(ResultCode.ERROR_NO_IME); 411 /** 412 * Predefined error object for {@link ResultCode#NO_EDITOR}. 413 */ 414 public static final InputBindResult NO_EDITOR = error(ResultCode.ERROR_NO_EDITOR); 415 /** 416 * Predefined error object for {@link ResultCode#ERROR_INVALID_PACKAGE_NAME}. 417 */ 418 public static final InputBindResult INVALID_PACKAGE_NAME = 419 error(ResultCode.ERROR_INVALID_PACKAGE_NAME); 420 /** 421 * Predefined error object for {@link ResultCode#ERROR_NULL_EDITOR_INFO}. 422 */ 423 public static final InputBindResult NULL_EDITOR_INFO = error(ResultCode.ERROR_NULL_EDITOR_INFO); 424 /** 425 * Predefined error object for {@link ResultCode#ERROR_NOT_IME_TARGET_WINDOW}. 426 */ 427 public static final InputBindResult NOT_IME_TARGET_WINDOW = 428 error(ResultCode.ERROR_NOT_IME_TARGET_WINDOW); 429 /** 430 * Predefined error object for {@link ResultCode#ERROR_IME_NOT_CONNECTED}. 431 */ 432 public static final InputBindResult IME_NOT_CONNECTED = 433 error(ResultCode.ERROR_IME_NOT_CONNECTED); 434 /** 435 * Predefined error object for {@link ResultCode#ERROR_INVALID_USER}. 436 */ 437 public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER); 438 439 /** 440 * Predefined error object for {@link ResultCode#ERROR_DISPLAY_ID_MISMATCH}. 441 */ 442 public static final InputBindResult DISPLAY_ID_MISMATCH = 443 error(ResultCode.ERROR_DISPLAY_ID_MISMATCH); 444 445 /** 446 * Predefined error object for {@link ResultCode#ERROR_INVALID_DISPLAY_ID}. 447 */ 448 public static final InputBindResult INVALID_DISPLAY_ID = 449 error(ResultCode.ERROR_INVALID_DISPLAY_ID); 450 451 /** 452 * Predefined <strong>success</strong> object for 453 * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}. 454 */ 455 public static final InputBindResult USER_SWITCHING = 456 error(ResultCode.SUCCESS_WAITING_USER_SWITCHING); 457 } 458