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

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

package org.robolectric.shadows;

import android.view.ViewGroup.LayoutParams;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.fakes.RoboWebSettings;
import org.robolectric.util.ReflectionHelpers;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Shadow for {@link android.webkit.WebView}.
 */
@SuppressWarnings({"UnusedDeclaration"})
@Implements(value = WebView.class, inheritImplementationMethods = true)
public class ShadowWebView extends ShadowAbsoluteLayout {
  @RealObject
  private WebView realWebView;
  
  private String lastUrl;
  private Map lastAdditionalHttpHeaders;
  private HashMap javascriptInterfaces = new HashMap<>();
  private WebSettings webSettings = new RoboWebSettings();
  private WebViewClient webViewClient = null;
  private boolean runFlag = false;
  private boolean clearCacheCalled = false;
  private boolean clearCacheIncludeDiskFiles = false;
  private boolean clearFormDataCalled = false;
  private boolean clearHistoryCalled = false;
  private boolean clearViewCalled = false;
  private boolean destroyCalled = false;
  private boolean onPauseCalled = false;
  private boolean onResumeCalled = false;
  private WebChromeClient webChromeClient;
  private boolean canGoBack;
  private int goBackInvocations = 0;
  private LoadData lastLoadData;
  private LoadDataWithBaseURL lastLoadDataWithBaseURL;

  @HiddenApi @Implementation
  public void ensureProviderCreated() {
    final ClassLoader classLoader = getClass().getClassLoader();
    Class webViewProviderClass = getClassNamed("android.webkit.WebViewProvider");
    Field mProvider;
    try {
      mProvider = WebView.class.getDeclaredField("mProvider");
      mProvider.setAccessible(true);
      if (mProvider.get(realView) == null) {
        Object provider = Proxy.newProxyInstance(classLoader, new Class[]{webViewProviderClass}, new InvocationHandler() {
          @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("getViewDelegate") || method.getName().equals("getScrollDelegate")) {
              return Proxy.newProxyInstance(classLoader, new Class[]{
                  getClassNamed("android.webkit.WebViewProvider$ViewDelegate"),
                  getClassNamed("android.webkit.WebViewProvider$ScrollDelegate")
              }, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  return nullish(method);
                }
              });
            }

            return nullish(method);
          }
        });
        mProvider.set(realView, provider);
      }
    } catch (NoSuchFieldException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

  @Implementation
  public void setLayoutParams(LayoutParams params) {
    ReflectionHelpers.setField(realWebView, "mLayoutParams", params);
  }

  private Object nullish(Method method) {
    Class returnType = method.getReturnType();
    if (returnType.equals(long.class)
        || returnType.equals(double.class)
        || returnType.equals(int.class)
        || returnType.equals(float.class)
        || returnType.equals(short.class)
        || returnType.equals(byte.class)
        ) return 0;
    if (returnType.equals(char.class)) return '\0';
    if (returnType.equals(boolean.class)) return false;
    return null;
  }

  private Class getClassNamed(String className) {
    try {
      return getClass().getClassLoader().loadClass(className);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    }
  }

  @Implementation
  public void loadUrl(String url) {
    loadUrl(url, null);
  }

  @Implementation
  public void loadUrl(String url, Map additionalHttpHeaders) {
    lastUrl = url;

    if (additionalHttpHeaders != null) {
      this.lastAdditionalHttpHeaders = Collections.unmodifiableMap(additionalHttpHeaders);
    } else {
      this.lastAdditionalHttpHeaders = null;
    }
  }

  @Implementation
  public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
    lastLoadDataWithBaseURL = new LoadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
  }

  @Implementation
  public void loadData(String data, String mimeType, String encoding) {
    lastLoadData = new LoadData(data, mimeType, encoding);
  }

  /**
   * Non-Android accessor.
   *
   * @return the last loaded url
   */
  public String getLastLoadedUrl() {
    return lastUrl;
  }

  /**
   * Non-Android accessor.
   *
   * @return the additional Http headers that in the same request with last loaded url
   */
  public Map getLastAdditionalHttpHeaders() {
    return lastAdditionalHttpHeaders;
  }

  @Implementation
  public WebSettings getSettings() {
    return webSettings;
  }

  @Implementation
  public void setWebViewClient(WebViewClient client) {
    webViewClient = client;
  }

  @Implementation
  public void setWebChromeClient(WebChromeClient client) {
    webChromeClient = client;
  }

  public WebViewClient getWebViewClient() {
    return webViewClient;
  }

  @Implementation
  public void addJavascriptInterface(Object obj, String interfaceName) {
    javascriptInterfaces.put(interfaceName, obj);
  }

  public Object getJavascriptInterface(String interfaceName) {
    return javascriptInterfaces.get(interfaceName);
  }

  @Implementation
  public void clearCache(boolean includeDiskFiles) {
    clearCacheCalled = true;
    clearCacheIncludeDiskFiles = includeDiskFiles;
  }

  public boolean wasClearCacheCalled() {
    return clearCacheCalled;
  }

  public boolean didClearCacheIncludeDiskFiles() {
    return clearCacheIncludeDiskFiles;
  }

  @Implementation
  public void clearFormData() {
    clearFormDataCalled = true;
  }

  public boolean wasClearFormDataCalled() {
    return clearFormDataCalled;
  }

  @Implementation
  public void clearHistory() {
    clearHistoryCalled = true;
  }

  public boolean wasClearHistoryCalled() {
    return clearHistoryCalled;
  }

  @Implementation
  public void clearView() {
    clearViewCalled = true;
  }

  public boolean wasClearViewCalled() {
    return clearViewCalled;
  }

  @Implementation
  public void onPause(){
    onPauseCalled = true;
  }

  public boolean wasOnPauseCalled() {
    return onPauseCalled;
  }

  @Implementation
  public void onResume() {
    onResumeCalled = true;
  }

  public boolean wasOnResumeCalled() {
    return onResumeCalled;
  }

  @Implementation
  public void destroy() {
    destroyCalled = true;
  }

  public boolean wasDestroyCalled() {
    return destroyCalled;
  }

  @Implementation
  public void post(Runnable action) {
    action.run();
    runFlag = true;
  }

  public boolean getRunFlag() {
    return runFlag;
  }


  /**
   * Non-Android accessor.
   *
   * @return webChromeClient
   */
  public WebChromeClient getWebChromeClient() {
    return webChromeClient;
  }

  @Implementation
  public boolean canGoBack() {
    return canGoBack;
  }

  @Implementation
  public void goBack() {
    goBackInvocations++;
  }

  @Implementation
  public static String findAddress(String addr) {
    return null;
  }

  /**
   * Non-Android accessor.
   *
   * @return goBackInvocations the number of times {@code android.webkit.WebView#goBack()}
   * was invoked
   */
  public int getGoBackInvocations() {
    return goBackInvocations;
  }

  /**
   * Non-Android setter.
   *
   * Sets the value to return from {@code android.webkit.WebView#canGoBack()}
   *
   * @param canGoBack Value to return from {@code android.webkit.WebView#canGoBack()}
   */
  public void setCanGoBack(boolean canGoBack) {
    this.canGoBack = canGoBack;
  }

  public LoadData getLastLoadData() {
    return lastLoadData;
  }

  public LoadDataWithBaseURL getLastLoadDataWithBaseURL() {
    return lastLoadDataWithBaseURL;
  }

  public static void setWebContentsDebuggingEnabled(boolean enabled) { }

  public class LoadDataWithBaseURL {
    public final String baseUrl;
    public final String data;
    public final String mimeType;
    public final String encoding;
    public final String historyUrl;

    public LoadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
      this.baseUrl = baseUrl;
      this.data = data;
      this.mimeType = mimeType;
      this.encoding = encoding;
      this.historyUrl = historyUrl;
    }
  }

  public class LoadData {
    public final String data;
    public final String mimeType;
    public final String encoding;

    public LoadData(String data, String mimeType, String encoding) {
      this.data = data;
      this.mimeType = mimeType;
      this.encoding = encoding;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy