void applyTextZoomPref() {
   if (view != null) {
     view.applyTextZoomPref();
   }
 }
  public ArticleWebView(Context context, AttributeSet attrs) {
    super(context, attrs);

    connectivityManager =
        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

    styleSwitcherJs = Application.jsStyleSwitcher;

    WebSettings settings = this.getSettings();
    settings.setJavaScriptEnabled(true);
    settings.setBuiltInZoomControls(true);
    settings.setDisplayZoomControls(false);

    Resources r = getResources();
    defaultStyleTitle = r.getString(R.string.default_style_title);
    autoStyleTitle = r.getString(R.string.auto_style_title);

    this.addJavascriptInterface(this, "$SLOB");

    timer = new Timer();

    final Runnable applyStyleRunnable =
        new Runnable() {
          @Override
          public void run() {
            applyStylePref();
          }
        };

    applyStylePref =
        new TimerTask() {
          @Override
          public void run() {
            android.os.Handler handler = getHandler();
            if (handler != null) {
              handler.post(applyStyleRunnable);
            }
          }
        };

    this.setWebViewClient(
        new WebViewClient() {

          byte[] noBytes = new byte[0];

          Map<String, List<Long>> times = new HashMap<String, List<Long>>();

          @Override
          public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.d(TAG, "onPageStarted: " + url);
            if (url.startsWith("about:")) {
              return;
            }
            if (times.containsKey(url)) {
              Log.d(TAG, "onPageStarted: already ready seen " + url);
              times.get(url).add(System.currentTimeMillis());
              return;
            } else {
              List<Long> tsList = new ArrayList<Long>();
              tsList.add(System.currentTimeMillis());
              times.put(url, tsList);
              view.loadUrl("javascript:" + styleSwitcherJs);
              try {
                timer.schedule(applyStylePref, 250, 200);
              } catch (IllegalStateException ex) {
                Log.w(TAG, "Failed to schedule applyStylePref in view " + view.getId(), ex);
              }
            }
          }

          @Override
          public void onPageFinished(WebView view, String url) {
            Log.d(TAG, "onPageFinished: " + url);
            if (url.startsWith("about:")) {
              return;
            }
            if (times.containsKey(url)) {
              List<Long> tsList = times.get(url);
              long ts = tsList.remove(tsList.size() - 1);
              Log.d(
                  TAG,
                  "onPageFinished: finished: " + url + " in " + (System.currentTimeMillis() - ts));
              if (tsList.isEmpty()) {
                Log.d(TAG, "onPageFinished: really done with " + url);
                times.remove(url);
                applyStylePref.cancel();
              }
            } else {
              Log.w(TAG, "onPageFinished: Unexpected page finished event for " + url);
            }
            view.loadUrl(
                "javascript:"
                    + styleSwitcherJs
                    + ";$SLOB.setStyleTitles($styleSwitcher.getTitles())");
            applyStylePref();
          }

          @Override
          public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            Uri parsed;
            try {
              parsed = Uri.parse(url);
            } catch (Exception e) {
              Log.d(TAG, "Failed to parse url: " + url, e);
              return super.shouldInterceptRequest(view, url);
            }
            if (parsed.isRelative()) {
              return null;
            }
            String host = parsed.getHost();
            if (host == null || host.toLowerCase().equals(LOCALHOST)) {
              return null;
            }
            if (allowRemoteContent()) {
              return null;
            }
            return new WebResourceResponse(
                "text/plain", "UTF-8", new ByteArrayInputStream(noBytes));
          }

          @Override
          public boolean shouldOverrideUrlLoading(WebView view, final String url) {
            Log.d(
                TAG,
                String.format("shouldOverrideUrlLoading: %s (current %s)", url, view.getUrl()));

            Uri uri = Uri.parse(url);
            String scheme = uri.getScheme();
            String host = uri.getHost();

            if (externalSchemes.contains(scheme)
                || (scheme.equals("http") && !host.equals(LOCALHOST))) {
              Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
              getContext().startActivity(browserIntent);
              return true;
            }

            if (scheme.equals("http")
                && host.equals(LOCALHOST)
                && uri.getQueryParameter("blob") == null) {
              Intent intent = new Intent(getContext(), ArticleCollectionActivity.class);
              intent.setData(uri);
              getContext().startActivity(intent);
              Log.d(TAG, "Overriding loading of " + url);
              return true;
            }
            Log.d(TAG, "NOT overriding loading of " + url);
            return false;
          }
        });

    applyTextZoomPref();
  }