Developer Console

Step 7: Add a BroadcastReceiver (VSK Fire TV)

When you add a BroadcastReceiver in your manifest, it tells Fire TV to send any intents with Alexa directives for your app to the BroadcastReceiver class you specify, e.g., AlexaDirectiveReceiver. This class is where you accept and handle the directives Alexa sends to your app.

Sample App Notes

The sample app reports had a BroadcastReceiver, so you do not need to do any coding in this step. In the sample app, the BroadCastReceiver is called AlexaDirectiveReceiver (inside java/com/example/vskfiretv/company/receiver).

Declare a BroadcastReceiver and Intent Filter in Your Manifest

The VSK Agent on Fire TV will send directives in intents that your app will receive. In your app's manifest, declare a BroadcastReceiver with an intent filter for handling Alexa directives and other capability reporting from the VSK Agent. This BroadcastReceiver will handle ACTION_ALEXA_DIRECTIVE and ACTION_REPORT_CAPABILITIES in its intent filter.

In the following manifest example, the name of the BroadcastReceiver is AlexaDirectiveReceiver, which is how the BroadcastReceiver is named in the sample app. Change this name to whatever you call your BroadcastReceiver in your app.

   <receiver
       android:name=".receiver.AlexaDirectiveReceiver"
       android:enabled="true"
       android:exported="true"
       android:permission="com.amazon.alexa.androidapplicationagent.permission.SEND_DATA">
       <!-- Intent action for receiving an Alexa directive-->
       <intent-filter>
           <action android:name="com.amazon.alexa.vsk_app_agent_api.ACTION_ALEXA_DIRECTIVE" />
       </intent-filter>
       <!-- Intent action requested by VSK Agent to an app to report its dynamic capabilities-->
       <intent-filter>
           <action android:name="com.amazon.alexa.vsk_app_agent_api.ACTION_REPORT_CAPABILITIES" />
       </intent-filter>
   </receiver>
Sample App Notes

See the AndroidManifest.xml in the sample app (inside app/src) for an example of how to declare your BroadcastReceiver and intent filter.

Add a BroadcastReceiver Java Class

Add a BroadcastReceiver Java class (e.g., AlexaDirectiveReceiver) that can handle various intents sent from the VSK Agent. You can name the receiver whatever you want as long as the class matches up with your manifest declaration (in the previous section).

The BroadcastReceiver class takes care of handling all the directives that are received by Alexa. Alexa sends directives to the VSK Agent, and the VSK Agent communicates the directives to your BroadcastReceiver.

The following is a boilerplate example of the BroadcastReceiver class:

// -------------------------------\
// MyDirectiveReceiver.java
// -------------------------------/
public class MyDirectiveReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {

    if (VSKIntentConstants.ACTION_ALEXA_DIRECTIVE.equals(intent.getAction())) {
      String namespace = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_NAMESPACE);
      String name = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_NAME);
      String payload = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_PAYLOAD);
      PendingIntent response = intent.getParcelableExtra(VSKIntentConstants.EXTRA_DIRECTIVE_RESPONSE_PENDING_INTENT);

      boolean didSucceed = false;
      boolean sendResponse = true;
      if (namespace.equals("RemoteVideoPlayer") {
        if (name.equals("SearchAndPlay") {
          sendResponse = false; //handling of this operation is async, pass around PendingIntent and call back when we know that status
          handlePlay(payload, response); // extract entities and build intent to deeplink into player activity
        } else if (name.equals("SearchAndDisplayResults") {
          didSucceed = handleSearch(payload); // extract entities and build intent to deeplink into search activity
        }
      } else if (name.equals("PlaybackController") {
        // ...
      } else if // ...
      if (response != null && sendResponse) {
        Intent success = new Intent().putExtra(VSKIntentConstants.EXTRA_DIRECTIVE_STATUS, didSucceed);
        try {
          response.send(context, 0, success);
        } catch(PendingIntent.CanceledException e) {
          //we probably took too long to respond, log error
        }
      }
    }
  }
}

This code receives the directives from Alexa and has placeholders to perform some logic based on the content. If the directive is handled successfully, you send a response with a success status. The response has either a true or false Boolean as the success parameter.

The next step, Step 8: React to Directives, goes into much more detail about the various directives that your app will receive and how to handle them.

Sample App Notes

The AlexaDirectiveReceiver class in the sample app has more detailed logic and other context than the boilerplate example above. The sample app attempts to show more of a real-world context for handling the directives.

Testing Your Dynamic Capabilities Integrations (Optional)

With dynamic integrations (regardless of whether you integrate using the VSK Agent Client Library or raw VSKApplicationAgentAPI package), you can call the sendCapabilityTestDirective method to test your app's integration. Calling this method causes the Fire OS routing agent to report back the capabilities for calling the app as a VSK directive.

This method is not intended to test that any particular directive handling is working. Its purpose is to verify that the device communication channels are working, so that you can see that you're correctly reporting your app's capabilities and that your BroadcastReceiver can receive intents from routing agent — without the need to connect to a Fire TV device or make a request/utterance.

The following code shows how to make a call to the sendCapabilityTestDirective() method.

// -------------------------------\
// MyDirectiveReceiver.java
// -------------------------------/
public class MyDirectiveReceiver extends BroadcastReciever {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (VSKIntentConstants.ACTION_ALEXA_DIRECTIVE.equals(intent.getAction())) {
            String namespace = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_NAMESPACE);
            String name = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_NAME);
            String payload = intent.getStringExtra(VSKIntentConstants.EXTRA_DIRECTIVE_PAYLOAD);

            if (VSKIntentConstants.TEST_DIRECTIVE_NAMESPACE.equals(namespace) &&
                VSKIntentConstants.TEST_DIRECTIVE_NAME.equals(name)) {
                log.d(TAG, payload);
            }
            ...
        }
        ...
     }
}

The requestTestDirectiveFromVSKAgent() method will trigger the VSK routing agent to send a test directive to your app, with no need to make a request/utterance to Alexa. The payload of this intent will be a JSON list of the capabilities that the routing agent has on record for your app. For example:

{"capabilities":[{"configurations":{"operations":["SearchAndDisplayResults","SearchAndPlay"],"catalogs":[{"type":"VIDEO_PUBLIC_CATALOG_IDENTIFIER","sourceId":"imdb"}]},"interface":"Alexa.RemoteVideoPlayer","type":"AlexaInterface","version":"3.1"},{"interface":"Alexa.PlaybackController","type":"AlexaInterface","version":"3","supportedOperations":["Play","Pause","Stop"]}]}

Sample App Notes

To see the sendCapabilityTestDirective() method in the sample app, take a look at the DynamicCapabilityReporter class (inside app/java/com/example/vskfiretv/company/reporter), specifically this section:

public void requestTestDirectiveFromVSKAgent() {
    Log.i(TAG, "Requesting VSK Agent for a test directive to be sent to the app");
    client.sendCapabilityTestDirective();
    Log.i(TAG, "Test Directive Request completed");
}

The sample app calls this method in MainActivity.java. The sample app uses an ExecutorService to spin up a background thread separate from the main thread:

// Spin a background thread to report the capabilities
final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(reporter::reportDynamicCapabilities);

Next Steps

Go to the next step: Step 8: React to Directives.