All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.shadows.ShadowInputMethodManager Maven / Gradle / Ivy

package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import static android.os.Build.VERSION_CODES.S;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static org.robolectric.util.reflector.Reflector.reflector;

import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.util.SparseArray;
import android.view.View;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import java.util.List;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.ReflectionHelpers.ClassParameter;
import org.robolectric.util.reflector.Accessor;
import org.robolectric.util.reflector.Direct;
import org.robolectric.util.reflector.ForType;
import org.robolectric.util.reflector.Static;

@Implements(value = InputMethodManager.class)
public class ShadowInputMethodManager {

  /**
   * Handler for receiving soft input visibility changed event.
   *
   * 

Since Android does not have any API for retrieving soft input status, most application * relies on GUI layout changes to detect the soft input change event. Currently, Robolectric are * not able to simulate the GUI change when application changes the soft input through {@code * InputMethodManager}, this handler can be used by application to simulate GUI change in response * of the soft input change. */ public interface SoftInputVisibilityChangeHandler { void handleSoftInputVisibilityChange(boolean softInputVisible); } /** Handler for receiving PrivateCommands. */ public interface PrivateCommandListener { void onPrivateCommand(View view, String action, Bundle data); } private boolean softInputVisible; private Optional visibilityChangeHandler = Optional.absent(); private Optional privateCommandListener = Optional.absent(); private List inputMethodInfoList = ImmutableList.of(); private List enabledInputMethodInfoList = ImmutableList.of(); private Optional inputMethodSubtype = Optional.absent(); @Implementation protected boolean showSoftInput(View view, int flags) { return showSoftInput(view, flags, null); } @Implementation(maxSdk = R) protected boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) { setSoftInputVisibility(true); return true; } @Implementation(minSdk = S, maxSdk = TIRAMISU) protected boolean showSoftInput( View view, int flags, ResultReceiver resultReceiver, int ignoredReason) { return showSoftInput(view, flags, resultReceiver); } @Implementation(minSdk = S) protected boolean hideSoftInputFromWindow( IBinder windowToken, int flags, ResultReceiver resultReceiver, int ignoredReason) { return hideSoftInputFromWindow(windowToken, flags, resultReceiver); } @Implementation(maxSdk = R) protected boolean hideSoftInputFromWindow(IBinder windowToken, int flags) { return hideSoftInputFromWindow(windowToken, flags, null); } @Implementation protected boolean hideSoftInputFromWindow( IBinder windowToken, int flags, ResultReceiver resultReceiver) { int resultCode; if (isSoftInputVisible()) { setSoftInputVisibility(false); resultCode = InputMethodManager.RESULT_HIDDEN; } else { resultCode = InputMethodManager.RESULT_UNCHANGED_HIDDEN; } if (resultReceiver != null) { resultReceiver.send(resultCode, null); } return true; } @Implementation protected void toggleSoftInput(int showFlags, int hideFlags) { setSoftInputVisibility(!isSoftInputVisible()); } public boolean isSoftInputVisible() { return softInputVisible; } public void setSoftInputVisibilityHandler( SoftInputVisibilityChangeHandler visibilityChangeHandler) { this.visibilityChangeHandler = Optional.of(visibilityChangeHandler); } private void setSoftInputVisibility(boolean visible) { if (visible == softInputVisible) { return; } softInputVisible = visible; if (visibilityChangeHandler.isPresent()) { visibilityChangeHandler.get().handleSoftInputVisibilityChange(softInputVisible); } } /** * The framework implementation does a blocking call to system server. This will deadlock on * Robolectric, so just stub out the method. */ @Implementation(minSdk = S) protected void closeCurrentInput() {} /** * Returns the list of {@link InputMethodInfo} that are installed. * *

This method differs from Android implementation by allowing the list to be set using {@link * #setInputMethodInfoList(List)}. */ @Implementation protected List getInputMethodList() { return inputMethodInfoList; } /** * Sets the list of {@link InputMethodInfo} that are marked as installed. See {@link * #getInputMethodList()}. */ public void setInputMethodInfoList(List inputMethodInfoList) { this.inputMethodInfoList = inputMethodInfoList; } /** * Returns the {@link InputMethodSubtype} that is installed. * *

This method differs from Android implementation by allowing the list to be set using {@link * #setCurrentInputMethodSubtype(InputMethodSubtype)}. */ @Implementation protected InputMethodSubtype getCurrentInputMethodSubtype() { return inputMethodSubtype.orNull(); } /** * Sets the current {@link InputMethodSubtype} that will be returned by {@link * #getCurrentInputMethodSubtype()}. */ public void setCurrentInputMethodSubtype(InputMethodSubtype inputMethodSubtype) { this.inputMethodSubtype = Optional.of(inputMethodSubtype); } /** * Returns the list of {@link InputMethodInfo} that are enabled. * *

This method differs from Android implementation by allowing the list to be set using {@link * #setEnabledInputMethodInfoList(List)}. */ @Implementation protected List getEnabledInputMethodList() { return enabledInputMethodInfoList; } /** * Sets the list of {@link InputMethodInfo} that are marked as enabled. See {@link * #getEnabledInputMethodList()}. */ public void setEnabledInputMethodInfoList(List inputMethodInfoList) { this.enabledInputMethodInfoList = inputMethodInfoList; } @Implementation protected void restartInput(View view) {} @Implementation protected boolean isActive(View view) { return false; } @Implementation protected boolean isActive() { return false; } @Implementation protected boolean isFullscreenMode() { return false; } @Implementation(maxSdk = Q) protected void focusIn(View view) {} @Implementation(minSdk = M, maxSdk = Q) protected void onViewDetachedFromWindow(View view) {} @Implementation protected void displayCompletions(View view, CompletionInfo[] completions) {} @Implementation(maxSdk = LOLLIPOP_MR1) protected static InputMethodManager peekInstance() { // Android has a bug pre M where peekInstance was dereferenced without a null check:- // https://github.com/aosp-mirror/platform_frameworks_base/commit/a046faaf38ad818e6b5e981a39fd7394cf7cee03 // So for earlier versions, just call through directly to getInstance() if (RuntimeEnvironment.getApiLevel() <= JELLY_BEAN_MR1) { return ReflectionHelpers.callStaticMethod( InputMethodManager.class, "getInstance", ClassParameter.from(Looper.class, Looper.getMainLooper())); } else if (RuntimeEnvironment.getApiLevel() <= LOLLIPOP_MR1) { return InputMethodManager.getInstance(); } return reflector(_InputMethodManager_.class).peekInstance(); } @Implementation(minSdk = N) protected boolean startInputInner( int startInputReason, IBinder windowGainingFocus, int startInputFlags, int softInputMode, int windowFlags) { return true; } @Implementation(minSdk = M) protected void sendAppPrivateCommand(View view, String action, Bundle data) { if (privateCommandListener.isPresent()) { privateCommandListener.get().onPrivateCommand(view, action, data); } } public void setAppPrivateCommandListener(PrivateCommandListener listener) { privateCommandListener = Optional.of(listener); } @Resetter public static void reset() { int apiLevel = RuntimeEnvironment.getApiLevel(); _InputMethodManager_ _reflector = reflector(_InputMethodManager_.class); if (apiLevel <= JELLY_BEAN_MR1) { _reflector.setMInstance(null); } else { _reflector.setInstance(null); } if (apiLevel > P) { _reflector.getInstanceMap().clear(); } } @ForType(InputMethodManager.class) interface _InputMethodManager_ { @Static @Direct InputMethodManager peekInstance(); @Static @Accessor("mInstance") void setMInstance(InputMethodManager instance); @Static @Accessor("sInstance") void setInstance(InputMethodManager instance); @Static @Accessor("sInstanceMap") SparseArray getInstanceMap(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy