private void processCommand(Context context, NotificationCommandModel command) {
    // Check format
    if (!"1.0.00".equals(command.format)) {
      LOGW(TAG, "GCM notification command has unrecognized format: " + command.format);
      return;
    }

    // Check app version
    if (!TextUtils.isEmpty(command.minVersion) || !TextUtils.isEmpty(command.maxVersion)) {
      LOGD(TAG, "Command has version range.");
      int minVersion = 0;
      int maxVersion = Integer.MAX_VALUE;
      try {
        if (!TextUtils.isEmpty(command.minVersion)) {
          minVersion = Integer.parseInt(command.minVersion);
        }
        if (!TextUtils.isEmpty(command.maxVersion)) {
          maxVersion = Integer.parseInt(command.maxVersion);
        }
        LOGD(TAG, "Version range: " + minVersion + " - " + maxVersion);
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        LOGD(TAG, "My version code: " + pinfo.versionCode);
        if (pinfo.versionCode < minVersion) {
          LOGD(
              TAG,
              "Skipping command because our version is too old, "
                  + pinfo.versionCode
                  + " < "
                  + minVersion);
          return;
        }
        if (pinfo.versionCode > maxVersion) {
          LOGD(
              TAG,
              "Skipping command because our version is too new, "
                  + pinfo.versionCode
                  + " > "
                  + maxVersion);
          return;
        }
      } catch (NumberFormatException ex) {
        LOGE(
            TAG,
            "Version spec badly formatted: min="
                + command.minVersion
                + ", max="
                + command.maxVersion);
        return;
      } catch (Exception ex) {
        LOGE(TAG, "Unexpected problem doing version check.", ex);
        return;
      }
    }

    // Check if we are the right audience
    LOGD(TAG, "Checking audience: " + command.audience);
    if ("remote".equals(command.audience)) {
      if (PrefUtils.isAttendeeAtVenue(context)) {
        LOGD(TAG, "Ignoring notification because audience is remote and attendee is on-site");
        return;
      } else {
        LOGD(TAG, "Relevant (attendee is remote).");
      }
    } else if ("local".equals(command.audience)) {
      if (!PrefUtils.isAttendeeAtVenue(context)) {
        LOGD(TAG, "Ignoring notification because audience is on-site and attendee is remote.");
        return;
      } else {
        LOGD(TAG, "Relevant (attendee is local).");
      }
    } else if ("all".equals(command.audience)) {
      LOGD(TAG, "Relevant (audience is 'all').");
    } else {
      LOGE(TAG, "Invalid audience on GCM notification command: " + command.audience);
      return;
    }

    // Check if it expired
    Date expiry = command.expiry == null ? null : TimeUtils.parseTimestamp(command.expiry);
    if (expiry == null) {
      LOGW(TAG, "Failed to parse expiry field of GCM notification command: " + command.expiry);
      return;
    } else if (expiry.getTime() < UIUtils.getCurrentTime(context)) {
      LOGW(TAG, "Got expired GCM notification command. Expiry: " + expiry.toString());
      return;
    } else {
      LOGD(TAG, "Message is still valid (expiry is in the future: " + expiry.toString() + ")");
    }

    // decide the intent that will be fired when the user clicks the notification
    Intent intent;
    if (TextUtils.isEmpty(command.dialogText)) {
      // notification leads directly to the URL, no dialog
      if (TextUtils.isEmpty(command.url)) {
        intent =
            new Intent(context, MyScheduleActivity.class)
                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
      } else {
        intent = new Intent(Intent.ACTION_VIEW, Uri.parse(command.url));
      }
    } else {
      // use a dialog
      intent =
          new Intent(context, MyScheduleActivity.class)
              .setFlags(
                  Intent.FLAG_ACTIVITY_CLEAR_TOP
                      | Intent.FLAG_ACTIVITY_SINGLE_TOP
                      | Intent.FLAG_ACTIVITY_NEW_TASK
                      | Intent.FLAG_ACTIVITY_CLEAR_TASK);
      intent.putExtra(
          MyScheduleActivity.EXTRA_DIALOG_TITLE,
          command.dialogTitle == null ? "" : command.dialogTitle);
      intent.putExtra(
          MyScheduleActivity.EXTRA_DIALOG_MESSAGE,
          command.dialogText == null ? "" : command.dialogText);
      intent.putExtra(
          MyScheduleActivity.EXTRA_DIALOG_YES,
          command.dialogYes == null ? "OK" : command.dialogYes);
      intent.putExtra(
          MyScheduleActivity.EXTRA_DIALOG_NO, command.dialogNo == null ? "" : command.dialogNo);
      intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_URL, command.url == null ? "" : command.url);
    }

    final String title =
        TextUtils.isEmpty(command.title) ? context.getString(R.string.app_name) : command.title;
    final String message = TextUtils.isEmpty(command.message) ? "" : command.message;

    // fire the notification
    ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
        .notify(
            0,
            new NotificationCompat.Builder(context)
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.ic_stat_notification)
                .setTicker(command.message)
                .setContentTitle(title)
                .setContentText(message)
                // .setColor(context.getResources().getColor(R.color.theme_primary))
                // Note: setColor() is available in the support lib v21+.
                // We commented it out because we want the source to compile
                // against support lib v20. If you are using support lib
                // v21 or above on Android L, uncomment this line.
                .setContentIntent(
                    PendingIntent.getActivity(
                        context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT))
                .setAutoCancel(true)
                .build());
  }
  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);
    }
  }