/**
  * Registers an {@link
  * com.google.android.libraries.cast.companionlibrary.cast.callbacks.DataCastConsumer} interface
  * with this class. Registered listeners will be notified of changes to a variety of lifecycle and
  * status changes through the callbacks that the interface provides.
  */
 public void addDataCastConsumer(DataCastConsumer listener) {
   if (listener != null) {
     addBaseCastConsumer(listener);
     boolean result;
     result = mDataConsumers.add(listener);
     if (result) {
       LOGD(TAG, "Successfully added the new DataCastConsumer listener " + listener);
     } else {
       LOGD(
           TAG,
           "Adding Listener " + listener + " was already registered, " + "skipping this step");
     }
   }
 }
  @Override
  public void onApplicationConnected(
      WebAppSession webAppSession, WebAppSession.WebAppStatus status) {
    LOGD(
        TAG,
        "onApplicationConnected() reached with sessionId: "
            + webAppSession.launchSession.getSessionId());

    // saving session for future retrieval; we only save the last session info
    mPreferenceAccessor.saveStringToPreference(
        PREFS_KEY_SESSION_ID, webAppSession.launchSession.getSessionId());
    if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) {
      // we have tried to reconnect and successfully launched the app, so
      // it is time to select the route and make the cast icon happy :-)
      List<RouteInfo> routes = mMediaRouter.getRoutes();
      if (routes != null) {
        String routeId = mPreferenceAccessor.getStringFromPreference(PREFS_KEY_ROUTE_ID);
        boolean found = false;
        for (RouteInfo routeInfo : routes) {
          if (routeId.equals(routeInfo.getId())) {
            // found the right route
            LOGD(TAG, "Found the correct route during reconnection attempt");
            found = true;
            mReconnectionStatus = RECONNECTION_STATUS_FINALIZED;
            mMediaRouter.selectRoute(routeInfo);
            break;
          }
        }
        if (!found) {
          // we were hoping to have the route that we wanted, but we
          // didn't so we deselect the device
          onDeviceSelected(null);
          mReconnectionStatus = RECONNECTION_STATUS_INACTIVE;
          return;
        }
      }
    }
    // registering namespaces, if any
    try {
      attachDataChannels();
      mSessionId = webAppSession.launchSession.getSessionId();
      for (DataCastConsumer consumer : mDataConsumers) {
        consumer.onApplicationConnected(webAppSession, status);
      }
    } catch (IllegalStateException | IOException e) {
      LOGE(TAG, "Failed to attach namespaces", e);
    }
  }
 protected DataCastManager(Context context, String applicationId, String... namespaces) {
   super(context, applicationId);
   if (namespaces != null) {
     for (String namespace : namespaces) {
       if (!TextUtils.isEmpty(namespace)) {
         mNamespaceList.add(namespace);
       } else {
         LOGD(TAG, "A null or empty namespace was ignored.");
       }
     }
   }
 }
 /**
  * Initializes the DataCastManager for clients. Before clients can use DataCastManager, they need
  * to initialize it by calling this static method. Then clients can obtain an instance of this
  * singleton class by calling {@link DataCastManager#getInstance()}. Failing to initialize this
  * class before requesting an instance will result in a {@link CastException} exception.
  *
  * @param context
  * @param applicationId the application ID for your application
  * @param namespaces Namespaces to be set up for this class.
  */
 public static synchronized DataCastManager initialize(
     Context context, String applicationId, String... namespaces) {
   if (sInstance == null) {
     LOGD(TAG, "New instance of DataCastManager is created");
     if (ConnectionResult.SUCCESS
         != GooglePlayServicesUtil.isGooglePlayServicesAvailable(context)) {
       String msg = "Couldn't find the appropriate version of Google Play Services";
       LOGE(TAG, msg);
       throw new RuntimeException(msg);
     }
     sInstance = new DataCastManager(context, applicationId, namespaces);
   }
   return sInstance;
 }
 public void onApplicationStatusChanged() {
   String appStatus;
   if (!isConnected()) {
     return;
   }
   try {
     appStatus = Cast.CastApi.getApplicationStatus(mApiClient);
     LOGD(TAG, "onApplicationStatusChanged() reached: " + appStatus);
     for (DataCastConsumer consumer : mDataConsumers) {
       consumer.onApplicationStatusChanged(appStatus);
     }
   } catch (IllegalStateException e) {
     LOGE(TAG, "onApplicationStatusChanged(): Failed", e);
   }
 }
 /**
  * Unregisters a namespace. If namespace is not already registered, it returns <code>false</code>,
  * otherwise a successful removal returns <code>true</code>.
  *
  * @throws NoConnectionException If no connectivity to the device exists
  * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a
  *     possibly transient loss of network
  */
 public boolean removeNamespace(String namespace)
     throws TransientNetworkDisconnectionException, NoConnectionException {
   checkConnectivity();
   if (TextUtils.isEmpty(namespace)) {
     throw new IllegalArgumentException("namespace cannot be empty");
   }
   if (!mNamespaceList.contains(namespace)) {
     LOGD(TAG, "Ignoring to remove a namespace that is not registered.");
     return false;
   }
   try {
     Cast.CastApi.removeMessageReceivedCallbacks(mApiClient, namespace);
     mNamespaceList.remove(namespace);
     return true;
   } catch (IOException | IllegalStateException e) {
     LOGE(TAG, String.format("removeNamespace(%s)", namespace), e);
   }
   return false;
 }
 /**
  * Adds a channel with the given {@code namespace} and registers {@link DataCastManager} as the
  * callback receiver. If the namespace is already registered, this returns <code>false</code>,
  * otherwise returns <code>true</code>.
  *
  * @throws NoConnectionException If no connectivity to the device exists
  * @throws TransientNetworkDisconnectionException If framework is still trying to recover from a
  *     possibly transient loss of network
  */
 public boolean addNamespace(String namespace)
     throws TransientNetworkDisconnectionException, NoConnectionException {
   checkConnectivity();
   if (TextUtils.isEmpty(namespace)) {
     throw new IllegalArgumentException("namespace cannot be empty");
   }
   if (mNamespaceList.contains(namespace)) {
     LOGD(TAG, "Ignoring to add a namespace that is already added.");
     return false;
   }
   //        try {
   //            Cast.CastApi.setMessageReceivedCallbacks(mApiClient, namespace, this);
   //            mNamespaceList.add(namespace);
   //            return true;
   //        } catch (IOException | IllegalStateException e) {
   //            LOGE(TAG, String.format("addNamespace(%s)", namespace), e);
   //        }
   return false;
 }
 @Override
 public void onApplicationConnectionFailed(int errorCode) {
   if (mReconnectionStatus == RECONNECTION_STATUS_IN_PROGRESS) {
     if (errorCode == CastStatusCodes.APPLICATION_NOT_RUNNING) {
       // while trying to re-establish session, we found out that the app is not running
       // so we need to disconnect
       mReconnectionStatus = RECONNECTION_STATUS_INACTIVE;
       onDeviceSelected(null);
     }
   } else {
     for (DataCastConsumer consumer : mDataConsumers) {
       consumer.onApplicationConnectionFailed(errorCode);
     }
     onDeviceSelected(null);
     if (mMediaRouter != null) {
       LOGD(TAG, "onApplicationConnectionFailed(): Setting route to default");
       mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute());
     }
   }
 }