diff options
| author | Nikita Dubrovsky <dubrovsky@google.com> | 2020-09-29 14:01:07 -0700 |
|---|---|---|
| committer | Nikita Dubrovsky <dubrovsky@google.com> | 2020-10-12 11:03:31 -0700 |
| commit | 92422b34a2935210865098a7aca971654cb2dc2a (patch) | |
| tree | cafed0e745de753042e4633080f9efe4c6f8933d /core/java | |
| parent | 94ddd9d4cb1621f27347ca4ba892a77b89553440 (diff) | |
Add callbacks to notify View when an InputConnection is opened/closed
Added hidden callback methods on View to notify editors when the
system has initialized an InputConnection successfully and when
the InputConnection is closed.
This allows editable views (e.g. EditText) to have access to the
final EditorInfo and InputConnection that were created via
onCreateInputConnection(). This enables the editor platform code
to do things such as
* know what type of content can be inserted into the view (ie, the
MIME types in EditorInfo.contentMimeTypes)
* call APIs on InputConnection, e.g. commitContent() to pass
non-text content to the application
Bug: 163400105
Test: Manual and unit test
atest FrameworksCoreTests:ViewInputConnectionTest
Change-Id: Iaafb0a03126c9292c24415f866dbdd72cadfa239
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/view/View.java | 36 | ||||
| -rw-r--r-- | core/java/android/view/inputmethod/InputMethodManager.java | 33 |
2 files changed, 67 insertions, 2 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c430a4d57338..4f05a599c171 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -15165,6 +15165,42 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application + * that the system has successfully initialized an {@link InputConnection} and it is ready for + * use. + * + * <p>The default implementation does nothing, since a view doesn't support input methods by + * default (see {@link #onCreateInputConnection}). + * + * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, + * after it's been fully initialized by the system. + * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. + * @param handler The dedicated {@link Handler} on which IPC method calls from input methods + * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If + * that method returns null, this parameter will be null also. + * + * @hide + */ + public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, + @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} + + /** + * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application + * that the {@link InputConnection} has been closed. + * + * <p>The default implementation does nothing, since a view doesn't support input methods by + * default (see {@link #onCreateInputConnection}). + * + * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when + * the {@link InputConnection} is closed or the connection is not valid and managed by + * {@link com.android.server.inputmethod.InputMethodManagerService}. + * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. + * + * @hide + */ + public void onInputConnectionClosedInternal() {} + + /** * Called by the {@link android.view.inputmethod.InputMethodManager} * when a view who is not the current * input connection target is trying to make a call on the manager. The diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b8f04159faa9..5785999e2672 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1006,6 +1006,24 @@ public final class InputMethodManager { return; } closeConnection(); + + // Notify the app that the InputConnection was closed. + final View servedView = mServedView.get(); + if (servedView != null) { + final Handler handler = servedView.getHandler(); + // The handler is null if the view is already detached. When that's the case, for + // now, we simply don't dispatch this callback. + if (handler != null) { + if (DEBUG) { + Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView); + } + if (handler.getLooper().isCurrentThread()) { + servedView.onInputConnectionClosedInternal(); + } else { + handler.post(servedView::onInputConnectionClosedInternal); + } + } + } } @Override @@ -1940,6 +1958,8 @@ public final class InputMethodManager { InputConnection ic = view.onCreateInputConnection(tba); if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); + final Handler icHandler; + InputBindResult res = null; synchronized (mH) { // Now that we are locked again, validate that our state hasn't // changed. @@ -1976,7 +1996,6 @@ public final class InputMethodManager { mCursorCandEnd = -1; mCursorRect.setEmpty(); mCursorAnchorInfo = null; - final Handler icHandler; missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic); if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER) != 0) { @@ -1990,6 +2009,7 @@ public final class InputMethodManager { } else { servedContext = null; missingMethodFlags = 0; + icHandler = null; } mServedInputConnectionWrapper = servedContext; @@ -1997,7 +2017,7 @@ public final class InputMethodManager { if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic=" + ic + " tba=" + tba + " startInputFlags=" + InputMethodDebug.startInputFlagsToString(startInputFlags)); - final InputBindResult res = mService.startInputOrWindowGainedFocus( + res = mService.startInputOrWindowGainedFocus( startInputReason, mClient, windowGainingFocus, startInputFlags, softInputMode, windowFlags, tba, servedContext, missingMethodFlags, view.getContext().getApplicationInfo().targetSdkVersion); @@ -2036,6 +2056,15 @@ public final class InputMethodManager { } } + // Notify the app that the InputConnection is initialized and ready for use. + if (ic != null && res != null && res.method != null) { + if (DEBUG) { + Log.v(TAG, "Calling View.onInputConnectionOpened: view= " + view + + ", ic=" + ic + ", tba=" + tba + ", handler=" + icHandler); + } + view.onInputConnectionOpenedInternal(ic, tba, icHandler); + } + return true; } |
