private void showStarred(boolean starred, boolean allowAnimate) {
    mAddScheduleButton.setChecked(starred, allowAnimate);

    mLUtils.setOrAnimatePlusCheckIcon(mAddScheduleButton, starred, allowAnimate);
    mAddScheduleButton.setContentDescription(
        getString(starred ? R.string.remove_from_schedule_desc : R.string.add_to_schedule_desc));
  }
  private void initViewListeners() {
    mAddScheduleButton.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View view) {
            boolean starred = !((CheckableFloatingActionButton) view).isChecked();
            showStarred(starred, true);
            if (starred) {
              sendUserAction(SessionDetailUserActionEnum.STAR, null);
            } else {
              sendUserAction(SessionDetailUserActionEnum.UNSTAR, null);
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              mAddScheduleButton.announceForAccessibility(
                  starred
                      ? getString(R.string.session_details_a11y_session_added)
                      : getString(R.string.session_details_a11y_session_removed));
            }
          }
        });
  }
  private void updateTimeBasedUi(SessionDetailModel data) {
    // Show "Live streamed" for all live-streamed sessions that aren't currently going on.
    mLiveStreamVideocamIconAndText.setVisibility(
        data.hasLiveStream() && !data.isSessionOngoing() ? View.VISIBLE : View.GONE);

    if (data.hasLiveStream() && data.hasSessionStarted()) {
      // Show the play button and text only once the session starts.
      mLiveStreamVideocamIconAndText.setVisibility(View.VISIBLE);

      if (data.isSessionOngoing()) {
        mLiveStreamPlayIconAndText.setText(getString(R.string.session_watch_live));
      } else {
        mLiveStreamPlayIconAndText.setText(getString(R.string.session_watch));
        // TODO: implement Replay.
      }
    } else {
      mLiveStreamPlayIconAndText.setVisibility(View.GONE);
    }

    // If the session is done, hide the FAB, and show the "Give feedback" card.
    if (data.isSessionReadyForFeedback()) {
      mAddScheduleButton.setVisibility(View.INVISIBLE);
      if (!data.hasFeedback()
          && data.isInScheduleWhenSessionFirstLoaded()
          && !sDismissedFeedbackCard.contains(data.getSessionId())) {
        showGiveFeedbackCard(data);
      }
    }

    String timeHint = "";

    if (TimeUtils.hasConferenceEnded(getContext())) {
      // No time hint to display.
      timeHint = "";
    } else if (data.hasSessionEnded()) {
      timeHint = getString(R.string.time_hint_session_ended);
    } else if (data.isSessionOngoing()) {
      long minutesAgo = data.minutesSinceSessionStarted();
      if (minutesAgo > 1) {
        timeHint = getString(R.string.time_hint_started_min, minutesAgo);
      } else {
        timeHint = getString(R.string.time_hint_started_just);
      }
    } else {
      long minutesUntilStart = data.minutesUntilSessionStarts();
      if (minutesUntilStart > 0
          && minutesUntilStart <= SessionDetailConstants.HINT_TIME_BEFORE_SESSION_MIN) {
        if (minutesUntilStart > 1) {
          timeHint = getString(R.string.time_hint_about_to_start_min, minutesUntilStart);
        } else {
          timeHint = getString(R.string.time_hint_about_to_start_shortly, minutesUntilStart);
        }
      }
    }

    final TextView timeHintView = (TextView) getActivity().findViewById(R.id.time_hint);

    if (!TextUtils.isEmpty(timeHint)) {
      timeHintView.setVisibility(View.VISIBLE);
      timeHintView.setText(timeHint);
    } else {
      timeHintView.setVisibility(View.GONE);
    }
  }
  private void displaySessionData(final SessionDetailModel data) {
    mTitle.setText(data.getSessionTitle());
    mSubtitle.setText(data.getSessionSubtitle());

    mPhotoViewContainer.setBackgroundColor(
        UIUtils.scaleSessionColorToDefaultBG(data.getSessionColor()));

    if (data.hasPhotoUrl()) {
      mHasPhoto = true;
      mNoPlaceholderImageLoader.loadImage(
          data.getPhotoUrl(),
          mPhotoView,
          new RequestListener<String, Bitmap>() {
            @Override
            public boolean onException(
                Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
              mHasPhoto = false;
              recomputePhotoAndScrollingMetrics();
              return false;
            }

            @Override
            public boolean onResourceReady(
                Bitmap resource,
                String model,
                Target<Bitmap> target,
                boolean isFromMemoryCache,
                boolean isFirstResource) {
              // Trigger image transition
              recomputePhotoAndScrollingMetrics();
              return false;
            }
          });
      recomputePhotoAndScrollingMetrics();
    } else {
      mHasPhoto = false;
      recomputePhotoAndScrollingMetrics();
    }

    tryExecuteDeferredUiOperations();

    // Handle Keynote as a special case, where the user cannot remove it
    // from the schedule (it is auto added to schedule on sync)
    mAddScheduleButton.setVisibility(
        (AccountUtils.hasActiveAccount(getContext()) && !data.isKeynote())
            ? View.VISIBLE
            : View.INVISIBLE);

    displayTags(data);

    if (!data.isKeynote()) {
      showStarredDeferred(data.isInSchedule(), false);
    }

    if (!TextUtils.isEmpty(data.getSessionAbstract())) {
      UIUtils.setTextMaybeHtml(mAbstract, data.getSessionAbstract());
      mAbstract.setVisibility(View.VISIBLE);
    } else {
      mAbstract.setVisibility(View.GONE);
    }

    // Build requirements section
    final View requirementsBlock = getActivity().findViewById(R.id.session_requirements_block);
    final String sessionRequirements = data.getRequirements();
    if (!TextUtils.isEmpty(sessionRequirements)) {
      UIUtils.setTextMaybeHtml(mRequirements, sessionRequirements);
      requirementsBlock.setVisibility(View.VISIBLE);
    } else {
      requirementsBlock.setVisibility(View.GONE);
    }

    final ViewGroup relatedVideosBlock =
        (ViewGroup) getActivity().findViewById(R.id.related_videos_block);
    relatedVideosBlock.setVisibility(View.GONE);

    updateEmptyView(data);

    updateTimeBasedUi(data);

    if (data.getLiveStreamVideoWatched()) {
      mPhotoView.setColorFilter(getContext().getResources().getColor(R.color.video_scrim_watched));
      mLiveStreamPlayIconAndText.setText(getString(R.string.session_replay));
    }

    if (data.hasLiveStream()) {
      mLiveStreamPlayIconAndText.setOnClickListener(
          new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              String videoId =
                  YouTubeUtils.getVideoIdFromSessionData(
                      data.getYouTubeUrl(), data.getLiveStreamId());
              YouTubeUtils.showYouTubeVideo(videoId, getActivity());
            }
          });
    }

    fireAnalyticsScreenView(data.getSessionTitle());

    mHandler.post(
        new Runnable() {
          @Override
          public void run() {
            onScrollChanged(0, 0); // trigger scroll handling
            mScrollViewChild.setVisibility(View.VISIBLE);
            // mAbstract.setTextIsSelectable(true);
          }
        });

    mTimeHintUpdaterRunnable =
        new Runnable() {
          @Override
          public void run() {
            if (getActivity() == null) {
              // Do not post a delayed message if the activity is detached.
              return;
            }
            updateTimeBasedUi(data);
            mHandler.postDelayed(
                mTimeHintUpdaterRunnable, SessionDetailConstants.TIME_HINT_UPDATE_INTERVAL);
          }
        };
    mHandler.postDelayed(
        mTimeHintUpdaterRunnable, SessionDetailConstants.TIME_HINT_UPDATE_INTERVAL);
  }