From 92d2dd36cdd44ddeb5db85a5c3aee6f2fd3000c0 Mon Sep 17 00:00:00 2001 From: Tarandeep Singh Date: Wed, 7 Aug 2019 14:45:01 -0700 Subject: IME transitions without pre-rendering. Support new IME inset api transitions without using pre-rendering. This would be the default behavior when ViewRootImpl#sNewInsetsMode > 0 and pre-rendering is not enabled. Bug: 111084606 Bug: 118599175 Test: Manually verify by just enabling Insets API and keeping pre-rendering off. 1. Build and flash 2. adb shell setprop persist.wm.new_insets 1 3. adb reboot 4. Make sure tapping on edit text brings keyboard up with new transition and back closes IME with various apps. 5. Make sure IME behavior is unchanged for apps with ADJUST_RESIZE like whatsapp. Test: atest CtsInputMethodTestCases CtsInputMethodServiceHostTestCases Change-Id: If33e9dd45e549e49757237fa66051351b858875d --- .../inputmethodservice/InputMethodService.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 82d4d1d10d7e..83391f368ac1 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -19,6 +19,7 @@ package android.inputmethodservice; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -62,6 +63,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; @@ -595,12 +597,12 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "hideSoftInput()"); final boolean wasVisible = mIsPreRendered ? mDecorViewVisible && mWindowVisible : isInputViewShown(); + applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */); if (mIsPreRendered) { if (DEBUG) { Log.v(TAG, "Making IME window invisible"); } setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition); - applyVisibilityInInsetsConsumer(false /* setVisible */); onPreRenderedWindowVisibilityChanged(false /* setVisible */); } else { mShowInputFlags = 0; @@ -632,11 +634,11 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.v(TAG, "Making IME window visible"); } - applyVisibilityInInsetsConsumer(true /* setVisible */); onPreRenderedWindowVisibilityChanged(true /* setVisible */); } else { showWindow(true); } + applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */); } // If user uses hard keyboard, IME button should always be shown. setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); @@ -1974,16 +1976,20 @@ public class InputMethodService extends AbstractInputMethodService { /** * Apply the IME visibility in {@link android.view.ImeInsetsSourceConsumer} when - * pre-rendering is enabled. + * {@link ViewRootImpl.sNewInsetsMode} is enabled. * @param setVisible {@code true} to make it visible, false to hide it. */ - private void applyVisibilityInInsetsConsumer(boolean setVisible) { - if (!mIsPreRendered) { + private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) { + if (!isVisibilityAppliedUsingInsetsConsumer()) { return; } mPrivOps.applyImeVisibility(setVisible); } + private boolean isVisibilityAppliedUsingInsetsConsumer() { + return ViewRootImpl.sNewInsetsMode > NEW_INSETS_MODE_NONE; + } + private void finishViews(boolean finishingInput) { if (mInputViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onFinishInputView"); @@ -2007,7 +2013,11 @@ public class InputMethodService extends AbstractInputMethodService { mWindowVisible = false; finishViews(false /* finishingInput */); if (mDecorViewVisible) { - mWindow.hide(); + // When insets API is enabled, it is responsible for client and server side + // visibility of IME window. + if (!isVisibilityAppliedUsingInsetsConsumer()) { + mWindow.hide(); + } mDecorViewVisible = false; onWindowHidden(); mDecorViewWasVisible = false; -- cgit v1.2.3 From 31595bc94e3fe1db377e19d8f33613c34262c97c Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 30 Sep 2019 15:04:19 -0700 Subject: Set gesture exclusion rect for IMEs Use visible inset values provided by IMEs to set gesture exclusion rects for the EdgeBackGestureHandler to ignore regions where the keyboard is. If the IME has not overridden onComputeInsets(), InputMethodService uses the location of R.id.inputArea to approximate the location of where the IME region starts. Fixes: 141215181 Test: Tested full screen landscape keyboards (Messenger, Hangouts), non full screen landscape keyboards (SMS Messages), searching from the top of the screen in the Toolbar (Google Play Store) Change-Id: I359d719493fb92d49cd309c2d00371134cd758fe --- .../android/inputmethodservice/InputMethodService.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 83391f368ac1..43842c5c3403 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -94,6 +94,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Collections; /** * InputMethodService provides a standard implementation of an InputMethod, @@ -434,6 +435,7 @@ public class InputMethodService extends AbstractInputMethodService { final int[] mTmpLocation = new int[2]; final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { + onComputeInsets(mTmpInsets); if (isExtractViewShown()) { // In true fullscreen mode, we just say the window isn't covering // any content so we don't impact whatever is behind. @@ -442,12 +444,15 @@ public class InputMethodService extends AbstractInputMethodService { info.touchableRegion.setEmpty(); info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); } else { - onComputeInsets(mTmpInsets); info.contentInsets.top = mTmpInsets.contentTopInsets; info.visibleInsets.top = mTmpInsets.visibleTopInsets; info.touchableRegion.set(mTmpInsets.touchableRegion); info.setTouchableInsets(mTmpInsets.touchableInsets); } + + if (mInputFrame != null) { + setImeExclusionRect(mTmpInsets.visibleTopInsets); + } }; final View.OnClickListener mActionClickListener = v -> { @@ -672,6 +677,14 @@ public class InputMethodService extends AbstractInputMethodService { mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition); } + /** Set region of the keyboard to be avoided from back gesture */ + private void setImeExclusionRect(int visibleTopInsets) { + View inputFrameRootView = mInputFrame.getRootView(); + Rect r = new Rect(0, visibleTopInsets, inputFrameRootView.getWidth(), + inputFrameRootView.getHeight()); + inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r)); + } + /** * Concrete implementation of * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides -- cgit v1.2.3 From 4a7835ffb6811e0e38e2b16672a282106d43e1d2 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Wed, 6 Nov 2019 00:07:56 +0800 Subject: Window Manager Flag Migration (7/n) Introduce new APIs in Window/WindowManager.LayoutParams for developers to decide which types of insets at which side a window should avoid: setFitWindowInsetsTypes(@InsetsType int types) setFitWindowInsetsSides(@InsetsSide int sides) setFitIgnoreVisibility(boolean ignore) The existing logic in DisplayPolicy.layoutWindowLw uses combinations of window types, window flags, and system UI flags to decide what frames a window should have, which is very complex, difficult to maintain, and should be replaced with the new APIs. Bug: 118118435 Test: atest InsetsSourceProviderTest InsetsStateControllerTest InsetsPolicyTest WindowStateTests CommandQueueTest RegisterStatusBarResultTest InsetsFlagsTest LightBarControllerTest RegisterStatusBarResultTest ViewRootImplTest DisplayPolicyLayoutTests DisplayPolicyInsetsTests DisplayPolicyTests TaskSnapshotSurfaceTest Change-Id: I06ddc9d0d2887ba4ded7bb8adbf9c9c0da4bf7b4 --- core/java/android/inputmethodservice/InputMethodService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 43842c5c3403..156bcfe147f7 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -21,6 +21,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -66,6 +67,7 @@ import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; @@ -1019,6 +1021,16 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); + mWindow.getWindow().setFitWindowInsetsTypes(WindowInsets.Type.systemBars()); + mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND); + mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( + (v, insets) -> v.onApplyWindowInsets( + new WindowInsets.Builder(insets).setSystemWindowInsets( + android.graphics.Insets.of( + insets.getSystemWindowInsetLeft(), + insets.getSystemWindowInsetTop(), + insets.getSystemWindowInsetRight(), + insets.getStableInsetBottom())).build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set // by default (but IME developers can opt this out later if they want a new behavior). mWindow.getWindow().setFlags( -- cgit v1.2.3 From bc67f2e15813ec05c07f18ef961e7303fd344ff1 Mon Sep 17 00:00:00 2001 From: Adam He Date: Wed, 13 Nov 2019 14:34:56 -0800 Subject: API for autofill integration with keyboard. Bug: 137800469 Test: manual verification Change-Id: Id222500c373898d576661cacb7a1cb51061041d4 --- .../inputmethodservice/InputMethodService.java | 185 +++++++++++++++++++++ 1 file changed, 185 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 43842c5c3403..da70359332a1 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -22,6 +22,8 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.AnyThread; @@ -34,6 +36,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Dialog; +import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -46,6 +49,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; import android.provider.Settings; @@ -68,11 +73,14 @@ import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.view.animation.AnimationUtils; +import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; @@ -89,11 +97,14 @@ import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; +import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.IInlineSuggestionsResponseCallback; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.Collections; /** @@ -434,6 +445,14 @@ public class InputMethodService extends AbstractInputMethodService { final Insets mTmpInsets = new Insets(); final int[] mTmpLocation = new int[2]; + @Nullable + private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; + + @Nullable + private InlineSuggestionsResponseCallbackImpl mInlineSuggestionsResponseCallback = null; + + private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); + final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { onComputeInsets(mTmpInsets); if (isExtractViewShown()) { @@ -491,6 +510,18 @@ public class InputMethodService extends AbstractInputMethodService { attachToken(token); } + /** + * {@inheritDoc} + * @hide + */ + @MainThread + @Override + public void onCreateInlineSuggestionsRequest(ComponentName componentName, + AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); + handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb); + } + /** * {@inheritDoc} */ @@ -668,6 +699,103 @@ public class InputMethodService extends AbstractInputMethodService { } } + // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. + /** + * Returns an {@link InlineSuggestionsRequest} to be sent to Autofill. + * + *

Should be implemented by subclasses.

+ */ + public @Nullable InlineSuggestionsRequest onCreateInlineSuggestionsRequest() { + return null; + } + + /** + * Called when Autofill responds back with {@link InlineSuggestionsResponse} containing + * inline suggestions. + * + *

Should be implemented by subclasses.

+ * + * @param response {@link InlineSuggestionsResponse} passed back by Autofill. + * @return Whether the IME will use and render the inline suggestions. + */ + public boolean onInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) { + return false; + } + + /** + * Returns whether inline suggestions are enabled on this service. + * + * TODO(b/137800469): check XML for value. + */ + private boolean isInlineSuggestionsEnabled() { + return true; + } + + /** + * Sends an {@link InlineSuggestionsRequest} obtained from + * {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through + * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}. + */ + private void makeInlineSuggestionsRequest() { + if (mInlineSuggestionsRequestInfo == null) { + Log.w(TAG, "makeInlineSuggestionsRequest() called with null requestInfo cache"); + return; + } + + final IInlineSuggestionsRequestCallback requestCallback = + mInlineSuggestionsRequestInfo.mCallback; + try { + final InlineSuggestionsRequest request = onCreateInlineSuggestionsRequest(); + if (request == null) { + Log.w(TAG, "onCreateInlineSuggestionsRequest() returned null request"); + requestCallback.onInlineSuggestionsUnsupported(); + } else { + if (mInlineSuggestionsResponseCallback == null) { + mInlineSuggestionsResponseCallback = + new InlineSuggestionsResponseCallbackImpl(this, + mInlineSuggestionsRequestInfo.mComponentName, + mInlineSuggestionsRequestInfo.mFocusedId); + } + requestCallback.onInlineSuggestionsRequest(request, + mInlineSuggestionsResponseCallback); + } + } catch (RemoteException e) { + Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e); + } + } + + private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, + @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) { + mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, + callback); + + if (!isInlineSuggestionsEnabled()) { + try { + callback.onInlineSuggestionsUnsupported(); + } catch (RemoteException e) { + Log.w(TAG, "handleMakeInlineSuggestionsRequest() RemoteException:" + e); + } + return; + } + + if (!mInputStarted) { + Log.w(TAG, "onStartInput() not called yet"); + return; + } + + makeInlineSuggestionsRequest(); + } + + private void handleOnInlineSuggestionsResponse(@NonNull ComponentName componentName, + @NonNull AutofillId autofillId, @NonNull InlineSuggestionsResponse response) { + if (!mInlineSuggestionsRequestInfo.validate(componentName)) { + Log.d(TAG, "Response component=" + componentName + " differs from request component=" + + mInlineSuggestionsRequestInfo.mComponentName + ", ignoring response"); + return; + } + onInlineSuggestionsResponse(response); + } + private void notifyImeHidden() { setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition); onPreRenderedWindowVisibilityChanged(false /* setVisible */); @@ -685,6 +813,63 @@ public class InputMethodService extends AbstractInputMethodService { inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r)); } + /** + * Internal implementation of {@link IInlineSuggestionsResponseCallback}. + */ + private static final class InlineSuggestionsResponseCallbackImpl + extends IInlineSuggestionsResponseCallback.Stub { + private final WeakReference mInputMethodService; + + private final ComponentName mRequestComponentName; + private final AutofillId mRequestAutofillId; + + private InlineSuggestionsResponseCallbackImpl(InputMethodService inputMethodService, + ComponentName componentName, AutofillId autofillId) { + mInputMethodService = new WeakReference<>(inputMethodService); + mRequestComponentName = componentName; + mRequestAutofillId = autofillId; + } + + @Override + public void onInlineSuggestionsResponse(InlineSuggestionsResponse response) + throws RemoteException { + final InputMethodService service = mInputMethodService.get(); + if (service != null) { + service.mHandler.sendMessage(obtainMessage( + InputMethodService::handleOnInlineSuggestionsResponse, service, + mRequestComponentName, mRequestAutofillId, response)); + } + } + } + + /** + * Information about incoming requests from Autofill Frameworks for inline suggestions. + */ + private static final class InlineSuggestionsRequestInfo { + final ComponentName mComponentName; + final AutofillId mFocusedId; + final IInlineSuggestionsRequestCallback mCallback; + + InlineSuggestionsRequestInfo(ComponentName componentName, AutofillId focusedId, + IInlineSuggestionsRequestCallback callback) { + this.mComponentName = componentName; + this.mFocusedId = focusedId; + this.mCallback = callback; + } + + /** + * Returns whether the cached {@link ComponentName} matches the passed in activity. + */ + public boolean validate(ComponentName componentName) { + final boolean result = componentName.equals(mComponentName); + if (!result) { + Log.d(TAG, "Cached request info ComponentName=" + mComponentName + + " differs from received ComponentName=" + componentName); + } + return result; + } + } + /** * Concrete implementation of * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides -- cgit v1.2.3 From ec3f84a899015c3a83d6431b116f8a1cb7569099 Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Mon, 23 Dec 2019 12:46:58 -0800 Subject: Make InputMethodService to never reuse the inline suggestion response callback. Test: manual Bug: 146903532 Change-Id: I7bc007fb3009897cba57e63edbc67cef541f0e05 --- .../android/inputmethodservice/InputMethodService.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7da7dc120dcb..a45f70316953 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -450,9 +450,6 @@ public class InputMethodService extends AbstractInputMethodService { @Nullable private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; - @Nullable - private InlineSuggestionsResponseCallbackImpl mInlineSuggestionsResponseCallback = null; - private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { @@ -752,14 +749,12 @@ public class InputMethodService extends AbstractInputMethodService { Log.w(TAG, "onCreateInlineSuggestionsRequest() returned null request"); requestCallback.onInlineSuggestionsUnsupported(); } else { - if (mInlineSuggestionsResponseCallback == null) { - mInlineSuggestionsResponseCallback = - new InlineSuggestionsResponseCallbackImpl(this, - mInlineSuggestionsRequestInfo.mComponentName, - mInlineSuggestionsRequestInfo.mFocusedId); - } + final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = + new InlineSuggestionsResponseCallbackImpl(this, + mInlineSuggestionsRequestInfo.mComponentName, + mInlineSuggestionsRequestInfo.mFocusedId); requestCallback.onInlineSuggestionsRequest(request, - mInlineSuggestionsResponseCallback); + inlineSuggestionsResponseCallback); } } catch (RemoteException e) { Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e); -- cgit v1.2.3 From 7bc8f60377e6fef99f9fdb2ac5cd70716abe9526 Mon Sep 17 00:00:00 2001 From: Adam He Date: Thu, 12 Dec 2019 17:00:34 -0800 Subject: Added attributes for IME and AutofillService to indicate they support inline suggestions. Fixes: 146452946 Test: atest FrameworksCoreTests:android.view.inputmethod.InputMethodInfoTest Change-Id: I709b16d3f12c693bc670600bdcb9125630eb9b8e --- .../inputmethodservice/InputMethodService.java | 24 +++------------------- 1 file changed, 3 insertions(+), 21 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index a45f70316953..fe4f860484cf 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -721,15 +721,6 @@ public class InputMethodService extends AbstractInputMethodService { return false; } - /** - * Returns whether inline suggestions are enabled on this service. - * - * TODO(b/137800469): check XML for value. - */ - private boolean isInlineSuggestionsEnabled() { - return true; - } - /** * Sends an {@link InlineSuggestionsRequest} obtained from * {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through @@ -763,23 +754,14 @@ public class InputMethodService extends AbstractInputMethodService { private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) { - mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, - callback); - - if (!isInlineSuggestionsEnabled()) { - try { - callback.onInlineSuggestionsUnsupported(); - } catch (RemoteException e) { - Log.w(TAG, "handleMakeInlineSuggestionsRequest() RemoteException:" + e); - } - return; - } - if (!mInputStarted) { Log.w(TAG, "onStartInput() not called yet"); return; } + mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, + callback); + makeInlineSuggestionsRequest(); } -- cgit v1.2.3 From d9a916fe4da8d91f7a1e0d36fb1bde7d333e76b9 Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Thu, 2 Jan 2020 19:03:16 +0800 Subject: Finish autofill integration with keyboard cleanup tasks 1. Only print log when debug is on. 2. Callback be notified when input does not start. 3. Avoid using hard code tag in Log class. 4. onCreateInlineSuggestionsRequest() do nothing in NOP. 5. Add missing javadoc. Bug: 146525448 Test: manual verification Change-Id: I41e1de92ffcdb8020aef99acbfec274e0294bad3 --- .../inputmethodservice/InputMethodService.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index fe4f860484cf..ffb97c09a905 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -517,7 +517,9 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void onCreateInlineSuggestionsRequest(ComponentName componentName, AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { - Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); + if (DEBUG) { + Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); + } handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb); } @@ -755,7 +757,12 @@ public class InputMethodService extends AbstractInputMethodService { private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) { if (!mInputStarted) { - Log.w(TAG, "onStartInput() not called yet"); + try { + Log.w(TAG, "onStartInput() not called yet"); + callback.onInlineSuggestionsUnsupported(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call onInlineSuggestionsUnsupported.", e); + } return; } @@ -768,8 +775,12 @@ public class InputMethodService extends AbstractInputMethodService { private void handleOnInlineSuggestionsResponse(@NonNull ComponentName componentName, @NonNull AutofillId autofillId, @NonNull InlineSuggestionsResponse response) { if (!mInlineSuggestionsRequestInfo.validate(componentName)) { - Log.d(TAG, "Response component=" + componentName + " differs from request component=" - + mInlineSuggestionsRequestInfo.mComponentName + ", ignoring response"); + if (DEBUG) { + Log.d(TAG, + "Response component=" + componentName + " differs from request component=" + + mInlineSuggestionsRequestInfo.mComponentName + + ", ignoring response"); + } return; } onInlineSuggestionsResponse(response); @@ -841,7 +852,7 @@ public class InputMethodService extends AbstractInputMethodService { */ public boolean validate(ComponentName componentName) { final boolean result = componentName.equals(mComponentName); - if (!result) { + if (DEBUG && !result) { Log.d(TAG, "Cached request info ComponentName=" + mComponentName + " differs from received ComponentName=" + componentName); } -- cgit v1.2.3 From 269580069b3033c8d80d21e807cdf8ac4156ce75 Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:52 +0000 Subject: Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I0c336de56bc4a041dc97ff9b7927f62f0b44b457 --- core/java/android/inputmethodservice/InputMethodService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index ffb97c09a905..8e52ee944c1c 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -34,9 +34,9 @@ import android.annotation.IntDef; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; -- cgit v1.2.3 From bb0e2f753b4b6e37ab0411499c25661abfbf6553 Mon Sep 17 00:00:00 2001 From: Tarandeep Singh Date: Wed, 15 Jan 2020 13:58:29 -0800 Subject: Pipe windowToken of window requesting IME It takes time from when IME is requested to the time when IME is ready to be shown. When its ready to be shown, we need to make sure that window that requested IME is still the IME target in DisplayContent. The only realistic way of knowing originating window is passing windowToken from IMM API. Bug: 111084606 Test: CtsInputMethodTestCases Change-Id: Ia49e23dd077d264a58d28a7b8acffde54b7db187 --- .../inputmethodservice/InputMethodService.java | 48 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 8e52ee944c1c..81a0d629380a 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -46,11 +46,13 @@ import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.Region; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; @@ -450,6 +452,16 @@ public class InputMethodService extends AbstractInputMethodService { @Nullable private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; + /** + * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} + * The original app window token is passed from client app window. + * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique dummy + * token to identify this window. + * This dummy token is only valid for a single call to {@link InputMethodImpl#showSoftInput}, + * after which it is set null until next call. + */ + private IBinder mCurShowInputToken; + private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { @@ -491,6 +503,9 @@ public class InputMethodService extends AbstractInputMethodService { * all of the standard behavior for an input method. */ public class InputMethodImpl extends AbstractInputMethodImpl { + + private boolean mSystemCallingShowSoftInput; + /** * {@inheritDoc} * @hide @@ -657,6 +672,21 @@ public class InputMethodService extends AbstractInputMethodService { } } + /** + * {@inheritDoc} + * @hide + */ + @MainThread + @Override + public void showSoftInputWithToken(int flags, ResultReceiver resultReceiver, + IBinder showInputToken) { + mSystemCallingShowSoftInput = true; + mCurShowInputToken = showInputToken; + showSoftInput(flags, resultReceiver); + mCurShowInputToken = null; + mSystemCallingShowSoftInput = false; + } + /** * {@inheritDoc} */ @@ -664,6 +694,13 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void showSoftInput(int flags, ResultReceiver resultReceiver) { if (DEBUG) Log.v(TAG, "showSoftInput()"); + // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods. + if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R + && !mSystemCallingShowSoftInput) { + Log.e(TAG," IME shouldn't call showSoftInput on itself." + + " Use requestShowSelf(int) itself"); + return; + } final boolean wasVisible = mIsPreRendered ? mDecorViewVisible && mWindowVisible : isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { @@ -698,6 +735,15 @@ public class InputMethodService extends AbstractInputMethodService { public void changeInputMethodSubtype(InputMethodSubtype subtype) { dispatchOnCurrentInputMethodSubtypeChanged(subtype); } + + /** + * {@inheritDoc} + * @hide + */ + @Override + public void setCurrentShowInputToken(IBinder showInputToken) { + mCurShowInputToken = showInputToken; + } } // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. @@ -2181,7 +2227,7 @@ public class InputMethodService extends AbstractInputMethodService { if (!isVisibilityAppliedUsingInsetsConsumer()) { return; } - mPrivOps.applyImeVisibility(setVisible); + mPrivOps.applyImeVisibility(mCurShowInputToken, setVisible); } private boolean isVisibilityAppliedUsingInsetsConsumer() { -- cgit v1.2.3 From 7fb715c4254a8544fec3072d8220d76a5821b189 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Thu, 9 Jan 2020 23:45:41 +0100 Subject: Introduce Window.setContentOnApplyWindowInsetsListener When root-level content containers fit insets, they used to just apply and consume the entire system insets. However, with the new Inset APIs, and with deprecating ADJUST_RESIZE IME flag, we want to give apps an easy way to customize this behavior. For that, we introduce Window.setOnContentApplyWindowInsetsListener that returns what kind of margins/padding should be applied and what should be dispatched to the content views. This is essentially a replacement for SYSTEM_UI_FLAG_LAYOUT_* as well as SOFT_INPUT_ADJUST_RESIZE: It allows apps to choose which insets should be handled on the window level vs view level. For that, we mark the window decor views as FRAMEWORK_OPTIONAL_FIT_SYSTEM_WINDOWS, in order to distinguish the case when support library calls makeOptionalFitSystemWindows(). This is because of two reasons: - We don't want the listener to be invoked twice. - We can not do the compat ping-pong between onApplyWindowInsets and fitSystemWindows. This is because during the ping-pong, the result of the OnContentApplyWindowInsetsListener would be lost. However, we still need to do the compat ping-pong for ActionBarOverlayLayout in the support library (until that gets migrated to use onApplyWindowInsets), so we have this separate dispatching path that only gets used for framework optional fitting views. Test: WindowTest Bug: 118118435 Change-Id: I4b514addd9e094163062d651972f85615b4a35db --- core/java/android/inputmethodservice/InputMethodService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 8e52ee944c1c..86ff0f4e0dfc 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1194,7 +1194,7 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().setFitWindowInsetsTypes(WindowInsets.Type.systemBars()); + mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(WindowInsets.Type.systemBars()); mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND); mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( -- cgit v1.2.3 From 0da8fd165fed21f26b2b10ddcf4bd1a89d9981c3 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 10 Jan 2020 01:23:21 +0100 Subject: Force non-floating main app windows to not fit anything Since we have a better approach of fitting content instead of setting them on the layout params (Window.setContentOnApplyWindowInsetsListener), we can now simplify forcing of filling the screen: Instead of clearing the fit types when the private flag is set, we unset the types and straight out reject any params when the client would like to fit. Test: DisplayPolicyTests Bug: 118118435 Change-Id: I845e6b1c81e29ab66a770891d03c62a32418e8cc --- .../android/inputmethodservice/InputMethodService.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 86ff0f4e0dfc..82b21f9b266e 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -20,8 +20,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; +import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -1194,16 +1194,15 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(WindowInsets.Type.systemBars()); - mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND); + mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(WindowInsets.Type.statusBars()); + + // IME layout should always be inset by navigation bar, no matter it's current visibility. mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( - new WindowInsets.Builder(insets).setSystemWindowInsets( - android.graphics.Insets.of( - insets.getSystemWindowInsetLeft(), - insets.getSystemWindowInsetTop(), - insets.getSystemWindowInsetRight(), - insets.getStableInsetBottom())).build())); + new WindowInsets.Builder(insets).setInsets( + navigationBars(), insets.getMaxInsets(navigationBars())) + .build())); + // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set // by default (but IME developers can opt this out later if they want a new behavior). mWindow.getWindow().setFlags( -- cgit v1.2.3 From 527244459c6d776e51407eb99c74d2643b289615 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Mon, 20 Jan 2020 21:38:42 +0800 Subject: Window Manager Flag Migration (12/n) - Unhide new APIs - MaxInsets -> InsetsIgnoringVisibility - Deprecate SystemUI flags - Deprecate some other stuff Bug: 118118435 Test: Build, CTS coming soon Change-Id: I0a0cbdb48258b3779d536668b59e8c88f3c96d18 Exempt-From-Owner-Approval: Trivial rename --- core/java/android/inputmethodservice/InputMethodService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c5f0aab3daa9..92047dcad09e 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1240,13 +1240,14 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(WindowInsets.Type.statusBars()); + mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars()); // IME layout should always be inset by navigation bar, no matter it's current visibility. mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( new WindowInsets.Builder(insets).setInsets( - navigationBars(), insets.getMaxInsets(navigationBars())) + navigationBars(), + insets.getInsetsIgnoringVisibility(navigationBars())) .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set -- cgit v1.2.3 From 7eec316f54e22237f92a2808a3a2f9356229335d Mon Sep 17 00:00:00 2001 From: JianYang Liu Date: Thu, 23 Jan 2020 17:09:26 -0800 Subject: Updated InputMethodService to not inset by navigation bar if requested by automotive. Bug: 147155538 Test: Manual Change-Id: I4faf82bdd7536bd2d049ded04034a9635d8ca0d3 --- .../inputmethodservice/InputMethodService.java | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 92047dcad09e..cc6a0de64cb3 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -39,6 +39,7 @@ import android.app.Dialog; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; @@ -52,7 +53,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; -import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; @@ -452,6 +452,9 @@ public class InputMethodService extends AbstractInputMethodService { @Nullable private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; + private boolean mAutomotiveHideNavBarForKeyboard; + private boolean mIsAutomotive; + /** * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} * The original app window token is passed from client app window. @@ -1233,6 +1236,11 @@ public class InputMethodService extends AbstractInputMethodService { super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mSettingsObserver = SettingsObserver.createAndRegister(this); + + mIsAutomotive = isAutomotive(); + mAutomotiveHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + // TODO(b/111364446) Need to address context lifecycle issue if need to re-create // for update resources & configuration correctly when show soft input // in non-default display. @@ -1242,12 +1250,16 @@ public class InputMethodService extends AbstractInputMethodService { WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars()); - // IME layout should always be inset by navigation bar, no matter it's current visibility. + // IME layout should always be inset by navigation bar, no matter its current visibility, + // unless automotive requests it, since automotive may hide the navigation bar. mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( new WindowInsets.Builder(insets).setInsets( navigationBars(), - insets.getInsetsIgnoringVisibility(navigationBars())) + mIsAutomotive && mAutomotiveHideNavBarForKeyboard + ? android.graphics.Insets.NONE + : insets.getInsetsIgnoringVisibility(navigationBars()) + ) .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set @@ -3286,6 +3298,11 @@ public class InputMethodService extends AbstractInputMethodService { : IME_VISIBLE) : 0); } + private boolean isAutomotive() { + return getApplicationContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + } + /** * Performs a dump of the InputMethodService's internal state. Override * to add your own information to the dump. -- cgit v1.2.3 From e57f2dc246532d54229046d319d7b907b23288b3 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Sun, 26 Jan 2020 20:59:07 -0800 Subject: Exempt-From-Owner-Approval: Fix usages of WindowManager.getDefaultDisplay() in f/b Replace the existing usages of now-deprecated API WindowManager.getDefaultDisplay() with WindowMetrics or Context.getDisplay() in frameworks/base. Bug: 128338354 Test: Build, auto test Change-Id: I02d38a022c5e0e6e9d699f03d35b65d6c8126da9 --- .../android/inputmethodservice/InputMethodService.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 92047dcad09e..da9cc8a47a39 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -16,7 +16,6 @@ package android.inputmethodservice; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; @@ -52,7 +51,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; -import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; @@ -64,6 +62,7 @@ import android.text.method.MovementMethod; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; +import android.util.Size; import android.view.Gravity; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -560,12 +559,10 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void updateInputMethodDisplay(int displayId) { // Update display for adding IME window to the right display. - if (displayId != DEFAULT_DISPLAY) { - // TODO(b/111364446) Need to address context lifecycle issue if need to re-create - // for update resources & configuration correctly when show soft input - // in non-default display. - updateDisplay(displayId); - } + // TODO(b/111364446) Need to address context lifecycle issue if need to re-create + // for update resources & configuration correctly when show soft input + // in non-default display. + updateDisplay(displayId); } /** @@ -1466,8 +1463,9 @@ public class InputMethodService extends AbstractInputMethodService { * screen orientation changes. */ public int getMaxWidth() { - WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); - return wm.getDefaultDisplay().getWidth(); + final WindowManager windowManager = getSystemService(WindowManager.class); + final Size windowSize = windowManager.getCurrentWindowMetrics().getSize(); + return windowSize.getWidth(); } /** -- cgit v1.2.3 From 401162563844fe484e21082b25cf1843f393aaff Mon Sep 17 00:00:00 2001 From: Adam He Date: Tue, 4 Feb 2020 14:55:39 -0800 Subject: Move rendering logic for inline suggestions to ExtServices. Added a render service in ExtServices to connect to the renderer in androidx.autofill for inline suggestion slices. Cleaned up old UI rendering code that lived in system_server. Bug: 146453086 Test: atest ExtServicesUnitTests Change-Id: I25a7ea438afe524683671c850625ae80dacccfaa --- .../java/android/inputmethodservice/InputMethodService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 49e1d5e4f213..a95938b5db2d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -789,6 +789,7 @@ public class InputMethodService extends AbstractInputMethodService { Log.w(TAG, "onCreateInlineSuggestionsRequest() returned null request"); requestCallback.onInlineSuggestionsUnsupported(); } else { + request.setHostInputToken(getHostInputToken()); final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = new InlineSuggestionsResponseCallbackImpl(this, mInlineSuggestionsRequestInfo.mComponentName, @@ -833,6 +834,18 @@ public class InputMethodService extends AbstractInputMethodService { onInlineSuggestionsResponse(response); } + /** + * Returns the {@link IBinder} input token from the host view root. + */ + @Nullable + private IBinder getHostInputToken() { + ViewRootImpl viewRoot = null; + if (mRootView != null) { + viewRoot = mRootView.getViewRootImpl(); + } + return viewRoot == null ? null : viewRoot.getInputToken(); + } + private void notifyImeHidden() { setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition); onPreRenderedWindowVisibilityChanged(false /* setVisible */); -- cgit v1.2.3 From abd6b072ff174f46990ae07a38d6a444e475f832 Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Wed, 12 Feb 2020 19:08:44 -0800 Subject: Refactor the InputMethodService to move inline suggestion stuff to a separate class Test: manual Bug: 149442582 Change-Id: I71a3cf2ddd24dcf79709ec89136ad7609089f54c --- .../inputmethodservice/InputMethodService.java | 129 +++------------------ 1 file changed, 15 insertions(+), 114 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index a95938b5db2d..b1aa67e9f7ed 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -22,8 +22,6 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; - import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.AnyThread; @@ -51,7 +49,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; @@ -102,13 +99,11 @@ import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.view.IInlineSuggestionsRequestCallback; -import com.android.internal.view.IInlineSuggestionsResponseCallback; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; import java.util.Collections; /** @@ -450,7 +445,7 @@ public class InputMethodService extends AbstractInputMethodService { final int[] mTmpLocation = new int[2]; @Nullable - private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null; + private InlineSuggestionSession mInlineSuggestionSession; private boolean mAutomotiveHideNavBarForKeyboard; private boolean mIsAutomotive; @@ -465,8 +460,6 @@ public class InputMethodService extends AbstractInputMethodService { */ private IBinder mCurShowInputToken; - private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); - final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { onComputeInsets(mTmpInsets); if (isExtractViewShown()) { @@ -538,7 +531,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } - handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb); + handleOnCreateInlineSuggestionsRequest(componentName, cb); } /** @@ -770,40 +763,9 @@ public class InputMethodService extends AbstractInputMethodService { return false; } - /** - * Sends an {@link InlineSuggestionsRequest} obtained from - * {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through - * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}. - */ - private void makeInlineSuggestionsRequest() { - if (mInlineSuggestionsRequestInfo == null) { - Log.w(TAG, "makeInlineSuggestionsRequest() called with null requestInfo cache"); - return; - } - - final IInlineSuggestionsRequestCallback requestCallback = - mInlineSuggestionsRequestInfo.mCallback; - try { - final InlineSuggestionsRequest request = onCreateInlineSuggestionsRequest(); - if (request == null) { - Log.w(TAG, "onCreateInlineSuggestionsRequest() returned null request"); - requestCallback.onInlineSuggestionsUnsupported(); - } else { - request.setHostInputToken(getHostInputToken()); - final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = - new InlineSuggestionsResponseCallbackImpl(this, - mInlineSuggestionsRequestInfo.mComponentName, - mInlineSuggestionsRequestInfo.mFocusedId); - requestCallback.onInlineSuggestionsRequest(request, - inlineSuggestionsResponseCallback); - } - } catch (RemoteException e) { - Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e); - } - } - + @MainThread private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, - @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) { + @NonNull IInlineSuggestionsRequestCallback callback) { if (!mInputStarted) { try { Log.w(TAG, "onStartInput() not called yet"); @@ -814,24 +776,20 @@ public class InputMethodService extends AbstractInputMethodService { return; } - mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, - callback); - - makeInlineSuggestionsRequest(); + if (mInlineSuggestionSession != null) { + mInlineSuggestionSession.invalidateSession(); + } + mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback, + this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest, + this::getHostInputToken, this::onInlineSuggestionsResponse); } - private void handleOnInlineSuggestionsResponse(@NonNull ComponentName componentName, - @NonNull AutofillId autofillId, @NonNull InlineSuggestionsResponse response) { - if (!mInlineSuggestionsRequestInfo.validate(componentName)) { - if (DEBUG) { - Log.d(TAG, - "Response component=" + componentName + " differs from request component=" - + mInlineSuggestionsRequestInfo.mComponentName - + ", ignoring response"); - } - return; + @Nullable + private String getEditorInfoPackageName() { + if (mInputEditorInfo != null) { + return mInputEditorInfo.packageName; } - onInlineSuggestionsResponse(response); + return null; } /** @@ -863,63 +821,6 @@ public class InputMethodService extends AbstractInputMethodService { inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r)); } - /** - * Internal implementation of {@link IInlineSuggestionsResponseCallback}. - */ - private static final class InlineSuggestionsResponseCallbackImpl - extends IInlineSuggestionsResponseCallback.Stub { - private final WeakReference mInputMethodService; - - private final ComponentName mRequestComponentName; - private final AutofillId mRequestAutofillId; - - private InlineSuggestionsResponseCallbackImpl(InputMethodService inputMethodService, - ComponentName componentName, AutofillId autofillId) { - mInputMethodService = new WeakReference<>(inputMethodService); - mRequestComponentName = componentName; - mRequestAutofillId = autofillId; - } - - @Override - public void onInlineSuggestionsResponse(InlineSuggestionsResponse response) - throws RemoteException { - final InputMethodService service = mInputMethodService.get(); - if (service != null) { - service.mHandler.sendMessage(obtainMessage( - InputMethodService::handleOnInlineSuggestionsResponse, service, - mRequestComponentName, mRequestAutofillId, response)); - } - } - } - - /** - * Information about incoming requests from Autofill Frameworks for inline suggestions. - */ - private static final class InlineSuggestionsRequestInfo { - final ComponentName mComponentName; - final AutofillId mFocusedId; - final IInlineSuggestionsRequestCallback mCallback; - - InlineSuggestionsRequestInfo(ComponentName componentName, AutofillId focusedId, - IInlineSuggestionsRequestCallback callback) { - this.mComponentName = componentName; - this.mFocusedId = focusedId; - this.mCallback = callback; - } - - /** - * Returns whether the cached {@link ComponentName} matches the passed in activity. - */ - public boolean validate(ComponentName componentName) { - final boolean result = componentName.equals(mComponentName); - if (DEBUG && !result) { - Log.d(TAG, "Cached request info ComponentName=" + mComponentName - + " differs from received ComponentName=" + componentName); - } - return result; - } - } - /** * Concrete implementation of * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides -- cgit v1.2.3 From 36960ee20ea612b2df2447d73003ac4af6f32341 Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Tue, 18 Feb 2020 18:23:30 -0800 Subject: Introduces the Bundle to inline suggestions APIs to encode custom UI styling information. * The bundle will be generated/consumed by the support library. * More API documentation and example usage will be added later once we have the support library impl ready. * The old style resource name approach doesn't work due to the potential mismatch in the support library version across the host IME and the platform renderer service, and the non-static nature of the public attribute int id in the support lib. * The Bundle added to the onCreateInlineSuggestionsRequest() is intended for the platform/ExtServices to communicate the UI versions it supports. * The Bundle added to the InlinePresentationSpec is intended for the IME to communicate the custom styles for the chosen UI versions. Test: manual verification, and also atest CtsInputMethodTestCases:InlineSuggestionInfoTest CtsInputMethodTestCases:InlineSuggestionTest CtsInputMethodTestCases:InlineSuggestionsRequestTest CtsInputMethodTestCases:InlineSuggestionsResponseTest Bug: 146454892 Change-Id: Id7fea32a7550fb924fec811b376790474a7b92eb --- .../inputmethodservice/InputMethodService.java | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index b1aa67e9f7ed..20a4ab35defe 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -34,7 +34,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.Dialog; import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -74,7 +73,6 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; -import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -99,6 +97,7 @@ import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperations; import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -526,12 +525,13 @@ public class InputMethodService extends AbstractInputMethodService { */ @MainThread @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest( + @NonNull InlineSuggestionsRequestInfo requestInfo, + @NonNull IInlineSuggestionsRequestCallback cb) { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } - handleOnCreateInlineSuggestionsRequest(componentName, cb); + handleOnCreateInlineSuggestionsRequest(requestInfo, cb); } /** @@ -742,11 +742,14 @@ public class InputMethodService extends AbstractInputMethodService { // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. /** - * Returns an {@link InlineSuggestionsRequest} to be sent to Autofill. + * This method should be implemented by subclass which supports displaying autofill inline + * suggestion. * - *

Should be implemented by subclasses.

+ * @param uiExtras the extras that contain the UI renderer related information + * @return an {@link InlineSuggestionsRequest} to be sent to Autofill. */ - public @Nullable InlineSuggestionsRequest onCreateInlineSuggestionsRequest() { + @Nullable + public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(@NonNull Bundle uiExtras) { return null; } @@ -764,7 +767,8 @@ public class InputMethodService extends AbstractInputMethodService { } @MainThread - private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName, + private void handleOnCreateInlineSuggestionsRequest( + @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback) { if (!mInputStarted) { try { @@ -779,8 +783,9 @@ public class InputMethodService extends AbstractInputMethodService { if (mInlineSuggestionSession != null) { mInlineSuggestionSession.invalidateSession(); } - mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback, - this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest, + mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), + callback, this::getEditorInfoPackageName, + () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), this::getHostInputToken, this::onInlineSuggestionsResponse); } -- cgit v1.2.3 From 94c9a8328e4dc9f8942ffc0d02784700ee77880b Mon Sep 17 00:00:00 2001 From: Tarandeep Singh Date: Mon, 3 Feb 2020 14:55:30 -0800 Subject: Remove IME surface when hidden When IME is no longer shown, notify IMS to hide the window surface. This reclaims the memory allocated to IME window surface. Fix: 150163310 Test: atest CtsInputMethodTests Manually: 1. Open any app that has editor and run adb shell dumpsys SurfaceFlinger | grep Total 2. Note down total memory 3. Tap on editor and IME shows. Note down memory using command in #1. It should go up by ~27MB 4. Hide IME and note down memory again. It should revert to original value in #1. Change-Id: I6c2a13dd40b22d3fd62b4763ba369992e5ff1138 --- .../android/inputmethodservice/InputMethodService.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 20a4ab35defe..61adfbce30bf 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -814,6 +814,13 @@ public class InputMethodService extends AbstractInputMethodService { onPreRenderedWindowVisibilityChanged(false /* setVisible */); } + private void removeImeSurface() { + if (!mShowInputRequested && !mWindowVisible) { + // hiding a window removes its surface. + mWindow.hide(); + } + } + private void setImeWindowStatus(int visibilityFlags, int backDisposition) { mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition); } @@ -932,6 +939,14 @@ public class InputMethodService extends AbstractInputMethodService { public final void notifyImeHidden() { InputMethodService.this.notifyImeHidden(); } + + /** + * Notify IME that surface can be now removed. + * @hide + */ + public final void removeImeSurface() { + InputMethodService.this.removeImeSurface(); + } } /** -- cgit v1.2.3 From 4fe5b654a1e420fd66781b09223a1c25f9a06aeb Mon Sep 17 00:00:00 2001 From: Tarandeep Singh Date: Thu, 20 Feb 2020 17:20:19 -0800 Subject: Pipe windowToken for hideSoftInput Pipe the windowToken of the window requesting hideSoftInput just like we did it for showSoftInput [1]. This calls hideInsets on the correct display when control target is different from IME target e.g. ActivityView. Also hideInsets should be called on InsetsControlTarget instead which was originally attempted in [2] [1]: Ia49e23dd077d264a58d28a7b8acffde54b7db187 [2]: I7133e151a1037c42b275b97857936437a7a6725f Bug: 149870112 Bug: 133381284 Test: Manually using steps mentioned in bug. Change-Id: Ia596a392eb73ae46debd097151c8c9a7edd59833 --- .../inputmethodservice/InputMethodService.java | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 20a4ab35defe..45aea4f3d8fc 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -459,6 +459,16 @@ public class InputMethodService extends AbstractInputMethodService { */ private IBinder mCurShowInputToken; + /** + * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#hideSoftInput} + * The original app window token is passed from client app window. + * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique dummy + * token to identify this window. + * This dummy token is only valid for a single call to {@link InputMethodImpl#hideSoftInput}, + * after which it is set {@code null} until next call. + */ + private IBinder mCurHideInputToken; + final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { onComputeInsets(mTmpInsets); if (isExtractViewShown()) { @@ -500,6 +510,7 @@ public class InputMethodService extends AbstractInputMethodService { public class InputMethodImpl extends AbstractInputMethodImpl { private boolean mSystemCallingShowSoftInput; + private boolean mSystemCallingHideSoftInput; /** * {@inheritDoc} @@ -634,6 +645,21 @@ public class InputMethodService extends AbstractInputMethodService { } } + /** + * {@inheritDoc} + * @hide + */ + @MainThread + @Override + public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver, + IBinder hideInputToken) { + mSystemCallingHideSoftInput = true; + mCurHideInputToken = hideInputToken; + hideSoftInput(flags, resultReceiver); + mCurHideInputToken = null; + mSystemCallingHideSoftInput = false; + } + /** * {@inheritDoc} */ @@ -641,6 +667,12 @@ public class InputMethodService extends AbstractInputMethodService { @Override public void hideSoftInput(int flags, ResultReceiver resultReceiver) { if (DEBUG) Log.v(TAG, "hideSoftInput()"); + if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R + && !mSystemCallingHideSoftInput) { + Log.e(TAG, "IME shouldn't call hideSoftInput on itself." + + " Use requestHideSelf(int) itself"); + return; + } final boolean wasVisible = mIsPreRendered ? mDecorViewVisible && mWindowVisible : isInputViewShown(); applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */); @@ -738,6 +770,15 @@ public class InputMethodService extends AbstractInputMethodService { public void setCurrentShowInputToken(IBinder showInputToken) { mCurShowInputToken = showInputToken; } + + /** + * {@inheritDoc} + * @hide + */ + @Override + public void setCurrentHideInputToken(IBinder hideInputToken) { + mCurHideInputToken = hideInputToken; + } } // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. @@ -2157,7 +2198,8 @@ public class InputMethodService extends AbstractInputMethodService { if (!isVisibilityAppliedUsingInsetsConsumer()) { return; } - mPrivOps.applyImeVisibility(mCurShowInputToken, setVisible); + mPrivOps.applyImeVisibility(setVisible + ? mCurShowInputToken : mCurHideInputToken, setVisible); } private boolean isVisibilityAppliedUsingInsetsConsumer() { -- cgit v1.2.3 From e65a97cef4e9a9b801e0ff985349d4059364ed59 Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Fri, 28 Feb 2020 11:39:56 -0800 Subject: Populate the autofillId in the IMS EditorInfo * So it can be checked against the autofillId from autofill manager service * Currently not checking due to race condition, will find a fix in follow up CL Test: manual verification Bug: 149522488 Change-Id: I49457e33c7a1acb028023cb70f248805a96c5346 --- core/java/android/inputmethodservice/InputMethodService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 27839e780494..d27d1382e09d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -73,6 +73,7 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; +import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -825,7 +826,7 @@ public class InputMethodService extends AbstractInputMethodService { mInlineSuggestionSession.invalidateSession(); } mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), - callback, this::getEditorInfoPackageName, + callback, this::getEditorInfoPackageName, this::getEditorInfoAutofillId, () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), this::getHostInputToken, this::onInlineSuggestionsResponse); } @@ -838,6 +839,14 @@ public class InputMethodService extends AbstractInputMethodService { return null; } + @Nullable + private AutofillId getEditorInfoAutofillId() { + if (mInputEditorInfo != null) { + return mInputEditorInfo.autofillId; + } + return null; + } + /** * Returns the {@link IBinder} input token from the host view root. */ -- cgit v1.2.3 From 7c85eb79a7434f011c6ab903cc0b945758711baf Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Fri, 28 Feb 2020 11:39:56 -0800 Subject: Notify autofill with the IME start/finish input view events * autofill will cache the inline suggestions response until it receives a start input view event from IME * the data flow from IMS point of view is: IMS#startViews and IMS#doStartInput (before calling onStartInputView) -> [async] InlineSuggestionsRequestCallback#onInputMethodStartInputView() --- process boundary --- -> IMMS.InlineSuggestionsRequestCallbackDecorator #onInputMethodStartInputView() -> InlineSuggestionSession.InlineSuggestionsRequestCallbackImpl #onInputMethodStartInputView() * similar data flow for IMS#finishViews() * this CL should not block IME's UI thread because it's only issuing a new async IPC from IMS start/finish input view call that's running on the UI thread. * there should not be performance impact on IMEs if autofill inline integration is not active Test: manual verification, atest EditorInfoTest Test: atest android.autofillservice.cts.inline, with two failing cases: InlineAugmentedLoginActivityTest#testAugmentedAutoFill_twoDatasetThenFilledSecond and InlineAugmentedLoginActivityTest#testAugmentedAutoFill_oneDatasetThenFilled due to the test itself being broken, I'll fix the test in a separate patch Bug: 149522488 Bug: 149442582 Change-Id: I2faa3577b9f95a122f26a6d7fa7822a769a51e34 --- .../inputmethodservice/InputMethodService.java | 39 ++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index d27d1382e09d..9e639346de73 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -444,6 +444,16 @@ public class InputMethodService extends AbstractInputMethodService { final Insets mTmpInsets = new Insets(); final int[] mTmpLocation = new int[2]; + /** + * We use a separate {@code mInlineLock} to make sure {@code mInlineSuggestionSession} is + * only accessed synchronously. Although when the lock is introduced, all the calls are from + * the main thread so the lock is not really necessarily (but for the same reason it also + * doesn't hurt), it's still being added as a safety guard to make sure in the future we + * don't add more code causing race condition when updating the {@code + * mInlineSuggestionSession}. + */ + private final Object mInlineLock = new Object(); + @GuardedBy("mInlineLock") @Nullable private InlineSuggestionSession mInlineSuggestionSession; @@ -822,13 +832,15 @@ public class InputMethodService extends AbstractInputMethodService { return; } - if (mInlineSuggestionSession != null) { - mInlineSuggestionSession.invalidateSession(); + synchronized (mInlineLock) { + if (mInlineSuggestionSession != null) { + mInlineSuggestionSession.invalidateSession(); + } + mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), + callback, this::getEditorInfoPackageName, this::getEditorInfoAutofillId, + () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), + this::getHostInputToken, this::onInlineSuggestionsResponse, mInputViewStarted); } - mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), - callback, this::getEditorInfoPackageName, this::getEditorInfoAutofillId, - () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), - this::getHostInputToken, this::onInlineSuggestionsResponse); } @Nullable @@ -2193,6 +2205,11 @@ public class InputMethodService extends AbstractInputMethodService { if (!mInputViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onStartInputView"); mInputViewStarted = true; + synchronized (mInlineLock) { + if (mInlineSuggestionSession != null) { + mInlineSuggestionSession.notifyOnStartInputView(getEditorInfoAutofillId()); + } + } onStartInputView(mInputEditorInfo, false); } } else if (!mCandidatesViewStarted) { @@ -2233,6 +2250,11 @@ public class InputMethodService extends AbstractInputMethodService { private void finishViews(boolean finishingInput) { if (mInputViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onFinishInputView"); + synchronized (mInlineLock) { + if (mInlineSuggestionSession != null) { + mInlineSuggestionSession.notifyOnFinishInputView(getEditorInfoAutofillId()); + } + } onFinishInputView(finishingInput); } else if (mCandidatesViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView"); @@ -2345,6 +2367,11 @@ public class InputMethodService extends AbstractInputMethodService { if (mShowInputRequested) { if (DEBUG) Log.v(TAG, "CALL: onStartInputView"); mInputViewStarted = true; + synchronized (mInlineLock) { + if (mInlineSuggestionSession != null) { + mInlineSuggestionSession.notifyOnStartInputView(getEditorInfoAutofillId()); + } + } onStartInputView(mInputEditorInfo, restarting); startExtractingText(true); } else if (mCandidatesVisibility == View.VISIBLE) { -- cgit v1.2.3 From 0fe4f784f4ee850c464a4a4f04bc5048d3e89b64 Mon Sep 17 00:00:00 2001 From: Tarandeep Singh Date: Thu, 5 Mar 2020 13:37:53 -0800 Subject: Remove IME surface when window unbinds Previous attempt to remove IME surface [1] works when IME animates out within same app window. However, if IME doesn't animate or window hides without hiding keyboard, surface would still be around in memory. With this CL, IME surface will be hidden moment it unbinds from the window. [1] I6c2a13dd40b22d3fd62b4763ba369992e5ff1138 Bug: 150163310 Test: Manually: 1. Open any app that has editor and tap on editor to show IME adb shell dumpsys SurfaceFlinger | grep InputMethod 2. Note down IME Buffer layers that consume memory using command in #1 3. Hide IME and note down memory again. It should not have anything other than container layers 4. Use 3 button navbar and retest by pressing home button Change-Id: I629fa817eb57e8dd6f7e58c1a358487a16363ddb --- core/java/android/inputmethodservice/InputMethodService.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 9e639346de73..1b6c1ee4f7e2 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -611,6 +611,10 @@ public class InputMethodService extends AbstractInputMethodService { public void unbindInput() { if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding + " ic=" + mInputConnection); + // Unbind input is per process per display. + // TODO(b/150902448): free-up IME surface when target is changing. + // e.g. DisplayContent#setInputMethodTarget() + removeImeSurface(); onUnbindInput(); mInputBinding = null; mInputConnection = null; -- cgit v1.2.3 From c8364e3878aa8e0f9e8dda1bd5305c5ef7eeada0 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Tue, 10 Mar 2020 21:20:58 +0800 Subject: Make IME fit navgation bars at left and right sides IME is not big enough to be the background of navigation bar when navigation bar is on the left or right edge of the screen. Also, IME can be on top of navigation bar in landscape split-screen mode, we don't want IME to block touches on navigation bar. Fix: 151083985 Test: 1. Open Messages. 2. Rotate device to landscape. 3. Click on "Search message" and see if IME extends into the navigation bar area at the left or right edge. Change-Id: I0ef3d6379a9ae52b3749154d2fdc54e9aa94a9e0 --- core/java/android/inputmethodservice/InputMethodService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 1b6c1ee4f7e2..7e4d68d9925e 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -71,6 +72,7 @@ import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowInsets; +import android.view.WindowInsets.Side; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.view.autofill.AutofillId; @@ -1246,7 +1248,8 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars()); + mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars()); + mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM); // IME layout should always be inset by navigation bar, no matter its current visibility, // unless automotive requests it, since automotive may hide the navigation bar. -- cgit v1.2.3 From e68d6f53ce120c433d7b3741c16f06695751dadc Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Mon, 16 Mar 2020 11:53:05 -0700 Subject: Handle IME hide internal state correctly. IME process is notified after client has hidden the IME. At this point IME should call doHideWindow() so internal lifecycle methods are called the way they were called earlier. Also, with insets we don't hide the decorView of IME window till client is unbound, so to be consistent with previous behavior, call windowVisibilityChanged(View.GONE) explicitly. Fix: 151125925 Test: atest KeyboardVisibilityTest InputMethodServiceTest Change-Id: Ibe9a02b93489370b6ae9b497993e366f88791a62 --- core/java/android/inputmethodservice/InputMethodService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 7e4d68d9925e..2cafcdb9f4aa 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -878,8 +878,7 @@ public class InputMethodService extends AbstractInputMethodService { } private void notifyImeHidden() { - setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition); - onPreRenderedWindowVisibilityChanged(false /* setVisible */); + doHideWindow(); } private void removeImeSurface() { @@ -2284,7 +2283,9 @@ public class InputMethodService extends AbstractInputMethodService { if (mDecorViewVisible) { // When insets API is enabled, it is responsible for client and server side // visibility of IME window. - if (!isVisibilityAppliedUsingInsetsConsumer()) { + if (isVisibilityAppliedUsingInsetsConsumer()) { + mInputView.dispatchWindowVisibilityChanged(View.GONE); + } else { mWindow.hide(); } mDecorViewVisible = false; -- cgit v1.2.3 From f739e47c41303231ebde042d4fefcf929ebb1a27 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Fri, 20 Mar 2020 13:08:10 -0700 Subject: Add null check in IMS hideWindow Input view can be null. Add a null check. Fix: 152060038 Test: Manually using steps in bug Change-Id: I1ed899ef83b75003b0862f97de733247fe840ae4 --- core/java/android/inputmethodservice/InputMethodService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 2cafcdb9f4aa..c2ee21d5115d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -2284,7 +2284,9 @@ public class InputMethodService extends AbstractInputMethodService { // When insets API is enabled, it is responsible for client and server side // visibility of IME window. if (isVisibilityAppliedUsingInsetsConsumer()) { - mInputView.dispatchWindowVisibilityChanged(View.GONE); + if (mInputView != null) { + mInputView.dispatchWindowVisibilityChanged(View.GONE); + } } else { mWindow.hide(); } -- cgit v1.2.3 From aef529a7cc6ab4de33c8e5deb7c3a62784920783 Mon Sep 17 00:00:00 2001 From: Taran Singh Date: Mon, 23 Mar 2020 16:57:22 -0700 Subject: Fix IME hide state Insets API notifies IME when it's hidden. however, IMMS never really received these state changes. Using requestHideSelf() makes sure IMMS is in-sync. Fix: 151980214 Test: manually using the steps in bug Change-Id: I7f6098a61a5942795ffd33a60329e4dd5fb5d6cb --- core/java/android/inputmethodservice/InputMethodService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c2ee21d5115d..7c34ddcb9287 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -878,7 +878,7 @@ public class InputMethodService extends AbstractInputMethodService { } private void notifyImeHidden() { - doHideWindow(); + requestHideSelf(0); } private void removeImeSurface() { -- cgit v1.2.3 From 0be1d67b681982e20f87359a810ba6c94e438378 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Thu, 5 Mar 2020 19:34:43 -0800 Subject: Report bounds instead of size in WindowMetrics Use case: Jetpack WM will use them to get the location of windows on screen and compute the display feature positions in window coordinate space. Bug: 150908045 Test: atest FrameworksCoreTests:WindowMetricsTest Test: atest CtsWindowManagerDeviceTestCases:WindowMetricsTests Change-Id: Ia08950cd5df35971408e8b17bb27d97d29d0ab9b Exempt-From-Owner-Approval: API change --- core/java/android/inputmethodservice/InputMethodService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c2ee21d5115d..a6d2fa8c3176 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -60,7 +60,6 @@ import android.text.method.MovementMethod; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.util.Size; import android.view.Gravity; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -1479,8 +1478,8 @@ public class InputMethodService extends AbstractInputMethodService { */ public int getMaxWidth() { final WindowManager windowManager = getSystemService(WindowManager.class); - final Size windowSize = windowManager.getCurrentWindowMetrics().getSize(); - return windowSize.getWidth(); + final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); + return windowBounds.width(); } /** -- cgit v1.2.3 From 227c665910377b3346760b2cb502d5c3f722f76b Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Thu, 19 Mar 2020 22:28:43 +0800 Subject: Make canBeImeTarget be compatible with legacy behavior And let IME always extend into the status bar area so that the position of IME can never affected by status bar. This can prevent flicker during IME animation. This CL also makes PerDisplay can restart the animation while the insets source control is changed during animation. Fix: 151759336 Test: atest WindowStateTests Change-Id: Ic2a308e6b7ec39b4b8645751e31addd26ddf3735 --- core/java/android/inputmethodservice/InputMethodService.java | 1 + 1 file changed, 1 insertion(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c2ee21d5115d..6af4f93788f1 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1249,6 +1249,7 @@ public class InputMethodService extends AbstractInputMethodService { WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars()); mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM); + mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true); // IME layout should always be inset by navigation bar, no matter its current visibility, // unless automotive requests it, since automotive may hide the navigation bar. -- cgit v1.2.3 From 97ec1c4dcc756854d9ecd763008df7c9c673ecfa Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Wed, 25 Mar 2020 12:20:42 -0700 Subject: Send more IME events to autofill manager service. * In IME side, wait for the input start before calling back to Autofill, rather than returning inline unsupported immediately. * Also adds an InlineSuggestionManager to simplify code in the InputMethodService Test: atest CtsAutoFillServiceTestCases Test: atest CtsInputMethodTestCases Bug: 151123764 Change-Id: I199925d77aa508f259e98a8929120aeb96015b57 --- .../inputmethodservice/InputMethodService.java | 85 ++++------------------ 1 file changed, 14 insertions(+), 71 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 782fff2f69e0..93ce88b767bc 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -49,7 +49,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; import android.provider.Settings; @@ -74,7 +73,6 @@ import android.view.WindowInsets; import android.view.WindowInsets.Side; import android.view.WindowManager; import android.view.animation.AnimationUtils; -import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -445,18 +443,7 @@ public class InputMethodService extends AbstractInputMethodService { final Insets mTmpInsets = new Insets(); final int[] mTmpLocation = new int[2]; - /** - * We use a separate {@code mInlineLock} to make sure {@code mInlineSuggestionSession} is - * only accessed synchronously. Although when the lock is introduced, all the calls are from - * the main thread so the lock is not really necessarily (but for the same reason it also - * doesn't hurt), it's still being added as a safety guard to make sure in the future we - * don't add more code causing race condition when updating the {@code - * mInlineSuggestionSession}. - */ - private final Object mInlineLock = new Object(); - @GuardedBy("mInlineLock") - @Nullable - private InlineSuggestionSession mInlineSuggestionSession; + private InlineSuggestionSessionController mInlineSuggestionSessionController; private boolean mAutomotiveHideNavBarForKeyboard; private boolean mIsAutomotive; @@ -554,7 +541,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } - handleOnCreateInlineSuggestionsRequest(requestInfo, cb); + mInlineSuggestionSessionController.onMakeInlineSuggestionsRequest(requestInfo, cb); } /** @@ -823,47 +810,6 @@ public class InputMethodService extends AbstractInputMethodService { return false; } - @MainThread - private void handleOnCreateInlineSuggestionsRequest( - @NonNull InlineSuggestionsRequestInfo requestInfo, - @NonNull IInlineSuggestionsRequestCallback callback) { - if (!mInputStarted) { - try { - Log.w(TAG, "onStartInput() not called yet"); - callback.onInlineSuggestionsUnsupported(); - } catch (RemoteException e) { - Log.w(TAG, "Failed to call onInlineSuggestionsUnsupported.", e); - } - return; - } - - synchronized (mInlineLock) { - if (mInlineSuggestionSession != null) { - mInlineSuggestionSession.invalidateSession(); - } - mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), - callback, this::getEditorInfoPackageName, this::getEditorInfoAutofillId, - () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), - this::getHostInputToken, this::onInlineSuggestionsResponse, mInputViewStarted); - } - } - - @Nullable - private String getEditorInfoPackageName() { - if (mInputEditorInfo != null) { - return mInputEditorInfo.packageName; - } - return null; - } - - @Nullable - private AutofillId getEditorInfoAutofillId() { - if (mInputEditorInfo != null) { - return mInputEditorInfo.autofillId; - } - return null; - } - /** * Returns the {@link IBinder} input token from the host view root. */ @@ -1269,6 +1215,10 @@ public class InputMethodService extends AbstractInputMethodService { initViews(); mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT); + + mInlineSuggestionSessionController = new InlineSuggestionSessionController( + this::onCreateInlineSuggestionsRequest, this::getHostInputToken, + this::onInlineSuggestionsResponse); } /** @@ -2112,6 +2062,7 @@ public class InputMethodService extends AbstractInputMethodService { */ private boolean dispatchOnShowInputRequested(int flags, boolean configChange) { final boolean result = onShowInputRequested(flags, configChange); + mInlineSuggestionSessionController.notifyOnShowInputRequested(result); if (result) { mShowInputFlags = flags; } else { @@ -2211,11 +2162,7 @@ public class InputMethodService extends AbstractInputMethodService { if (!mInputViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onStartInputView"); mInputViewStarted = true; - synchronized (mInlineLock) { - if (mInlineSuggestionSession != null) { - mInlineSuggestionSession.notifyOnStartInputView(getEditorInfoAutofillId()); - } - } + mInlineSuggestionSessionController.notifyOnStartInputView(); onStartInputView(mInputEditorInfo, false); } } else if (!mCandidatesViewStarted) { @@ -2256,11 +2203,7 @@ public class InputMethodService extends AbstractInputMethodService { private void finishViews(boolean finishingInput) { if (mInputViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onFinishInputView"); - synchronized (mInlineLock) { - if (mInlineSuggestionSession != null) { - mInlineSuggestionSession.notifyOnFinishInputView(getEditorInfoAutofillId()); - } - } + mInlineSuggestionSessionController.notifyOnFinishInputView(); onFinishInputView(finishingInput); } else if (mCandidatesViewStarted) { if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView"); @@ -2355,6 +2298,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "CALL: doFinishInput"); finishViews(true /* finishingInput */); if (mInputStarted) { + mInlineSuggestionSessionController.notifyOnFinishInput(); if (DEBUG) Log.v(TAG, "CALL: onFinishInput"); onFinishInput(); } @@ -2371,17 +2315,16 @@ public class InputMethodService extends AbstractInputMethodService { mStartedInputConnection = ic; mInputEditorInfo = attribute; initialize(); + mInlineSuggestionSessionController.notifyOnStartInput( + attribute == null ? null : attribute.packageName, + attribute == null ? null : attribute.autofillId); if (DEBUG) Log.v(TAG, "CALL: onStartInput"); onStartInput(attribute, restarting); if (mDecorViewVisible) { if (mShowInputRequested) { if (DEBUG) Log.v(TAG, "CALL: onStartInputView"); mInputViewStarted = true; - synchronized (mInlineLock) { - if (mInlineSuggestionSession != null) { - mInlineSuggestionSession.notifyOnStartInputView(getEditorInfoAutofillId()); - } - } + mInlineSuggestionSessionController.notifyOnStartInputView(); onStartInputView(mInputEditorInfo, restarting); startExtractingText(true); } else if (mCandidatesVisibility == View.VISIBLE) { -- cgit v1.2.3 From 045c020636b20033bb83c1eb06fbbfee432e7515 Mon Sep 17 00:00:00 2001 From: Adam He Date: Fri, 17 Apr 2020 15:20:01 -0700 Subject: Address leftover TODOs from inline suggestions. Fixes: 146524826 Test: atest android.autofillservice.cts.inline Change-Id: I50666e9fa012b18f74c20982068a452fdc9592f8 --- .../android/inputmethodservice/InputMethodService.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 93ce88b767bc..d3464fde4b75 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -784,10 +784,19 @@ public class InputMethodService extends AbstractInputMethodService { } } - // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. /** - * This method should be implemented by subclass which supports displaying autofill inline - * suggestion. + * Called when Autofill is requesting an {@link InlineSuggestionsRequest} from the IME. + * + *

The Autofill Framework will first request the IME to create and send an + * {@link InlineSuggestionsRequest} back. Once Autofill Framework receives a valid request and + * also receives valid inline suggestions, they will be returned via + * {@link #onInlineSuggestionsResponse(InlineSuggestionsResponse)}.

+ * + *

IME Lifecycle - The request will wait to be created after inputStarted

+ * + *

If the IME wants to support displaying inline suggestions, they must set + * supportsInlineSuggestions in its XML and implement this method to return a valid + * {@link InlineSuggestionsRequest}.

* * @param uiExtras the extras that contain the UI renderer related information * @return an {@link InlineSuggestionsRequest} to be sent to Autofill. -- cgit v1.2.3 From 49f329ca66e3cf06a8c6086b77333c68fef5cf5b Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Thu, 13 Feb 2020 16:41:32 +0800 Subject: Add WindowMetricsHelper This metrics now is used for calculating the value reported by Display#getSize. It could be extended to have more function later. Also replace getCurrentMetrics usages to make them report Display#getSize value. Bug: 148904274 Test: atest WindowMetricsHelperTest Change-Id: I182b6e63f7c28752eee22839cb9e69f073046c3f --- core/java/android/inputmethodservice/InputMethodService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index d3464fde4b75..d8b1f41c86d5 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -90,6 +90,7 @@ import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; +import android.window.WindowMetricsHelper; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.IInputContentUriToken; @@ -1438,8 +1439,8 @@ public class InputMethodService extends AbstractInputMethodService { */ public int getMaxWidth() { final WindowManager windowManager = getSystemService(WindowManager.class); - final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); - return windowBounds.width(); + return WindowMetricsHelper.getBoundsExcludingNavigationBarAndCutout( + windowManager.getCurrentWindowMetrics()).width(); } /** -- cgit v1.2.3 From 618dbe022ff715cadff46e1d4102b2f0715e85ea Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Fri, 19 Jun 2020 00:12:55 +0800 Subject: Disable user animations on insets whose visible frame is empty (refined) Floating IME or fullscreen IME won't cause insets (except the area overlapped with navigation bar). It doesn't make much sense to let apps move the IME at these cases. Fix: 157777145 Test: atest InsetsSourceConsumerTest GlobalActionsImeTest ImeInsetsControllerTest Change-Id: Id70f59be7653beedc02d6c8bc3b1bd50a357f4fe --- core/java/android/inputmethodservice/InputMethodService.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index d8b1f41c86d5..5647bf90d2fb 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -471,6 +471,10 @@ public class InputMethodService extends AbstractInputMethodService { final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { onComputeInsets(mTmpInsets); + if (!mViewsCreated) { + // The IME views are not ready, keep visible insets untouched. + mTmpInsets.visibleTopInsets = 0; + } if (isExtractViewShown()) { // In true fullscreen mode, we just say the window isn't covering // any content so we don't impact whatever is behind. -- cgit v1.2.3 From 2260ce4dafdd1fdaf8cbaf7579119ed7ecded088 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Thu, 2 Jul 2020 18:57:22 +0200 Subject: Fix IME flicker: move hiding the surface into the control target Fixes a flicker that occurs during transitions between windows. This happens for two reasons: 1.) Control is immediately transferred to the new window, and the previous window didn't get a chance to play the animation. This is addressed by adding logic to keep control on the exiting window for the duration of the transition - similar to what we do with the target for z-ordering purposes. 2.) Upon the input connection being severed, the InputMethodService immediately hides its window, preventing any animations whenever the input connection changes This is addressed by moving hiding of the surface into the controlling windows - where upon receiving control, we now trigger removal of the IME surface if we don't show it. Additionally: - Now ensures that any requests from the ImeInsetsSourceConsumer ensure that they come from the window that is currently served by IMM. - Removes the transparancy clause from isImeTargetFromDisplayContentAndImeSame to match the updated IME target computation in DisplayContent in [1]. [1]: Iedd5f7407926167f4891ce9b7e9a79e22751e668 Fixes: 153145997 Fixes: 150902448 Test: atest WindowInsetsAnimationControllerTests Test: atest DisplayContentTests InsetsSourceConsumerTest Test: Open app with IME, press HOME button, verify IME smoothly animates away Test: Open Messages, open a thread, open IME. Click search icon, verify IME opens in the search activity Change-Id: I4910c2a06cc67b0470477b245fc1de54b75f10f9 --- core/java/android/inputmethodservice/InputMethodService.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'core/java/android/inputmethodservice/InputMethodService.java') diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 5647bf90d2fb..c5a11abe1136 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -605,9 +605,6 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding + " ic=" + mInputConnection); // Unbind input is per process per display. - // TODO(b/150902448): free-up IME surface when target is changing. - // e.g. DisplayContent#setInputMethodTarget() - removeImeSurface(); onUnbindInput(); mInputBinding = null; mInputConnection = null; -- cgit v1.2.3