Step 6: Report Your App's Dynamic Capabilities (VSK Fire TV)
With dynamic capabilities integrations, your app's capabilities depend on the user's state (such as login state or subscription level). As such, you will need to integrate with the VSK Agent to report the capabilities. The recommended approach for integrating with the VSK Agent is through the VSK Agent Client Library.
The sample app reports dynamic capabilities, so you do not need to do any coding in this step. In the sample app, see the
DynamicCapabilityReporter
class, AndroidManifest.xml
, VSK Agent Client Library, and capability files (inside of res/raw
) for details.- About the VSK Agent
- Choose How to Integrate with the VSK Agent
- Steps for Option 1: Integrate with the VSK Agent Service via the VSK Agent Client Library
- Steps for Option 2: Integrate with VSK Agent through VSKApplicationAgentAPI Package
- Best Practices: Dynamic Capability Reporting
- Next Steps
About the VSK Agent
The VSK Agent is an on-device routing agent on Fire OS. Your Fire TV app uses the VSKAgentClient
class to report its dynamic capabilities to the VSK Agent. These capabilities let the VSK Agent know what kind of directives it can broadcast to your app. The VSK Agent communicates with Fire OS through the Android Interface Design Language API, or AIDL.
The VSK Agent will send only directives that your app is capable of supporting. For example, if you don't indicate that your app is capable of supporting the PlaybackController
interface, Alexa won't send you PlaybackController
directives.
Choose How to Integrate with the VSK Agent
You have two options for how you integrate with the VSK Agent:
Option 1: VSK Agent Client Library (recommended approach)
The recommended approach is to consume the Amazon-provided VSK Agent Client Library. The VSK Agent Client Library gives you the full functionality of VSK Agent while streamlining some of the Android interprocess communication (IPC) details. The VSK Agent Client Library reduces your need to write many lines of code for integrating with the Fire TV VSK Agent. In short, it handles the work of connecting to this service for you, presenting you with normal Java methods you can call.
When you consume the VSK Agent Client Library, you have the ability to dynamically add or remove capabilities selectively and at any time. If you plan to support more advanced ways of communicating your app's UI state or other dynamic state updates in the future, you should choose this option. Leveraging the VSK Agent Client Library to integrate with VSK Agent is the fastest and easiest route to enable VSK capabilities in your app. (Note that even with the VSK Agent Client Library, capabilities which are always supported can still be declared in a static resource by following the static capabilities integration.)
The VSK Agent provides two methods for reporting your app's capabilities in a dynamic way:
AddOrUpdateCapabilities()
— a method for declaring the capabilities you support.sendCapabilityTestDirective()
— a method for testing your integration.
See Steps for Option 1: Integrate with the VSK Agent Service via the VSK Agent Client Library below for the implementation steps.
Option 2: VSKApplicationAgentAPI
Another option for connecting with the VSK Agent is for you to consume only the service definition and manage this connection code yourself. The VSK Agent Client Library communicates with a bound service under the hood. If you so choose, you can integrate with this under-the-hood service yourself by consuming the VSKApplicationAgentAPI
package yourself.
This VSKApplicationAgentAPI
package contains the necessary .aidl
files (as part of the Android Interface Definition Library) and Java classes for communicating with this service. While not the recommended route, Amazon realizes that under certain circumstances, you may want to manage all code yourself. This option might be appealing if you do not want to have any Amazon libraries or code in your project, perhaps to avoid any dependencies or due to other requirements.
See Steps for Option 2: Integrate with VSK Agent through VSKApplicationAgentAPI Package for some brief steps. More details about how to consume the VSKApplicationAgentAPI
package in detail are beyond the scope of this documentation.
Steps for Option 1: Integrate with the VSK Agent Service via the VSK Agent Client Library
To integrate with the VSK Agent Client Library to communicate with the VSK Agent (Option 1 above), perform the following steps:
Add the VSK Agent Client Library to Your Project
-
Download the VSK Agent Client Library (an AAR file):
Note that by downloading the VSK Agent Client Library, you agree to Amazon's Program Materials License Agreement.
(Note that the "VSK Agent Client Library" is not the same as the "Alexa Client Library" used in cloudside integrations.)
-
Add the VSK Agent Client Library to your project. In Android Studio, go to Find > New > Module. Then choose Import .JAR/.AAR Package and select the VSKApplicationAgentClientLibrary file.
-
When you import the AAR file, Android Studio adds VSKApplicationAgentClientLibrary to
settings.gradle (Project Settings)
so that it is available to be added as a dependency in your app'sbuild.gradle
file. Expand Gradle Scripts and go tosettings.gradle (Project Settings)
. Make sure theVSKApplicationAgentClientLibrary
has been included:include ':VSKApplicationAgentClientLibrary'
-
Expand Gradle Scripts, open
build.gradle (Module: App)
, and add a dependency for theVSKApplicationAgentClientLibrary
in thedependencies
object:dependencies { implementation project(path: ':VSKApplicationAgentClientLibrary') }
Note that the VSK Agent Client Library is not available on Maven or JCenter.
Sample App Notes
The sample app incorporates the VSK Agent Client Library. In Android Studio, switch to the Project view and look for theVSKApplicationAgentClientLibrary
folder.
Configure Your Manifest
Your app's manifest (AndroidManifest.xml
) contains declarations of the activities that your app performs. In your app's manifest, add the following permission to allow your app to integrate with VSK Agent:
<uses-permission android:name="com.amazon.alexa.vsk_app_agent_api.permission.BIND_SERVICE_PERMISSION" />
See the
AndroidManifest.xml
file (in app/manifests
) in the sample app for a full example of the app manifest.Initialize the VSK Agent Client Library
The next step is to initialize the VSK Agent Client Library within your code base.
In the sample app, this initialization takes place within the
DynamicCapabilityReporter
class (see src/java/com/example/vskfiretv/reporter
). DynamicCapabilityReporter
is the class where you report what voice capabilities your app supports.-
Create a new instance of the VSK Agent client:
public DynamicCapabilityReporter(final Context context) { this.context = context; // Create an instance of VSKAgentClient client = new VSKAgentClient(context); }
-
Declare your capabilities in the
reportDynamicCapabilities()
method, and then make a capability reporting request with theAddOrUpdateCapabilities()
method. Call this method in your app after the user has logged in.public void reportDynamicCapabilities() { // Create a list of supported capabilities in your app. final List<AlexaCapability> supportedCapabilities = new ArrayList<>(); supportedCapabilities.add(getAlexaCapability(R.raw.remote_video_player_capability)); // RemoteVideoPlayer Capability // supportedCapabilities.add(getAlexaCapability(R.raw.play_back_controller_capability)); // PlaybackController Capability -- commented out here because Media Session is recommended over PlaybackController //supportedCapabilities.add(getAlexaCapability(R.raw.channel_controller_capability)); // ChannelController Capability (not yet supported in app-only integrations) //supportedCapabilities.add(getAlexaCapability(R.raw.seek_controller_capability)); // SeekController Capability //supportedCapabilities.add(getAlexaCapability(R.raw.keypad_controller_capability)); // KeypadController Capability (not yet supported in app-only integrations) // Make the capability reporting request final AddOrUpdateCapabilitiesRequest request = new AddOrUpdateCapabilitiesRequest(supportedCapabilities); }
Note: Many of the capabilities are commented out in the code above because they are not recommended for Fire TV implementations.RemoteVideoPlayer
is the only recommended capability for VSK Fire TV integrations. (The non-recommended interfaces might be relevant to VSK integrations outside of Fire TV, such as with set-top cable boxes.)Alexa will send directives related to these capabilities listed here. For example, if you indicate
remote_video_player_capability
, Alexa will send directives related to theRemoteVideoPlayer
interface. If you don't have the capability declared, Alexa won't send directives related to the capability. -
The previous code declares capabilities by referencing files with code such as
Utils.getTextForRawResource(R.raw.remote_video_player)
. The references in the sample code above are as follows:remote_video_player_capability
(refers toRemoteVideoPlayer
)seek_controller_capability
(refers toSeekController
)play_back_controller_capability
(refers toPlaybackController
)keypad_controller
(refers toKeypadController
)channel_controller_capability
(refers toChannelController
)
In
app/res/raw
, create the necessary files with these names and capabilities declarations based on the interfaces your app supports. The details of the JSON objects for each of the capabilities are described in Supported Capabilities with App-only Integration.Sample App Notes
In the sample app, you can see these capabilities inapp/res/raw
. You can copy these sample JSON objects into your own app as appropriate. -
Using the the
addOrUpdateCapabilities()
method, report your app's dynamic capabilities to the VSK Agent:Log.i(TAG, "Reporting dynamic capabilities to the VSK Agent..."); final boolean reportingStatus = client.addOrUpdateCapabilities(request); if(reportingStatus) { Log.i(TAG, "Successfully reported dynamic capabilities to the VSK Agent"); return; } Log.e(TAG, "Failed reporting dynamic capabilities to the VSK Agent"); }
Now the VSK Agent will know that your app supports those capabilities. When you later run your app on Fire TV and look at the logs (in Step 10: Test Utterances and Observe Logs), you will see these capabilities reported to the VSK Agent by the
DynamicCapabilityReporter
class.Looking Ahead: Specifying Different Catalogs Based on User State
If desired, in the future you'll be able to specify a different catalog based on the user's subscription or status. For example, you could offer free content on one catalog ID (e.g.,acme_free
) and premium content with another catalog (e.g.,acme_premium
). To do this, you would report different capabilities based on different user states.
For example, for users with a premium subscription level, you could report capabilities that contain a differentcatalogs
property in the capability file. For these users, you could point to a capabilities file withacme_premium
. For users who are not logged in, you could point to a capabilities file with a catalogs property containingacme_free
. See the RemoteVideoPlayer Capabilities section in "Supported Capabilities with App-only Integration" for more details about thecatalogs
property. Note that this functionality isn't currently supported but will be in the future.
Full Code Example for Reporting Dynamic Capabilities
Here's a full boilerplate code example for reporting dynamic capabilities.
See also the
DynamicCapabilityReporter
class example in the sample app for a more real-world example in context.// -------------------------------\
// MyApplication.java
// -------------------------------/
public class MyApplication extends Application {
private static MyApplication sTheApp;
private VSKAgentClient client;
private HandlerThread vskAgentThread;
private Handler vskAgentHandler;...
public static MyApplication getInstance() {
return sTheApp;
}
@Override
public void onCreate() {
super.onCreate();
//...
vskAgentThread = new HandlerThread("VSKAgentThread");
vskAgentThread.start()
vskAgentHandler = new Handler(vskAgentThread.getLooper);
client = new VSKAgentClient(this);
reportCapabilities();
//...
}
//...
public void reportCapabilities() {
// api calls should be made on a background thread
vskAgentHandler.post(new Runnable() {
public void run() {
reportCapabilitiesInternal()
}
});
}
private void reportCapabilitiesInternal() {
// Determine currently supported Alexa capabilities based on
// current application state. You can dynamically construct
// the capability json, or just reference json in resource files (as we do here)
List < AlexaCapability > supportedCapabilities = new ArrayList < >();
if (accountManager.isLoggedIn()) supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.remote_video_player)));
//supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.playback_controller)));
if (accountManager.geteCurrentCustomer().hasSubscription(Subscription.LIVE_TV) {
supportedCapabilities.add(new AlexaCapability(Utils.getTextForRawResource(R.raw.channel_controller)));
}
}
AddOrUpdateCapabilitiesRequest request = new AddOrUpdateCapabilitiesRequest(supportedCapabilities);
boolean success = client.addOrUpdateCapabilities(request);
if (!success) {
//handle error
}
}
private String getTextForRawResource(int resId) {
InputStream inputStream = getResources().openRawResource(resId);
String line;
StringBuilder result = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
while ((line = reader.readLine()) != null) {
result.append(line).append('\n');
}
return result.toString();
} catch(IOException e) {
//error
}
return null;
}
VSKAgentClient
class must be called from the main thread, otherwise it will throw an exception. In general, dynamic capabilities should be reported when the app starts as well as any time the capabilities change. Be sure to read our best practices mentioned below, before moving on to the next step.Steps for Option 2: Integrate with VSK Agent through VSKApplicationAgentAPI Package
If you prefer to integrate with the VSK Agent yourself using the VSKApplicationAgentAPI
package (without relying on the VSK Agent Client Library), do the following:
-
Download the VSKApplicationAgentAPI (an AAR file).
Note that by downloading the VSKApplicationAgentAPI, you agree to Amazon's Program Materials License Agreement.
-
Add the VSKApplicationAgentAPI to your project. In Android Studio, go to Find > New > Module. Then choose Import .JAR/.AAR Package and select the VSKApplicationAgentAPI file.
-
When you import the AAR file, Android Studio adds the file to
settings.gradle (Project Settings)
so that it is available to be added as a dependency in your app'sbuild.gradle
file. Expand Gradle Scripts and open thesettings.gradle (Project Settings)
file. Make sure theVSKApplicationAgentAPI
has been included:include ':VSKApplicationAgentAPI'
-
Expand Gradle Scripts and go to
build.gradle (Module: App)
and add a dependency for theVSKApplicationAgentAPI
in thedependencies
object:dependencies { implementation project(path: ':VSKApplicationAgentAPI') }
- Declare the necessary permissions in your app manifest.
- On application create, report the currently supported capabilities via the
addOrUpdateCapabilities()
method. - Whenever an app state change would cause your supported capabilities to change, also call
addOrUpdateCapabilities()
.
Best Practices: Dynamic Capability Reporting
When you report dynamic capabilities to the Alexa App Agent, it determines if your app's capabilities have changed since the previous report, and then reports any changes to the Alexa cloud. For that reason, it's a good idea to report your dynamic capabilities on every app start. However, these capabilities should not change across reports. Changes in dynamic capabilities should be reported when there are long term changes in the application or the customer state that impacts the ability to handle customer requests.
For example, you may remove the capability to play content when the customer logs out of your app. Reporting changes in your dynamic capabilities causes unnecessary churn in the capabilities reported to Alexa, and may impact your customers. This is especially true if your app is throttled due to excessive discovery traffic. To avoid this, we highly recommend you follow the guidelines below when reporting dynamic capabilities:
- Don't report capabilities based on an unknown state. For instance, if the dynamic capabilities your app reports depend on if the user is logged in and that is determined asynchronously, wait until that state is known before reporting. Don't report dynamic capabilities as if the customer was logged out only to report again a few moments later.
- Don't report capabilities based on an ephemeral state that may change frequently. For example, you don't need to add or remove
PlaybackController
/SeekController
based on if content is playing or not. It is enough that your app is capable of the actions declared by the capability interface. - Don't add or remove capabilities based on the state outside your application logic. For instance, it's not necessary to change your app's capabilities based on if your app is in the foreground, or if a customer switched inputs on FireTV.
Next Steps
Go to the next step: Step 7: Add a BroadcastReceiver.
Last updated: Feb 15, 2023