protected void update(String title, String url, long bookmarkId, boolean hasReaderCacheItem) {
    if (mShowIcons) {
      // The bookmark id will be 0 (null in database) when the url
      // is not a bookmark and negative for 'fake' bookmarks.
      final boolean isBookmark = bookmarkId > 0;

      updateStatusIcon(isBookmark, hasReaderCacheItem);
    } else {
      updateStatusIcon(false, false);
    }

    // Use the URL instead of an empty title for consistency with the normal URL
    // bar view - this is the equivalent of getDisplayTitle() in Tab.java
    setTitle(TextUtils.isEmpty(title) ? url : title);

    // No point updating the below things if URL has not changed. Prevents evil Favicon flicker.
    if (url.equals(mPageUrl)) {
      return;
    }

    // Blank the Favicon, so we don't show the wrong Favicon if we scroll and miss DB.
    mFavicon.clearImage();

    if (mOngoingIconLoad != null) {
      mOngoingIconLoad.cancel(true);
    }

    // Displayed RecentTabsPanel URLs may refer to pages opened in reader mode, so we
    // remove the about:reader prefix to ensure the Favicon loads properly.
    final String pageURL = ReaderModeUtils.stripAboutReaderUrl(url);

    if (bookmarkId < BrowserContract.Bookmarks.FAKE_PARTNER_BOOKMARKS_START) {
      mOngoingIconLoad =
          Icons.with(getContext())
              .pageUrl(pageURL)
              .skipNetwork()
              .privileged(true)
              .icon(
                  IconDescriptor.createGenericIcon(
                      PartnerBookmarksProviderProxy.getUriForIcon(getContext(), bookmarkId)
                          .toString()))
              .build()
              .execute(mFavicon.createIconCallback());
    } else {
      mOngoingIconLoad =
          Icons.with(getContext())
              .pageUrl(pageURL)
              .skipNetwork()
              .build()
              .execute(mFavicon.createIconCallback());
    }

    updateDisplayedUrl(url, hasReaderCacheItem);
  }
  @Override
  protected void configureDialogBuilder(AlertDialog.Builder builder) {
    // Copy the icon from this object to the prompt we produce. We lazily create the drawable,
    // as the user may not ever actually tap this object.
    if (mPromptIcon == null && mIconBitmap != null) {
      mPromptIcon = new BitmapDrawable(getContext().getResources(), mFaviconView.getBitmap());
    }

    builder.setIcon(mPromptIcon);
  }
  /**
   * Configure this Preference object from the Gecko search engine JSON object.
   *
   * @param geckoEngineJSON The Gecko-formatted JSON object representing the search engine.
   * @throws JSONException If the JSONObject is invalid.
   */
  public void setSearchEngineFromJSON(JSONObject geckoEngineJSON) throws JSONException {
    mIdentifier = geckoEngineJSON.getString("identifier");

    // A null JS value gets converted into a string.
    if (mIdentifier.equals("null")) {
      mIdentifier = "other";
    }

    final String engineName = geckoEngineJSON.getString("name");
    final SpannableString titleSpannable = new SpannableString(engineName);

    setTitle(titleSpannable);

    final String iconURI = geckoEngineJSON.getString("iconURI");
    // Keep a reference to the bitmap - we'll need it later in onBindView.
    try {
      final int desiredWidth;
      if (mFaviconView != null) {
        desiredWidth = mFaviconView.getWidth();
      } else {
        // largestFaviconSize is initialized when Favicons is attached to a
        // context, which occurs during GeckoApp.onCreate. That might not
        // ever happen (leaving it at 0), so we fall back.
        if (Favicons.largestFaviconSize == 0) {
          desiredWidth = 128;
        } else {
          desiredWidth = Favicons.largestFaviconSize;
        }
      }

      Favicons.getSizedFavicon(
          getContext(),
          mIdentifier,
          iconURI,
          desiredWidth,
          0,
          new OnFaviconLoadedListener() {
            @Override
            public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) {
              synchronized (bitmapLock) {
                mIconBitmap = favicon;

                if (mFaviconView != null) {
                  mFaviconView.updateAndScaleImage(mIconBitmap, getTitle().toString());
                }
              }
            }
          });
    } catch (IllegalArgumentException e) {
      Log.e(
          LOGTAG, "IllegalArgumentException creating Bitmap. Most likely a zero-length bitmap.", e);
    } catch (NullPointerException e) {
      Log.e(LOGTAG, "NullPointerException creating Bitmap. Most likely a zero-length bitmap.", e);
    }
  }
  /**
   * Called by Android when we're bound to the custom view. Allows us to set the custom properties
   * of our custom view elements as we desire (We can now use findViewById on them).
   *
   * @param view The view instance for this Preference object.
   */
  @Override
  protected void onBindView(View view) {
    super.onBindView(view);

    // We synchronise to avoid a race condition between this and the favicon loading callback in
    // setSearchEngineFromBundle.
    synchronized (bitmapLock) {
      // Set the icon in the FaviconView.
      mFaviconView = ((FaviconView) view.findViewById(R.id.search_engine_icon));

      if (mIconBitmap != null) {
        mFaviconView.updateAndScaleImage(IconResponse.create(mIconBitmap));
      }
    }
  }