Loading services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java 0 → 100644 +236 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputMethodInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback; import com.android.internal.inputmethod.InlineSuggestionsRequestInfo; /** * A controller managing autofill suggestion requests. */ final class AutofillSuggestionsController { private static final boolean DEBUG = false; private static final String TAG = AutofillSuggestionsController.class.getSimpleName(); @NonNull private final InputMethodManagerService mService; @NonNull private final ArrayMap<String, InputMethodInfo> mMethodMap; @NonNull private final InputMethodUtils.InputMethodSettings mSettings; private static final class CreateInlineSuggestionsRequest { @NonNull final InlineSuggestionsRequestInfo mRequestInfo; @NonNull final IInlineSuggestionsRequestCallback mCallback; @NonNull final String mPackageName; CreateInlineSuggestionsRequest( @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String packageName) { mRequestInfo = requestInfo; mCallback = callback; mPackageName = packageName; } } /** * If a request to create inline autofill suggestions comes in while the IME is unbound * due to {@link InputMethodManagerService#mPreventImeStartupUnlessTextEditor}, * this is where it is stored, so that it may be fulfilled once the IME rebinds. */ @GuardedBy("ImfLock.class") @Nullable private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest; /** * A callback into the autofill service obtained from the latest call to * {@link #onCreateInlineSuggestionsRequest}, which can be used to invalidate an * autofill session in case the IME process dies. */ @GuardedBy("ImfLock.class") @Nullable private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback; AutofillSuggestionsController(@NonNull InputMethodManagerService service) { mService = service; mMethodMap = mService.mMethodMap; mSettings = mService.mSettings; } @GuardedBy("ImfLock.class") void onCreateInlineSuggestionsRequest(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) { clearPendingInlineSuggestionsRequest(); mInlineSuggestionsRequestCallback = callback; final InputMethodInfo imi = mMethodMap.get(mService.getSelectedMethodIdLocked()); try { if (userId == mSettings.getCurrentUserId() && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) { mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest( requestInfo, callback, imi.getPackageName()); if (mService.getCurMethodLocked() != null) { // In the normal case when the IME is connected, we can make the request here. performOnCreateInlineSuggestionsRequest(); } else { // Otherwise, the next time the IME connection is established, // InputMethodBindingController.mMainConnection#onServiceConnected() will call // into #performOnCreateInlineSuggestionsRequestLocked() to make the request. if (DEBUG) { Slog.d(TAG, "IME not connected. Delaying inline suggestions request."); } } } else { callback.onInlineSuggestionsUnsupported(); } } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e); } } @GuardedBy("ImfLock.class") void performOnCreateInlineSuggestionsRequest() { if (mPendingInlineSuggestionsRequest == null) { return; } IInputMethodInvoker curMethod = mService.getCurMethodLocked(); if (DEBUG) { Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod); } if (curMethod != null) { final IInlineSuggestionsRequestCallback callback = new InlineSuggestionsRequestCallbackDecorator( mPendingInlineSuggestionsRequest.mCallback, mPendingInlineSuggestionsRequest.mPackageName, mService.getCurTokenDisplayIdLocked(), mService.getCurTokenLocked(), mService); curMethod.onCreateInlineSuggestionsRequest( mPendingInlineSuggestionsRequest.mRequestInfo, callback); } else { Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request."); } clearPendingInlineSuggestionsRequest(); } @GuardedBy("ImfLock.class") private void clearPendingInlineSuggestionsRequest() { mPendingInlineSuggestionsRequest = null; } private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi, boolean touchExplorationEnabled) { return imi.isInlineSuggestionsEnabled() && (!touchExplorationEnabled || imi.supportsInlineSuggestionsWithTouchExploration()); } @GuardedBy("ImfLock.class") void invalidateAutofillSession() { if (mInlineSuggestionsRequestCallback != null) { try { mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated(); } catch (RemoteException e) { Slog.e(TAG, "Cannot invalidate autofill session.", e); } } } /** * The decorator which validates the host package name in the * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. */ private static final class InlineSuggestionsRequestCallbackDecorator extends IInlineSuggestionsRequestCallback.Stub { @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final String mImePackageName; private final int mImeDisplayId; @NonNull private final IBinder mImeToken; @NonNull private final InputMethodManagerService mImms; InlineSuggestionsRequestCallbackDecorator( @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName, int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) { mCallback = callback; mImePackageName = imePackageName; mImeDisplayId = displayId; mImeToken = imeToken; mImms = imms; } @Override public void onInlineSuggestionsUnsupported() throws RemoteException { mCallback.onInlineSuggestionsUnsupported(); } @Override public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, IInlineSuggestionsResponseCallback callback) throws RemoteException { if (!mImePackageName.equals(request.getHostPackageName())) { throw new SecurityException( "Host package name in the provide request=[" + request.getHostPackageName() + "] doesn't match the IME package name=[" + mImePackageName + "]."); } request.setHostDisplayId(mImeDisplayId); mImms.setCurHostInputToken(mImeToken, request.getHostInputToken()); mCallback.onInlineSuggestionsRequest(request, callback); } @Override public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { mCallback.onInputMethodStartInput(imeFieldId); } @Override public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { mCallback.onInputMethodShowInputRequested(requestResult); } @Override public void onInputMethodStartInputView() throws RemoteException { mCallback.onInputMethodStartInputView(); } @Override public void onInputMethodFinishInputView() throws RemoteException { mCallback.onInputMethodFinishInputView(); } @Override public void onInputMethodFinishInput() throws RemoteException { mCallback.onInputMethodFinishInput(); } @Override public void onInlineSuggestionsSessionInvalidated() throws RemoteException { mCallback.onInlineSuggestionsSessionInvalidated(); } } } services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -77,7 +77,7 @@ final class InputMethodBindingController { @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent; @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent; @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") private IBinder mCurToken; @GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private boolean mVisibleBound; @GuardedBy("ImfLock.class") private boolean mVisibleBound; private boolean mSupportsStylusHw; private boolean mSupportsStylusHw; Loading Loading @@ -173,6 +173,7 @@ final class InputMethodBindingController { * identify it in the future. * identify it in the future. */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") @Nullable IBinder getCurToken() { IBinder getCurToken() { return mCurToken; return mCurToken; } } Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +9 −188 Original line number Original line Diff line number Diff line Loading @@ -134,9 +134,7 @@ import android.view.WindowManager.DisplayImePolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager; import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethod; Loading @@ -157,7 +155,6 @@ import com.android.internal.infra.AndroidFuture; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.IAccessibilityInputMethodSession; import com.android.internal.inputmethod.IAccessibilityInputMethodSession; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodClient; import com.android.internal.inputmethod.IInputMethodClient; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; Loading Loading @@ -282,39 +279,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @NonNull @NonNull private final Set<String> mNonPreemptibleInputMethods; private final Set<String> mNonPreemptibleInputMethods; private static final class CreateInlineSuggestionsRequest { @NonNull final InlineSuggestionsRequestInfo mRequestInfo; @NonNull final IInlineSuggestionsRequestCallback mCallback; @NonNull final String mPackageName; CreateInlineSuggestionsRequest( @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String packageName) { mRequestInfo = requestInfo; mCallback = callback; mPackageName = packageName; } } /** * If a request to create inline autofill suggestions comes in while the IME is unbound * due to {@link #mPreventImeStartupUnlessTextEditor}, this is where it is stored, so * that it may be fulfilled once the IME rebinds. */ @GuardedBy("ImfLock.class") @Nullable private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest; /** * A callback into the autofill service obtained from the latest call to * {@link #onCreateInlineSuggestionsRequestLocked}, which can be used to invalidate an * autofill session in case the IME process dies. */ @GuardedBy("ImfLock.class") @Nullable private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback; @UserIdInt @UserIdInt private int mLastSwitchUserId; private int mLastSwitchUserId; Loading @@ -338,7 +302,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub private final UserManager mUserManager; private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final UserManagerInternal mUserManagerInternal; private final InputMethodMenuController mMenuController; private final InputMethodMenuController mMenuController; private final InputMethodBindingController mBindingController; @NonNull private final InputMethodBindingController mBindingController; @NonNull private final AutofillSuggestionsController mAutofillController; // TODO(b/219056452): Use AccessibilityManagerInternal instead. // TODO(b/219056452): Use AccessibilityManagerInternal instead. private final AccessibilityManager mAccessibilityManager; private final AccessibilityManager mAccessibilityManager; Loading Loading @@ -717,7 +682,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * identify it in the future. * identify it in the future. */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") private IBinder getCurTokenLocked() { @Nullable IBinder getCurTokenLocked() { return mBindingController.getCurToken(); return mBindingController.getCurToken(); } } Loading Loading @@ -758,7 +724,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") @Nullable @Nullable private IInputMethodInvoker getCurMethodLocked() { IInputMethodInvoker getCurMethodLocked() { return mBindingController.getCurMethod(); return mBindingController.getCurMethod(); } } Loading Loading @@ -1794,6 +1760,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mSettings, context); mSettings, context); mMenuController = new InputMethodMenuController(this); mMenuController = new InputMethodMenuController(this); mBindingController = new InputMethodBindingController(this); mBindingController = new InputMethodBindingController(this); mAutofillController = new AutofillSuggestionsController(this); mPreventImeStartupUnlessTextEditor = mRes.getBoolean( mPreventImeStartupUnlessTextEditor = mRes.getBoolean( com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray( mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray( Loading Loading @@ -2178,149 +2145,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return settings.getEnabledInputMethodListLocked(); return settings.getEnabledInputMethodListLocked(); } } @GuardedBy("ImfLock.class") private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) { clearPendingInlineSuggestionsRequestLocked(); mInlineSuggestionsRequestCallback = callback; final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked()); try { if (userId == mSettings.getCurrentUserId() && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) { mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest( requestInfo, callback, imi.getPackageName()); if (getCurMethodLocked() != null) { // In the normal case when the IME is connected, we can make the request here. performOnCreateInlineSuggestionsRequestLocked(); } else { // Otherwise, the next time the IME connection is established, // InputMethodBindingController.mMainConnection#onServiceConnected() will call // into #performOnCreateInlineSuggestionsRequestLocked() to make the request. if (DEBUG) { Slog.d(TAG, "IME not connected. Delaying inline suggestions request."); } } } else { callback.onInlineSuggestionsUnsupported(); } } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e); } } @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") void performOnCreateInlineSuggestionsRequestLocked() { void performOnCreateInlineSuggestionsRequestLocked() { if (mPendingInlineSuggestionsRequest == null) { mAutofillController.performOnCreateInlineSuggestionsRequest(); return; } IInputMethodInvoker curMethod = getCurMethodLocked(); if (DEBUG) { Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod); } if (curMethod != null) { final IInlineSuggestionsRequestCallback callback = new InlineSuggestionsRequestCallbackDecorator( mPendingInlineSuggestionsRequest.mCallback, mPendingInlineSuggestionsRequest.mPackageName, mCurTokenDisplayId, getCurTokenLocked(), this); curMethod.onCreateInlineSuggestionsRequest( mPendingInlineSuggestionsRequest.mRequestInfo, callback); } else { Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request."); } clearPendingInlineSuggestionsRequestLocked(); } @GuardedBy("ImfLock.class") private void clearPendingInlineSuggestionsRequestLocked() { mPendingInlineSuggestionsRequest = null; } private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi, boolean touchExplorationEnabled) { return imi.isInlineSuggestionsEnabled() && (!touchExplorationEnabled || imi.supportsInlineSuggestionsWithTouchExploration()); } /** * The decorator which validates the host package name in the * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. */ private static final class InlineSuggestionsRequestCallbackDecorator extends IInlineSuggestionsRequestCallback.Stub { @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final String mImePackageName; private final int mImeDisplayId; @NonNull private final IBinder mImeToken; @NonNull private final InputMethodManagerService mImms; InlineSuggestionsRequestCallbackDecorator( @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName, int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) { mCallback = callback; mImePackageName = imePackageName; mImeDisplayId = displayId; mImeToken = imeToken; mImms = imms; } @Override public void onInlineSuggestionsUnsupported() throws RemoteException { mCallback.onInlineSuggestionsUnsupported(); } @Override public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, IInlineSuggestionsResponseCallback callback) throws RemoteException { if (!mImePackageName.equals(request.getHostPackageName())) { throw new SecurityException( "Host package name in the provide request=[" + request.getHostPackageName() + "] doesn't match the IME package name=[" + mImePackageName + "]."); } request.setHostDisplayId(mImeDisplayId); mImms.setCurHostInputToken(mImeToken, request.getHostInputToken()); mCallback.onInlineSuggestionsRequest(request, callback); } @Override public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { mCallback.onInputMethodStartInput(imeFieldId); } @Override public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { mCallback.onInputMethodShowInputRequested(requestResult); } @Override public void onInputMethodStartInputView() throws RemoteException { mCallback.onInputMethodStartInputView(); } @Override public void onInputMethodFinishInputView() throws RemoteException { mCallback.onInputMethodFinishInputView(); } @Override public void onInputMethodFinishInput() throws RemoteException { mCallback.onInputMethodFinishInput(); } @Override public void onInlineSuggestionsSessionInvalidated() throws RemoteException { mCallback.onInlineSuggestionsSessionInvalidated(); } } } /** /** Loading Loading @@ -2794,13 +2621,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") void invalidateAutofillSessionLocked() { void invalidateAutofillSessionLocked() { if (mInlineSuggestionsRequestCallback != null) { mAutofillController.invalidateAutofillSession(); try { mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated(); } catch (RemoteException e) { Slog.e(TAG, "Cannot invalidate autofill session.", e); } } } } @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") Loading Loading @@ -5511,7 +5332,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); synchronized (ImfLock.class) { synchronized (ImfLock.class) { onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb, mAutofillController.onCreateInlineSuggestionsRequest(userId, requestInfo, cb, touchExplorationEnabled); touchExplorationEnabled); } } } } Loading Loading
services/core/java/com/android/server/inputmethod/AutofillSuggestionsController.java 0 → 100644 +236 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputMethodInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback; import com.android.internal.inputmethod.InlineSuggestionsRequestInfo; /** * A controller managing autofill suggestion requests. */ final class AutofillSuggestionsController { private static final boolean DEBUG = false; private static final String TAG = AutofillSuggestionsController.class.getSimpleName(); @NonNull private final InputMethodManagerService mService; @NonNull private final ArrayMap<String, InputMethodInfo> mMethodMap; @NonNull private final InputMethodUtils.InputMethodSettings mSettings; private static final class CreateInlineSuggestionsRequest { @NonNull final InlineSuggestionsRequestInfo mRequestInfo; @NonNull final IInlineSuggestionsRequestCallback mCallback; @NonNull final String mPackageName; CreateInlineSuggestionsRequest( @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String packageName) { mRequestInfo = requestInfo; mCallback = callback; mPackageName = packageName; } } /** * If a request to create inline autofill suggestions comes in while the IME is unbound * due to {@link InputMethodManagerService#mPreventImeStartupUnlessTextEditor}, * this is where it is stored, so that it may be fulfilled once the IME rebinds. */ @GuardedBy("ImfLock.class") @Nullable private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest; /** * A callback into the autofill service obtained from the latest call to * {@link #onCreateInlineSuggestionsRequest}, which can be used to invalidate an * autofill session in case the IME process dies. */ @GuardedBy("ImfLock.class") @Nullable private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback; AutofillSuggestionsController(@NonNull InputMethodManagerService service) { mService = service; mMethodMap = mService.mMethodMap; mSettings = mService.mSettings; } @GuardedBy("ImfLock.class") void onCreateInlineSuggestionsRequest(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) { clearPendingInlineSuggestionsRequest(); mInlineSuggestionsRequestCallback = callback; final InputMethodInfo imi = mMethodMap.get(mService.getSelectedMethodIdLocked()); try { if (userId == mSettings.getCurrentUserId() && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) { mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest( requestInfo, callback, imi.getPackageName()); if (mService.getCurMethodLocked() != null) { // In the normal case when the IME is connected, we can make the request here. performOnCreateInlineSuggestionsRequest(); } else { // Otherwise, the next time the IME connection is established, // InputMethodBindingController.mMainConnection#onServiceConnected() will call // into #performOnCreateInlineSuggestionsRequestLocked() to make the request. if (DEBUG) { Slog.d(TAG, "IME not connected. Delaying inline suggestions request."); } } } else { callback.onInlineSuggestionsUnsupported(); } } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e); } } @GuardedBy("ImfLock.class") void performOnCreateInlineSuggestionsRequest() { if (mPendingInlineSuggestionsRequest == null) { return; } IInputMethodInvoker curMethod = mService.getCurMethodLocked(); if (DEBUG) { Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod); } if (curMethod != null) { final IInlineSuggestionsRequestCallback callback = new InlineSuggestionsRequestCallbackDecorator( mPendingInlineSuggestionsRequest.mCallback, mPendingInlineSuggestionsRequest.mPackageName, mService.getCurTokenDisplayIdLocked(), mService.getCurTokenLocked(), mService); curMethod.onCreateInlineSuggestionsRequest( mPendingInlineSuggestionsRequest.mRequestInfo, callback); } else { Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request."); } clearPendingInlineSuggestionsRequest(); } @GuardedBy("ImfLock.class") private void clearPendingInlineSuggestionsRequest() { mPendingInlineSuggestionsRequest = null; } private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi, boolean touchExplorationEnabled) { return imi.isInlineSuggestionsEnabled() && (!touchExplorationEnabled || imi.supportsInlineSuggestionsWithTouchExploration()); } @GuardedBy("ImfLock.class") void invalidateAutofillSession() { if (mInlineSuggestionsRequestCallback != null) { try { mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated(); } catch (RemoteException e) { Slog.e(TAG, "Cannot invalidate autofill session.", e); } } } /** * The decorator which validates the host package name in the * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. */ private static final class InlineSuggestionsRequestCallbackDecorator extends IInlineSuggestionsRequestCallback.Stub { @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final String mImePackageName; private final int mImeDisplayId; @NonNull private final IBinder mImeToken; @NonNull private final InputMethodManagerService mImms; InlineSuggestionsRequestCallbackDecorator( @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName, int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) { mCallback = callback; mImePackageName = imePackageName; mImeDisplayId = displayId; mImeToken = imeToken; mImms = imms; } @Override public void onInlineSuggestionsUnsupported() throws RemoteException { mCallback.onInlineSuggestionsUnsupported(); } @Override public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, IInlineSuggestionsResponseCallback callback) throws RemoteException { if (!mImePackageName.equals(request.getHostPackageName())) { throw new SecurityException( "Host package name in the provide request=[" + request.getHostPackageName() + "] doesn't match the IME package name=[" + mImePackageName + "]."); } request.setHostDisplayId(mImeDisplayId); mImms.setCurHostInputToken(mImeToken, request.getHostInputToken()); mCallback.onInlineSuggestionsRequest(request, callback); } @Override public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { mCallback.onInputMethodStartInput(imeFieldId); } @Override public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { mCallback.onInputMethodShowInputRequested(requestResult); } @Override public void onInputMethodStartInputView() throws RemoteException { mCallback.onInputMethodStartInputView(); } @Override public void onInputMethodFinishInputView() throws RemoteException { mCallback.onInputMethodFinishInputView(); } @Override public void onInputMethodFinishInput() throws RemoteException { mCallback.onInputMethodFinishInput(); } @Override public void onInlineSuggestionsSessionInvalidated() throws RemoteException { mCallback.onInlineSuggestionsSessionInvalidated(); } } }
services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -77,7 +77,7 @@ final class InputMethodBindingController { @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent; @GuardedBy("ImfLock.class") @Nullable private Intent mCurIntent; @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") private IBinder mCurToken; @GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private boolean mVisibleBound; @GuardedBy("ImfLock.class") private boolean mVisibleBound; private boolean mSupportsStylusHw; private boolean mSupportsStylusHw; Loading Loading @@ -173,6 +173,7 @@ final class InputMethodBindingController { * identify it in the future. * identify it in the future. */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") @Nullable IBinder getCurToken() { IBinder getCurToken() { return mCurToken; return mCurToken; } } Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +9 −188 Original line number Original line Diff line number Diff line Loading @@ -134,9 +134,7 @@ import android.view.WindowManager.DisplayImePolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager; import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethod; Loading @@ -157,7 +155,6 @@ import com.android.internal.infra.AndroidFuture; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.IAccessibilityInputMethodSession; import com.android.internal.inputmethod.IAccessibilityInputMethodSession; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback; import com.android.internal.inputmethod.IInlineSuggestionsResponseCallback; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodClient; import com.android.internal.inputmethod.IInputMethodClient; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; Loading Loading @@ -282,39 +279,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @NonNull @NonNull private final Set<String> mNonPreemptibleInputMethods; private final Set<String> mNonPreemptibleInputMethods; private static final class CreateInlineSuggestionsRequest { @NonNull final InlineSuggestionsRequestInfo mRequestInfo; @NonNull final IInlineSuggestionsRequestCallback mCallback; @NonNull final String mPackageName; CreateInlineSuggestionsRequest( @NonNull InlineSuggestionsRequestInfo requestInfo, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String packageName) { mRequestInfo = requestInfo; mCallback = callback; mPackageName = packageName; } } /** * If a request to create inline autofill suggestions comes in while the IME is unbound * due to {@link #mPreventImeStartupUnlessTextEditor}, this is where it is stored, so * that it may be fulfilled once the IME rebinds. */ @GuardedBy("ImfLock.class") @Nullable private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest; /** * A callback into the autofill service obtained from the latest call to * {@link #onCreateInlineSuggestionsRequestLocked}, which can be used to invalidate an * autofill session in case the IME process dies. */ @GuardedBy("ImfLock.class") @Nullable private IInlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback; @UserIdInt @UserIdInt private int mLastSwitchUserId; private int mLastSwitchUserId; Loading @@ -338,7 +302,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub private final UserManager mUserManager; private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; private final UserManagerInternal mUserManagerInternal; private final InputMethodMenuController mMenuController; private final InputMethodMenuController mMenuController; private final InputMethodBindingController mBindingController; @NonNull private final InputMethodBindingController mBindingController; @NonNull private final AutofillSuggestionsController mAutofillController; // TODO(b/219056452): Use AccessibilityManagerInternal instead. // TODO(b/219056452): Use AccessibilityManagerInternal instead. private final AccessibilityManager mAccessibilityManager; private final AccessibilityManager mAccessibilityManager; Loading Loading @@ -717,7 +682,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * identify it in the future. * identify it in the future. */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") private IBinder getCurTokenLocked() { @Nullable IBinder getCurTokenLocked() { return mBindingController.getCurToken(); return mBindingController.getCurToken(); } } Loading Loading @@ -758,7 +724,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ */ @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") @Nullable @Nullable private IInputMethodInvoker getCurMethodLocked() { IInputMethodInvoker getCurMethodLocked() { return mBindingController.getCurMethod(); return mBindingController.getCurMethod(); } } Loading Loading @@ -1794,6 +1760,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mSettings, context); mSettings, context); mMenuController = new InputMethodMenuController(this); mMenuController = new InputMethodMenuController(this); mBindingController = new InputMethodBindingController(this); mBindingController = new InputMethodBindingController(this); mAutofillController = new AutofillSuggestionsController(this); mPreventImeStartupUnlessTextEditor = mRes.getBoolean( mPreventImeStartupUnlessTextEditor = mRes.getBoolean( com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray( mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray( Loading Loading @@ -2178,149 +2145,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return settings.getEnabledInputMethodListLocked(); return settings.getEnabledInputMethodListLocked(); } } @GuardedBy("ImfLock.class") private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback, boolean touchExplorationEnabled) { clearPendingInlineSuggestionsRequestLocked(); mInlineSuggestionsRequestCallback = callback; final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked()); try { if (userId == mSettings.getCurrentUserId() && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) { mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest( requestInfo, callback, imi.getPackageName()); if (getCurMethodLocked() != null) { // In the normal case when the IME is connected, we can make the request here. performOnCreateInlineSuggestionsRequestLocked(); } else { // Otherwise, the next time the IME connection is established, // InputMethodBindingController.mMainConnection#onServiceConnected() will call // into #performOnCreateInlineSuggestionsRequestLocked() to make the request. if (DEBUG) { Slog.d(TAG, "IME not connected. Delaying inline suggestions request."); } } } else { callback.onInlineSuggestionsUnsupported(); } } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e); } } @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") void performOnCreateInlineSuggestionsRequestLocked() { void performOnCreateInlineSuggestionsRequestLocked() { if (mPendingInlineSuggestionsRequest == null) { mAutofillController.performOnCreateInlineSuggestionsRequest(); return; } IInputMethodInvoker curMethod = getCurMethodLocked(); if (DEBUG) { Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod); } if (curMethod != null) { final IInlineSuggestionsRequestCallback callback = new InlineSuggestionsRequestCallbackDecorator( mPendingInlineSuggestionsRequest.mCallback, mPendingInlineSuggestionsRequest.mPackageName, mCurTokenDisplayId, getCurTokenLocked(), this); curMethod.onCreateInlineSuggestionsRequest( mPendingInlineSuggestionsRequest.mRequestInfo, callback); } else { Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request."); } clearPendingInlineSuggestionsRequestLocked(); } @GuardedBy("ImfLock.class") private void clearPendingInlineSuggestionsRequestLocked() { mPendingInlineSuggestionsRequest = null; } private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi, boolean touchExplorationEnabled) { return imi.isInlineSuggestionsEnabled() && (!touchExplorationEnabled || imi.supportsInlineSuggestionsWithTouchExploration()); } /** * The decorator which validates the host package name in the * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. */ private static final class InlineSuggestionsRequestCallbackDecorator extends IInlineSuggestionsRequestCallback.Stub { @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final String mImePackageName; private final int mImeDisplayId; @NonNull private final IBinder mImeToken; @NonNull private final InputMethodManagerService mImms; InlineSuggestionsRequestCallbackDecorator( @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName, int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) { mCallback = callback; mImePackageName = imePackageName; mImeDisplayId = displayId; mImeToken = imeToken; mImms = imms; } @Override public void onInlineSuggestionsUnsupported() throws RemoteException { mCallback.onInlineSuggestionsUnsupported(); } @Override public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, IInlineSuggestionsResponseCallback callback) throws RemoteException { if (!mImePackageName.equals(request.getHostPackageName())) { throw new SecurityException( "Host package name in the provide request=[" + request.getHostPackageName() + "] doesn't match the IME package name=[" + mImePackageName + "]."); } request.setHostDisplayId(mImeDisplayId); mImms.setCurHostInputToken(mImeToken, request.getHostInputToken()); mCallback.onInlineSuggestionsRequest(request, callback); } @Override public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { mCallback.onInputMethodStartInput(imeFieldId); } @Override public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { mCallback.onInputMethodShowInputRequested(requestResult); } @Override public void onInputMethodStartInputView() throws RemoteException { mCallback.onInputMethodStartInputView(); } @Override public void onInputMethodFinishInputView() throws RemoteException { mCallback.onInputMethodFinishInputView(); } @Override public void onInputMethodFinishInput() throws RemoteException { mCallback.onInputMethodFinishInput(); } @Override public void onInlineSuggestionsSessionInvalidated() throws RemoteException { mCallback.onInlineSuggestionsSessionInvalidated(); } } } /** /** Loading Loading @@ -2794,13 +2621,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") void invalidateAutofillSessionLocked() { void invalidateAutofillSessionLocked() { if (mInlineSuggestionsRequestCallback != null) { mAutofillController.invalidateAutofillSession(); try { mInlineSuggestionsRequestCallback.onInlineSuggestionsSessionInvalidated(); } catch (RemoteException e) { Slog.e(TAG, "Cannot invalidate autofill session.", e); } } } } @GuardedBy("ImfLock.class") @GuardedBy("ImfLock.class") Loading Loading @@ -5511,7 +5332,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); synchronized (ImfLock.class) { synchronized (ImfLock.class) { onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb, mAutofillController.onCreateInlineSuggestionsRequest(userId, requestInfo, cb, touchExplorationEnabled); touchExplorationEnabled); } } } } Loading