private void followBlogUrl(String normUrl) {
   ReaderActions.ActionListener followListener =
       new ReaderActions.ActionListener() {
         @Override
         public void onActionResult(boolean succeeded) {
           if (isFinishing()) {
             return;
           }
           hideAddUrlProgress();
           if (succeeded) {
             // clear the edit text and hide the soft keyboard
             mEditAdd.setText(null);
             EditTextUtils.hideSoftInput(mEditAdd);
             showInfoToast(getString(R.string.reader_label_followed_blog));
             getPageAdapter().refreshBlogFragments(ReaderBlogType.FOLLOWED);
           } else {
             ToastUtils.showToast(ReaderSubsActivity.this, R.string.reader_toast_err_follow_blog);
           }
         }
       };
   // note that this uses the endpoint to follow as a feed since typed URLs are more
   // likely to point to a feed than a wp blog (and the endpoint should internally
   // follow it as a blog if it is one)
   ReaderBlogActions.followFeedByUrl(normUrl, true, followListener);
 }
  /*
   * user tapped follow button to follow/unfollow the blog this post is from
   */
  private void togglePostFollowed() {
    if (!isAdded() || !hasPost()) {
      return;
    }

    final boolean isAskingToFollow = !ReaderPostTable.isPostFollowed(mPost);
    final ReaderFollowButton followButton =
        (ReaderFollowButton) getView().findViewById(R.id.follow_button);

    ReaderActions.ActionListener listener =
        new ReaderActions.ActionListener() {
          @Override
          public void onActionResult(boolean succeeded) {
            if (!isAdded()) {
              return;
            }
            followButton.setEnabled(true);
            if (!succeeded) {
              int resId =
                  (isAskingToFollow
                      ? R.string.reader_toast_err_follow_blog
                      : R.string.reader_toast_err_unfollow_blog);
              ToastUtils.showToast(getActivity(), resId);
              followButton.setIsFollowedAnimated(!isAskingToFollow);
            }
          }
        };

    followButton.setEnabled(false);

    if (ReaderBlogActions.followBlogForPost(mPost, isAskingToFollow, listener)) {
      followButton.setIsFollowedAnimated(isAskingToFollow);
    }
  }
  private void changeFollowStatus(
      final TextView txtFollow, final int position, final boolean isAskingToFollow) {
    if (!isPositionValid(position)) {
      return;
    }

    final long blogId;
    final String blogUrl;
    switch (getBlogType()) {
      case RECOMMENDED:
        ReaderRecommendedBlog blog = mRecommendedBlogs.get(position);
        blogId = blog.blogId;
        blogUrl = blog.getBlogUrl();
        break;
      case FOLLOWED:
        ReaderBlog info = mFollowedBlogs.get(position);
        blogId = info.blogId;
        blogUrl = info.getUrl();
        break;
      default:
        return;
    }

    ReaderActions.ActionListener actionListener =
        new ReaderActions.ActionListener() {
          @Override
          public void onActionResult(boolean succeeded) {
            if (!succeeded && getContext() != null) {
              int resId =
                  (isAskingToFollow
                      ? R.string.reader_toast_err_follow_blog
                      : R.string.reader_toast_err_unfollow_blog);
              ToastUtils.showToast(getContext(), resId);
              ReaderUtils.showFollowStatus(txtFollow, !isAskingToFollow);
              checkFollowStatus();
            }
          }
        };
    if (ReaderBlogActions.performFollowAction(blogId, blogUrl, isAskingToFollow, actionListener)) {
      if (getBlogType() == ReaderBlogType.FOLLOWED) {
        mFollowedBlogs.get(position).isFollowing = isAskingToFollow;
      }
      ReaderUtils.showFollowStatus(txtFollow, isAskingToFollow);
      notifyDataSetChanged(); // <-- required for getView() to know correct follow status
      if (mFollowListener != null) {
        mFollowListener.onFollowBlogChanged();
      }
    }
  }
  /*
   * start a two-step process to follow a blog by url:
   *    1. test whether the url is reachable (API will follow any url, even if it doesn't exist)
   *    2. perform the actual follow
   * note that the passed URL is assumed to be normalized and validated
   */
  private void performAddUrl(final String blogUrl) {
    if (!NetworkUtils.checkConnection(this)) {
      return;
    }

    showAddUrlProgress();

    ReaderActions.ActionListener urlActionListener =
        new ReaderActions.ActionListener() {
          @Override
          public void onActionResult(boolean succeeded) {
            if (isFinishing()) {
              return;
            }
            if (succeeded) {
              followBlogUrl(blogUrl);
            } else {
              hideAddUrlProgress();
              ToastUtils.showToast(ReaderSubsActivity.this, R.string.reader_toast_err_follow_blog);
            }
          }
        };
    ReaderBlogActions.checkBlogUrlReachable(blogUrl, urlActionListener);
  }