Loading core/java/android/inputmethodservice/InlineSuggestionSession.java 0 → 100644 +158 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.inputmethodservice; import static android.inputmethodservice.InputMethodService.DEBUG; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; import android.content.ComponentName; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InlineSuggestionsResponse; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; import java.lang.ref.WeakReference; import java.util.function.Consumer; import java.util.function.Supplier; /** * Maintains an active inline suggestion session. * * <p> * Each session corresponds to one inline suggestion request, but there may be multiple callbacks * with the inline suggestions response. */ class InlineSuggestionSession { private static final String TAG = InlineSuggestionSession.class.getSimpleName(); private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); @NonNull private final ComponentName mComponentName; @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final InlineSuggestionsResponseCallbackImpl mResponseCallback; @NonNull private final Supplier<String> mClientPackageNameSupplier; @NonNull private final Supplier<InlineSuggestionsRequest> mRequestSupplier; @NonNull private final Supplier<IBinder> mHostInputTokenSupplier; @NonNull private final Consumer<InlineSuggestionsResponse> mResponseConsumer; private volatile boolean mInvalidated = false; InlineSuggestionSession(@NonNull ComponentName componentName, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull Supplier<String> clientPackageNameSupplier, @NonNull Supplier<InlineSuggestionsRequest> requestSupplier, @NonNull Supplier<IBinder> hostInputTokenSupplier, @NonNull Consumer<InlineSuggestionsResponse> responseConsumer) { mComponentName = componentName; mCallback = callback; mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this); mClientPackageNameSupplier = clientPackageNameSupplier; mRequestSupplier = requestSupplier; mHostInputTokenSupplier = hostInputTokenSupplier; mResponseConsumer = responseConsumer; makeInlineSuggestionsRequest(); } /** * This needs to be called before creating a new session, such that the later response callbacks * will be discarded. */ void invalidateSession() { mInvalidated = true; } /** * Sends an {@link InlineSuggestionsRequest} obtained from {@cocde supplier} to the current * Autofill Session through * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}. */ private void makeInlineSuggestionsRequest() { try { final InlineSuggestionsRequest request = mRequestSupplier.get(); if (request == null) { if (DEBUG) { Log.d(TAG, "onCreateInlineSuggestionsRequest() returned null request"); } mCallback.onInlineSuggestionsUnsupported(); } else { request.setHostInputToken(mHostInputTokenSupplier.get()); mCallback.onInlineSuggestionsRequest(request, mResponseCallback); } } catch (RemoteException e) { Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e); } } private void handleOnInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) { if (mInvalidated) { if (DEBUG) { Log.d(TAG, "handleOnInlineSuggestionsResponse() called on invalid session"); } return; } // TODO(b/149522488): checking the current focused input field to make sure we don't send // inline responses for previous input field if (!mComponentName.getPackageName().equals(mClientPackageNameSupplier.get())) { if (DEBUG) { Log.d(TAG, "handleOnInlineSuggestionsResponse() called on the wrong package name"); } return; } mResponseConsumer.accept(response); } /** * Internal implementation of {@link IInlineSuggestionsResponseCallback}. */ static final class InlineSuggestionsResponseCallbackImpl extends IInlineSuggestionsResponseCallback.Stub { private final WeakReference<InlineSuggestionSession> mInlineSuggestionSession; private InlineSuggestionsResponseCallbackImpl( InlineSuggestionSession inlineSuggestionSession) { mInlineSuggestionSession = new WeakReference<>(inlineSuggestionSession); } @Override public void onInlineSuggestionsResponse(InlineSuggestionsResponse response) throws RemoteException { final InlineSuggestionSession session = mInlineSuggestionSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( InlineSuggestionSession::handleOnInlineSuggestionsResponse, session, response)); } } } } core/java/android/inputmethodservice/InputMethodService.java +15 −114 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -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; Loading @@ -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()) { Loading Loading @@ -538,7 +531,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb); handleOnCreateInlineSuggestionsRequest(componentName, cb); } /** Loading Loading @@ -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"); Loading @@ -814,24 +776,20 @@ public class InputMethodService extends AbstractInputMethodService { return; } mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, callback); makeInlineSuggestionsRequest(); if (mInlineSuggestionSession != null) { mInlineSuggestionSession.invalidateSession(); } 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"); mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback, this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest, this::getHostInputToken, this::onInlineSuggestionsResponse); } return; @Nullable private String getEditorInfoPackageName() { if (mInputEditorInfo != null) { return mInputEditorInfo.packageName; } onInlineSuggestionsResponse(response); return null; } /** Loading Loading @@ -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<InputMethodService> 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 Loading Loading
core/java/android/inputmethodservice/InlineSuggestionSession.java 0 → 100644 +158 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.inputmethodservice; import static android.inputmethodservice.InputMethodService.DEBUG; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; import android.content.ComponentName; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InlineSuggestionsResponse; import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; import java.lang.ref.WeakReference; import java.util.function.Consumer; import java.util.function.Supplier; /** * Maintains an active inline suggestion session. * * <p> * Each session corresponds to one inline suggestion request, but there may be multiple callbacks * with the inline suggestions response. */ class InlineSuggestionSession { private static final String TAG = InlineSuggestionSession.class.getSimpleName(); private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); @NonNull private final ComponentName mComponentName; @NonNull private final IInlineSuggestionsRequestCallback mCallback; @NonNull private final InlineSuggestionsResponseCallbackImpl mResponseCallback; @NonNull private final Supplier<String> mClientPackageNameSupplier; @NonNull private final Supplier<InlineSuggestionsRequest> mRequestSupplier; @NonNull private final Supplier<IBinder> mHostInputTokenSupplier; @NonNull private final Consumer<InlineSuggestionsResponse> mResponseConsumer; private volatile boolean mInvalidated = false; InlineSuggestionSession(@NonNull ComponentName componentName, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull Supplier<String> clientPackageNameSupplier, @NonNull Supplier<InlineSuggestionsRequest> requestSupplier, @NonNull Supplier<IBinder> hostInputTokenSupplier, @NonNull Consumer<InlineSuggestionsResponse> responseConsumer) { mComponentName = componentName; mCallback = callback; mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this); mClientPackageNameSupplier = clientPackageNameSupplier; mRequestSupplier = requestSupplier; mHostInputTokenSupplier = hostInputTokenSupplier; mResponseConsumer = responseConsumer; makeInlineSuggestionsRequest(); } /** * This needs to be called before creating a new session, such that the later response callbacks * will be discarded. */ void invalidateSession() { mInvalidated = true; } /** * Sends an {@link InlineSuggestionsRequest} obtained from {@cocde supplier} to the current * Autofill Session through * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}. */ private void makeInlineSuggestionsRequest() { try { final InlineSuggestionsRequest request = mRequestSupplier.get(); if (request == null) { if (DEBUG) { Log.d(TAG, "onCreateInlineSuggestionsRequest() returned null request"); } mCallback.onInlineSuggestionsUnsupported(); } else { request.setHostInputToken(mHostInputTokenSupplier.get()); mCallback.onInlineSuggestionsRequest(request, mResponseCallback); } } catch (RemoteException e) { Log.w(TAG, "makeInlinedSuggestionsRequest() remote exception:" + e); } } private void handleOnInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) { if (mInvalidated) { if (DEBUG) { Log.d(TAG, "handleOnInlineSuggestionsResponse() called on invalid session"); } return; } // TODO(b/149522488): checking the current focused input field to make sure we don't send // inline responses for previous input field if (!mComponentName.getPackageName().equals(mClientPackageNameSupplier.get())) { if (DEBUG) { Log.d(TAG, "handleOnInlineSuggestionsResponse() called on the wrong package name"); } return; } mResponseConsumer.accept(response); } /** * Internal implementation of {@link IInlineSuggestionsResponseCallback}. */ static final class InlineSuggestionsResponseCallbackImpl extends IInlineSuggestionsResponseCallback.Stub { private final WeakReference<InlineSuggestionSession> mInlineSuggestionSession; private InlineSuggestionsResponseCallbackImpl( InlineSuggestionSession inlineSuggestionSession) { mInlineSuggestionSession = new WeakReference<>(inlineSuggestionSession); } @Override public void onInlineSuggestionsResponse(InlineSuggestionsResponse response) throws RemoteException { final InlineSuggestionSession session = mInlineSuggestionSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( InlineSuggestionSession::handleOnInlineSuggestionsResponse, session, response)); } } } }
core/java/android/inputmethodservice/InputMethodService.java +15 −114 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -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; Loading @@ -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()) { Loading Loading @@ -538,7 +531,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()"); } handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb); handleOnCreateInlineSuggestionsRequest(componentName, cb); } /** Loading Loading @@ -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"); Loading @@ -814,24 +776,20 @@ public class InputMethodService extends AbstractInputMethodService { return; } mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId, callback); makeInlineSuggestionsRequest(); if (mInlineSuggestionSession != null) { mInlineSuggestionSession.invalidateSession(); } 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"); mInlineSuggestionSession = new InlineSuggestionSession(componentName, callback, this::getEditorInfoPackageName, this::onCreateInlineSuggestionsRequest, this::getHostInputToken, this::onInlineSuggestionsResponse); } return; @Nullable private String getEditorInfoPackageName() { if (mInputEditorInfo != null) { return mInputEditorInfo.packageName; } onInlineSuggestionsResponse(response); return null; } /** Loading Loading @@ -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<InputMethodService> 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 Loading