Amazon Device Messaging (ADM) and local notifications on Fire TV

Currently, Amazon Fire TV supports standard Android notifications through the Android Notifications API, which developers can use to send local notifications to customers that appear outside of your app’s user interface. Nowadays, it is quite common practice for apps developers to send notifications to smartphone users to grab their attention.

Similarly, on Fire TV, notifications allow developers to reach out to your customers to encourage them to revisit your app. You can use notifications to inform your customers when there is a new feature, content, or a promotional campaign available in your app.

This blog post will walk you through several types of notifications and the customer experience, how to send a server message through Amazon Devices Messaging (ADM), and how to convert that message to local notifications on Fire TV through the Android Notification API.

Note: Please be aware that ADM is required to push messages from your back-end to Amazon Fire OS devices, including Fire TV and Fire tablet.

 

Local notifications

There are 3 types of local notifications supported on Fire TV:

  • Heads-up notifications
  • Standard notifications
  • Toasts

 

1. Heads-up notifications

Fire TV by default sends notifications to customers when there is a new app or new update app available. You can also send heads-up notifications to the customer by using the Android notification API and specify the notification priority to high.

This is the method you need to invoke:

.setPriority(NotificationCompat.PRIORITY_HIGH)

 

Fire TV displays Heads up Notifications slightly differently from standard Android. See below for the user experience for Heads-up notifications on Fire TV:

 

2. Standard notifications

Standard notifications will be sent when the developer did not specify the notification priority. Standard notification will be stored inside the Notifications center under the Settings of Fire TV. These notifications are not shown as heads-up display and hence do not interrupt the user experience in any visible way when the customer is using a different app or is navigating the main Fire TV UI.

This is what the Notifications center looks like on Fire TV:

 

3. Toasts

Toasts are small pop-ups that appear within your app briefly and then disappear, with no ability for the user to interact with the message. Unlike heads-up notifications, toasts are not stored within the Notification Center. Developers can send a Toast message by using the makeText() and show() methods below. The display duration can also be adjusted in the makeText() method.:

        Context context = getApplicationContext();
        CharSequence text = title + message;
        int duration = Toast.LENGTH_LONG;

        Toast toast = Toast.makeText(context, text, duration);
        toast.show();

 

This is how Toast messages are displayed on Fire TV:

 

How to choose a notification method

While toasts notification allow a pop-up dialog to appear, Heads-up notification could also draw the customer’s attention via richer graphics and direct customers to launch your app immediately.

Note: Keep in mind that your app should not send a Heads-Up notification when another app is in the foreground, as this would provide a broken customer experience. Build your notification mechanism in order to verify if another app is in the foreground and do not display Heads-Up notifications in that case.

 

For less critical notifications such as app release information, standard notifications could be are a better choice instead of Heads-up notifications since they will not distract customers while they are consuming content.  Always be mindful of the customer experience when planning your notification mechanism.

 

Server-side messaging using ADM

Server-side messaging solution provide a scalable communication tools to mobile developers. Developers can send messages to millions of cross platform devices and connect with customers over channels like email, SMS, push, or voice.

One example of server-side messaging solution which supports Amazon Device Messaging (ADM) -required for sending messages to Fire OS devices such as Fire TV – is AWS Pinpoint. With AWS Pinpoint, developer can also measure customer engagement and generate analytical data from its applications. A marketing team can then use this insight to strengthen campaigns and determine how to most effectively communicate with its customers.

In this blog post, we will instead focus on the ADM implementation by using the ADM SDK available on Amazon Developer portal. Before you read through the setup procedures below, you can find more information on the ADM Architecture and Roles/Responsibilities for each ADM component by referring to the ADM Overview page.
 

1. Server setup

Download the ADM SDK and under the example folder, you could see the server scripts inside the server-python folder. To run the server, perform the following actions:

  1. Change the value of PORT at the beginning of server.py to the port you would like the server to listen on. Make sure this port is opened and accessible before proceeding.
  2. Change the values of PROD_CLIENT_ID and PROD_CLIENT_SECRET to the ones you received from Amazon. These are also located at the beginning of server.py.
  3. Run from the command line: > python server.py

For #2, PROD_CLIENT_ID and PROD_CLIENT_SECRET, these credentials are assigned to you by Amazon. Your servers use both pieces of these credentials in their requests to obtain access tokens.

After #3 above, you can access the server through a browser. In the image below you can see the Server UI for sending message to the clients.

The diagram below shows you the high level message flow from your server to your app. In this example, “your server” will be replaced with a self-contained sample web application written as a Python script which is provided as part of the ADM SDK. The web application simulates a range of tasks your server could implement to send messages to client applications.

 

2. Client setup

Under the same example folder, you should see the ADMMessenger folder where the client project is located.

To run the client:

  1. In ADMMessenger/assets/api_key.txt, replace the line of text you see with the API Key you received from Amazon.
  2. In ADMMessenger/res/values/strings.xml, change the values of server_address and server_port to values that reference your server.
<string name="server_address">http://xxx.xxx.xx.xx</string>
<string name="server_port">8080</string>

 

When you completed the setting above, you can build, install and run the client app from Android studio.

Here is the sample code, based on the ADM SDK, for how we could build local notification, with the data from JSON file through ADM, and display them on the Fire TV as a head-ups notification.
 

public static void createADMNotification(final Context context, final String titleKey, final String msgKey, final String urlKey, final String timeKey,
                                             final String intentAction, final String title, final String msg, final String url, final String time)
    {

        /* Clicking the notification should bring up the MainActivity. */
        /* Intent FLAGS prevent opening multiple instances of MainActivity. */
        final Intent notificationIntent = new Intent(context, MainActivity.class);
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        notificationIntent.putExtra(titleKey, title);
        notificationIntent.putExtra(msgKey, msg);
        notificationIntent.putExtra(urlKey, url);
        notificationIntent.putExtra(timeKey, time);

        /* Android reuses intents that have the same action. Adding a time stamp to the action ensures that */
        /* the notification intent received in onResume() isn't one that was recycled and that may hold old extras. */
        notificationIntent.setAction(intentAction + time);

        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent,Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL);

        Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.amazon1280);

        Notification.Builder builder;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = new Notification.Builder(context, CHANNEL_ID)
                    .setContentTitle(title)
                    .setContentText(msg)
                    .setContentText(url)
                    .setColor(Color.BLUE)
                    .setSmallIcon(R.drawable.ic_launcher_foreground)
                    .setLargeIcon(largeIcon)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);
        } else {
            builder = new Notification.Builder(context)
                    .setContentTitle(title)
                    .setContentText(msg)
                    .setContentText(url)
                    .setColor(Color.BLUE)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setSmallIcon(R.drawable.ic_launcher_foreground)
                    .setLargeIcon(largeIcon)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);
        }

        Notification notification = builder.build();

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        notificationManager.notify(context.getResources().getInteger(R.integer.sample_app_notification_id), notification);
    }

 

Here is what the customer experience looks like when the alert was sent from the app:

 

Conclusion

Together with marketing communications services such as AWS Pinpoint, Amazon Device Messaging, and the local notification features, Fire TV provides a powerful way to increase engagement.  Learn more with our documentation for Amazon Device Messaging (ADM).

 

 

KevinKaiTsang.jpg

Kevin Tsang is an Amazon Solutions Architect experienced with Fire TV and Fire tablet app development, Live TV, Catalogue Integration, and Alexa Video Skills implementation.

Amazon Appstore to support Android App Bundle

Earlier this year, Android App Bundle format was announced by Google as mandatory open-source format for new Google Play app submissions starting August 2021. Amazon Appstore is actively working to support the new format, which will provide benefits such as smaller app size downloads for customers and on-demand downloads for features and assets. These changes benefit customers by helping them download specific aspects of an app in real-time as needed.

For Amazon Appstore developers, in addition to the existing APK format, we are working to support the app bundles format across all types of submissions. We will share updates later this year on our progress to continue making app submission as simple and friction-less as possible for our developers.
 


FAQs

1. Will Android App Bundles be mandated for Amazon Appstore?
App bundles will be completely optional, and developers will be able to continue submitting apps using existing APK format.

2. Will there be any changes to the way developers submit apps ?
There are no changes to the app submission process. For both app formats (APK or bundle), developers will continue to submit apps in the same way as before.

3. Will I need to resubmit my app if it was published using APK?
No, you will not need to resubmit your app if it was submitted and published in APK format earlier. You can continue publishing new apps and updates to existing apps using APK format. In order to utilize app bundles, developers would need to plan future submissions using the bundles format (*.aab), however, there will be no changes in the way developers currently submit apps to Appstore.

5. Will my apps get all available App Bundle benefits when Amazon Appstore starts supporting it?
We will support upload of apps in App Bundle format. We have a roadmap to enable customer experience benefits incrementally over time. We will share our roadmap and more details closer to rollout.

6. Will I need to submit my app signing key to Amazon to submit App Bundles?
No, Amazon Appstore does not require you to share your app signing key to submit App Bundles. You will continue to sign App Bundles similar to the way that you sign APKs and submit today.
 

 

How to build a Touch-enabled Fire TV app using WebView and HTML5 web-app

Fire TV offers a variety of ways for developers to present content to customers. An HTML5 based web application could be a good candidate to provide a customer experience that is consistent with the rest of your service and have faster time to market, making it easier to deploy your apps in several marketplaces & devices. It also allows for an easier roll out of updates without having to build & release the whole app.

In this tutorial, you will learn how to create a wrapper app for Fire TV devices using Amazon WebView (AWV) technology that works using both D-Pad and touch interactions. The Fire TV documentation on UX Best Practices covers this basic aspects of app navigation and input.

 

The tutorial will cover 4 key steps:

  • Step 1: Declare Touchscreen hardware features
  • Step 2: Adding support for Amazon WebView (AWV) and enabling JavaScript
  • Step 3: Handling page navigation and device configuration changes
  • Step 4: Handling interactions between WebView and web application

 

Step 1: Declare Touchscreen hardware features

To enable basic touch interaction events such as tapping and dragging, add android.hardware.touchscreen declaration to your AndroidManifest.xml file. This feature indicates that the app is compatible with a device if that device has an actual touchscreen or emulates a touchscreen (“fake touch” interface). We need to add this as we will be targeting Fire TV devices with a touchscreen.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...>

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />
    ...
</manifest>

Since your web application is hosted online, your wrapper app must have access to the Internet. To get internet access, request the INTERNET permission in your manifest file. For example:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myapplication"
    tools:ignore="MissingLeanbackLauncher">

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />

    <uses-feature
        android:name="android.software.leanback"
        android:required="false" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:banner="@drawable/amazon_firetv"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true">
        <activity
            android:name=".MainActivity"
            android:configChanges="fontScale"
            android:label="@string/player_activity_name"
            android:launchMode="singleTop"
            android:theme="@style/AppTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <uses-library
            android:name="com.amazon.webview"
            android:required="false" />
    </application>

</manifest>

 

Step 2: Adding support for Amazon WebView (AWV) and enabling JavaScript

The [WebView](https://developer.android.com/reference/android/webkit/WebView) class is an extension of Android’s View class that allows you to render web pages as a part of your Activity layout. It does not include any features of a fully developed web browser, such as navigation controls or an address bar. All that WebView does, by default, is show a web page.

To add a WebView to your app in the layout, add the following code to your activity’s layout XML file:

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center" />

</FrameLayout>

Now, within your Fire TV app, create an Activity that contains a WebView, then use that to display your online web application in onCreate()). To load a web page in the WebView, use loadUrl()). In the following example, mBaseUri, holds the address to your online hosted web application.

MainActivity.java

public class MainActivity extends Activity {

    // Address to your online hosted web application
    private final String mBaseUri = "https://mysampleapp.com";

    private Context mContext = null;
    private WebView mWebView;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mContext = this.getApplicationContext();

        // An activity is a single, focused thing that the customer can do.
        // Activity class takes care of creating a window for you in which
        // you can place your layout resource defining your UI.
        // In this example layout resource is defined in activity_main.xml.
        setContentView(R.layout.activity_main);

        // Retrieve the WebView widget in UI that you need to interact with.
        // In this example WebView widget is identified by "web_view" in activity_main.xml.
        mWebView = findViewById(R.id.web_view);

        mWebView.loadUrl(mBaseUrl);
    }
    ...
}

Amazon WebView (AWV) optimizations

All Fire TV devices running on Fire OS 5 and later include Amazon WebView (AWV) as a transparent replacement for the standard Android WebView class. AWV uses a custom build of Chromium that has been optimized specifically for Fire OS, devices providing faster and more efficient rendering, better video performance, and improved resource management.

To enable support for AWV, specify com.amazon.webview shared library that the application must be linked against. This tells the system to include the library’s code in the class loader for the package.

AndroidManifest.xml

<application
    android:allowBackup="true"
    android:banner="@drawable/amazon_firetv"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true">
    ...

    <uses-library
        android:name="com.amazon.webview"
        android:required="false" />

</application>

To take a full advantage of various optimizations available with AWV, you can also enable additional functionalities by passing command line options in onCreate()) method of your app’s Activity that contains a WebView. For example:

MainActivity.java

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    ...
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ArrayList<String> cmd_args = new ArrayList<>();
        cmd_args.add("enable-system-key-events-processing");
        cmd_args.add("enable-awv-mode");
        cmd_args.add("amazon-player-type=exoplayer");
        cmd_args.add("enable-experimental-webkit-features");
        cmd_args.add("enable-use-wide-viewport");
        cmd_args.add("enable-full-paint-on-dom-update");
        cmd_args.add("enable-devtools-experiments");
        try {
            Class<?> webViewExtensionClassObj = Class.forName("com.amazon.webview.extensions.WebViewExt");
            Method setOptionsMethod = webViewExtensionClassObj.getDeclaredMethod("setEngineOptions", List.class);
            setOptionsMethod.invoke(webViewExtensionClassObj, cmd_args);
        } catch (Exception e) {
            Log.e(TAG, "com.amazon.webview load Exception: " + Log.getStackTraceString(e));
        }
        ...

        mWebView = findViewById(R.id.web_view);
        ...
    }
    ...
}

Note: Enabling AWV support using com.amazon.webview and optimization via flags added in Activity class is completely optional. Developers are advised to measure performance of their applications against individual flags.

 

Enabling JavaScript

As your web application is most likely to use JavaScript for enabling various customer interactions and communicate with your backend services, you must enable JavaScript for your WebView.

JavaScript is disabled in a WebView by default. You must enable it through the WebSettings attached to your WebView. To achieve this retrieve WebSettings with getSettings()), then enable JavaScript with setJavaScriptEnabled()).

MainActivity.java

public class MainActivity extends Activity {

    private final String mBaseUrl = "https://mysampleapp.com";

    private Context mContext = null;
    private WebView mWebView;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        mWebView = findViewById(R.id.web_view);
        
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        ...

        mWebView.loadUrl(mBaseUrl);
    }
    ...
}

WebSettings provides access to a variety of other settings that you might find useful. For example, if you’re developing a web application that’s designed specifically for the WebView in your Fire TV app, then you can define a custom user agent string with setUserAgentString()), then query the custom user agent in your web page to verify that the client requesting your web page is actually your Fire TV app.

 

Step 3: Handling page navigation and device configuration changes

Note: If your web application is built as a SPA (Single-page application) that only loads a single web document, and then updates the body content of that single document via JavaScript APIs, you can skip this step.

 

Navigation for non-SPA web applications

In case your web application requires customers to click a link for navigating to a different section of the app, for example a navigation menu, when the customer clicks a link in your WebView, the default behaviour is for Fire TV to launch an app that handles URLs. Usually, the default web browser opens and loads the destination URL. However, you can override this behavior for your WebView, so links open within your WebView. You can then allow the customer to navigate backward and forward through their web page history that’s maintained by your WebView.

Note: For security reasons, the Fire OS browser app does not share its application data with your web application.

 

To open all links clicked by the customer, provide a WebViewClient for your WebView, using setWebViewClient()). Creating a custom WebViewClient that overrides the shouldOverrideUrlLoading()) gives the host application a chance to take control when a URL is about to be loaded in the current WebView.

In the following example we are creating a CustomWebViewClient as an inner class of Activity and an instance of this new WebViewClient for the WebView.

MainActivity.java

public class MainActivity extends Activity {

    private final String mBaseUrl = "https://mysampleapp.com";

    private WebView mWebView;
    private CustomWebViewClient webViewClient;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        mWebView = findViewById(R.id.web_view);
        
        webViewClient = new CustomWebViewClient();
        mWebView.setWebViewClient(webViewClient);
        ...

        mWebView.loadUrl(mBaseUrl);
    }
    ...
}

class CustomWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        view.loadUrl(request.getUrl().toString());

        return super.shouldOverrideUrlLoading(view, request);
    }
}

Device configuration changes in response to accessibility features customization

There are various accessibility features available on Fire TV. One of them is the Text Banner, an on-screen text banner that will help customers with visual impairments view the text on their screen. When the customer changes accessibility features during the runtime, activity state changes occur causing device configuration changes. This could interfere with WebView object’s activity to be destroyed and a new activity to be created, which also creates a new WebView object that loads the destroyed object’s URL.

In order to handle configuration changes during runtime so that your application doesn’t need to update resources during a specific configuration change and avoid the activity restart, declare that your activity handles the fontScale configuration change itself which prevents the system from restarting your activity.

AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:configChanges="fontScale"
    android:label="@string/player_activity_name"
    android:launchMode="singleTop"
    android:theme="@style/AppTheme">
    ...
</activity>

Now, when the configurations change, MainActivity does not restart. Instead, the MainActivity receives a call to onConfigurationChanged(). This method is passed a Configuration object that specifies the new device configuration. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. At the time this method is called, your activity’s Resources object is updated to return resources based on the new configuration, so you can easily reset elements of your UI without the system restarting your activity.

MainActivity.java

public class MainActivity extends Activity {

    ...

    @Override
    public void onConfigurationChanged(final Configuration c) {
        super.onConfigurationChanged(c);

        mWebView.getSettings().setTextZoom((int) (c.fontScale * 100));
    }
}

That’s all you need for a basic WebView that displays a web page. Additionally, you can customise your WebView by modifying the following:

  • Enabling fullscreen support with WebChromeClient. This class is also called when a WebView needs permission to alter the web application’s UI, such as creating or closing windows and sending JavaScript dialogs to the customer.
  • Handling events that impact content rendering, such as errors on form submissions or navigation with WebViewClient. You can also use this subclass to intercept URL loading.

 

Step 4: Handling interactions between WebView and web application

 

Dispatching D-PAD events from webview

All Amazon Fire TV remote controls generate KeyEvent events for button presses, as any Android input device does. You can handle controller button input with standard Android event listener interfaces and callbacks. Neither the Amazon Fire TV Remote nor the Voice Remote raises motion events (from the Android MotionEvent class).

Note: The remote controllers for Fire TV Edition has some additional buttons — such as volume up/down, power, and specific app buttons that allow to directly open those apps. However, these buttons can’t be mapped to events in third-party apps.

 

You can greatly enhance the customer experience in your application by managing the D-Pad interactions. The Android framework provides APIs for detecting and processing D-Pad (or any other controller) inputs. In your Activity class, override the dispatchKeyEvent()) method, and add customizations as needed. The following example shows how to change the “BACK” key on D-Pad to go back in the WebView consistently, and exit the app if there is no history to navigate. Overriding the dispatchKeyEvent() method simultaneously allows sending the key events to WebView which can be handled in your web application using JavaScript to perform desired actions.

MainActivity.java

public class MainActivity extends Activity {

    private final String mBaseUrl = "https://mysampleapp.com";

    private Context mContext = null;
    private WebView mWebView;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
    }
    
    ...
    
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        Log.d(TAG, "dispatchKeyEvent : KeyCode = " + event.getKeyCode() + " (" + KeyEvent.keyCodeToString(event.getKeyCode()) + ")");

        switch (event.getKeyCode()) {
            // Handle back button from D-Pad
            case KeyEvent.KEYCODE_BACK:
                Log.d(TAG, "dispatchKeyEvent : mWebView.canGoBack = " + mWebView.canGoBack());
                if (mWebView.canGoBack()) {
                    // Navigate back on WebView
                    mWebView.goBack();
                } else {
                    // WebView has no more history, exit the app
                    finish();
                }
        }

        return super.dispatchKeyEvent(event);
    }
}

After overriding the dispatchKeyEvent() method, when you press Play/Pause button from the D-Pad you should see following lines in ADB logs. KEYCODE_MEDIA_PLAY_PAUSE is represented as KeyCode = 85. Please follow this link to learn more about the Android KeyEvent constants, and the default behavior of those buttons on Fire TV devices.

D/MainActivity: dispatchKeyEvent : KeyCode = 85 (KEYCODE_MEDIA_PLAY_PAUSE)

Handling D-pad interactions in javascript

D-Pad interactions by customers are received as KeyboardEvent events in your web application’s JavaScript. To handle a KeyboardEvent, you need to follow these steps:

1.  Select the [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) on which the event will fire. Since we are using WebView to render the web application’s content in your Fire TV wrapper application, it is recommended that events are listened on the [Window](https://developer.mozilla.org/en-US/docs/Web/API/Window) object.

2.  Use [element.addEventListener()](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to register an event handler. For each key press on D-Pad, JavaScript receives two events,

a. keydown – when a key on the D-Pad is pressed down, and auto repeats if the key is pressed down for long.

b. keyup – when a key on the D-Pad is released.

 

In following example, we are using an open source HTML5 video player called Video.js to setup a basic media player experience. keydown event is triggered as soon as D-Pad interaction starts, for the demonstration purpose, we are setting the background of whole document to green color. When the key press is released, keyup event is triggered. The custom key handling mechanism is defined in handleKeyEvent() method.

index.html

// https://videojs.com/getting-started/
const player = videojs("video", {...});

// Custom Key Event Handler
const moveTime = 10; // Move time by number of seconds
const handleKeyEvent = (event) => {
    switch(event.code) {
        case "MediaPlayPause":
        case "NumpadEnter":
            // Check is the playback is paused
            if (player.paused()) {
                videojs.log('handleKeyEvent:', 'Play', player.currentTime());
                // Resume the playback
                player.play();
            } else {
                videojs.log('handleKeyEvent:', 'Pause', player.currentTime());
                // Pause the playback
                player.pause();
            }
            break;
        case "MediaRewind":
        case "ArrowLeft":
            // Move back the playback time by 10 seconds
            player.currentTime((player.currentTime() - moveTime) < 0 ? 0 : (player.currentTime() - moveTime));
            videojs.log('handleKeyEvent:', 'Rewind', player.currentTime());
            break;
        case "MediaFastForward":
        case "ArrowRight":
            // Move forward the playback time by 10 seconds
            player.currentTime(player.currentTime() + moveTime);
            videojs.log('handleKeyEvent:', 'Fast Forward', player.currentTime());
            break;
        default:
            videojs.log('handleKeyEvent:', 'Unhandled event.code =', event.code);
            break;
    }
}

// Listen for Keyboard Events dispatched by Fire TV app's WebView
window.addEventListener("keyup", (event) => {
    // Reset the background colour when key press is lifted
    document.body.style.background = "";

    if (event.key !== undefined) {
        console.log('keyup:', 'event.key =', event.key);
        // Handle the event with KeyboardEvent.key
        handleKeyEvent(event);
    }
});

window.addEventListener("keydown", (event) => {
    // Change background colour when key press is down
    document.body.style.background = "green";
});

 

Dispatching Touch events from webview

Although your app should not exclusively depend on touch gestures for basic behaviors, since this form of interaction may not be available on all Fire TV devices, adding a touch-based interaction to your app wrapper application can greatly increase its usefulness and appeal.

A touch gesture occurs when a customer places one of more fingers on the touch enabled device’s screen, and your application interprets that pattern of touch as a particular gesture. There are two phases to the gesture detection:

1.  Gather data about the touch events – When a customer places one or more fingers on the screen, this triggers the callback onTouchEvent()) on the View that received the touch events. For each sequence of touch events (position, pressure, size, addition of another finger, etc.) that is ultimately identified as a gesture, onTouchEvent()) is fired several times.

2.  Interpret the data to see if it meets the criteria for any of the gestures your app supports. The gesture starts when the customer first touches the screen, continues as the system tracks the position of the customer’s finger(s), and ends by capturing the final event of the customer’s finger(s) leaving the screen. Throughout this interaction, the MotionEvent delivered to onTouchEvent()) provides the details of every interaction. Your app can use the data provided by the MotionEvent to determine if a gesture it cares about happened.

In the following example, we are intercepting touch events in app’s Activity class, overriding the onTouchEvent()) callback. The snippet uses getActionMasked()) to extract the action the customer performed from the event parameter. This gives you the raw data you need to determine if a gesture you care about occurred:

MainActivity.java

public class MainActivity extends Activity {
    
    ...
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();

        switch(action) {
            case (MotionEvent.ACTION_DOWN):
                Log.d(TAG,"Action was DOWN");
                return true;
            case (MotionEvent.ACTION_MOVE):
                Log.d(TAG,"Action was MOVE");
                return true;
            case (MotionEvent.ACTION_UP):
                Log.d(TAG,"Action was UP");
                return true;
            case (MotionEvent.ACTION_CANCEL):
                Log.d(TAG,"Action was CANCEL");
                return true;
            case (MotionEvent.ACTION_OUTSIDE) :
                Log.d(TAG,"Movement occurred outside bounds of current screen element");
                return true;
            default:
                return super.onTouchEvent(event);
        }
    }
}

Handling Touch interactions in JavaScript

Touch events are similar to mouse events except they support simultaneous touches and at different locations on the touch surface. The TouchEvent interface encapsulates all of the touch-points that are currently active. The Touch interface, which represents a single touchpoint, includes information such as the position of the touch point relative to the browser viewport.

Touch events consist of three interfaces (Touch, TouchEvent and TouchList) and the following event types:

  • touchstart – fired when a touch point is placed on the touch surface.
  • touchmove – fired when a touch point is moved along the touch surface.
  • touchend – fired when a touch point is removed from the touch surface.
  • touchcancel – fired when a touch point has been disrupted in an implementation-specific manner (for example, too many touch points are created).

Continuing from the previous example of HTML5 video player, we can now add some basic touch interactions on button elements defined within the player’s media control. playPauseControl element targets the play/pause button from the player, and muteControl targets audio the mute/un-mute button. You can learn more about JavaScript Touch Events from MDN Web Docs and a guide to adding touch events to your application is available on Google Web Fundamentals.

index.html

const player = videojs("video", {...});

// Listen for Touch Events dispatched by Fire TV app's WebView
// Play/Pause
let playPauseControl = document.getElementsByClassName('vjs-play-control')[0];
playPauseControl.addEventListener("click touchstart", (event) => {
    videojs.log('playPauseControl', 'touched');
});

// Mute/Un-mute
let muteControl = document.getElementsByClassName('vjs-mute-control')[0];
muteControl.addEventListener("click touchstart", (event) => {
    videojs.log('muteControl', 'touched');
});

 

Conclusion

If you are planning to deliver an existing HTML5 based web application as a part of a client application to Fire TV, this guide will help implement the necessary interactions and navigation required for a smooth customer experience. You can learn more about how to optimize Web Apps for Fire devices on the Amazon Developer Portal.

For more details, check out our documentation:

 

 

MayurAhir.jpg

Mayur Ahir is an Amazon Solutions Architect with domain expertise in developing cross-platform HTML5 applications for devices powered by Fire OS and Alexa, such as Fire TV, Fire Tablets, and Echo Show.

Recommendations on Fire TV

Fire TV devices offer a variety of entertainment options for the over 50 million monthly active users worldwide.  With so many choices available, simplify content discovery with recommendations. Your app can send recommendations to users about the movies, shows, music, and games that you want them to watch.

Recommendations appear on a “Recommended By Your Apps” (ReYA) row on the Amazon Fire TV home screen and shows all recommendations from apps the user has currently installed (and opened at least once).

 

 

ReYA in Fire TV is based on the Android Recommendations API, which in turn, is based on Android notifications.  Amazon extends the Android recommendations API to provide deeper integration with Amazon Fire TV.

If developers have optimized their apps for Fire OS 5, they may see their recommendations are missing from the ReYA row on Fire OS 7 devices; this is because Fire OS 7 is built on Android 9, which introduces changes to the recommendations engine. The Fire TV home screen, therefore, displays recommendations in two different ways depending on the version of Fire OS running on the device:

 

  • Fire OS 5 and 6: Older Fire TV devices are on Fire OS 5 (Android 5.1, API level 22). Before Android 8.0, Android shows all recommendations in a single recommendations row that always appears on the screen. Fire OS 6 is based on Android Nougat (Android 7.1.2, level 25), so the ReYA row will still show up correctly on these devices with no changes from Fire OS 5.

 

  • Fire OS 7: In Android 8.0 (API level 26) and later, apps can show recommendations in one or more channels that appear on separate rows. One channel (the default channel) always appears. Hence, in Fire OS 7, which is based on Android 9.0 Pie (API level 28), notifications that any app sends must be assigned to a channel (since recommendations are a kind of notification). If an app sends notifications or recommendations, then it must create a channel and associate the channel with the notification. A notification without a channel ID will be dropped.

 

To be able to show recommendations on all versions of Fire TV, apps should implement both recommendation APIs, i.e. for Fire OS 5 and 6 and for Fire OS 7.

 

Interested in learning more or ready to get started? Check out these resources:

Amazon and Microsoft create new opportunities for developers and increase return on investment in the Amazon Appstore

 

Today, at the Microsoft’s Windows Event, Microsoft and Amazon announced plans to bring the Amazon Appstore to Windows 11. With the upcoming release of Microsoft’s operating system, Windows customers will have access to Android apps on their Windows 11 devices, expanding the selection of apps for customers across multiple genres.

“Today we offer a broad selection of mobile apps in our Amazon Appstore, available across Fire TV, Fire Tablets, and Android devices that our customers use and enjoy every day,” said Palanidaran Chidambaram, Director of the Amazon Appstore and Cross-Screen Technology. “With this announcement, Amazon Appstore developers will now have the opportunity to make their Android apps available to hundreds of millions of Windows customers.”

The availability of the Amazon Appstore on Windows 11 will allow developers to easily expand their app reach to Windows devices and increase their return on investment. Microsoft customers will be able to discover a new selection of Android apps in the Microsoft Store on Windows 11, and download them through the Amazon Appstore.

The initial Amazon Appstore selection will be available to Windows customers later this year. We will have more to share in the future about how you can make your app available to Windows customers.

 

Are you new to the Amazon Appstore? The best way to get started is to submit your app here to unlock the benefits of the Amazon Appstore.   


FAQs 

 

1. How will the Amazon Appstore work for Windows customers?

The expanded mobile app selection in the Microsoft Store is powered by the Amazon Appstore, offering more app choice and selection for Windows 11 customers. Customers can access these mobile apps within the Microsoft Store on their Windows device.
 

2. How will customers find my app in the Microsoft Store?

Windows customers will be able to find Amazon Appstore apps through integrated search, browse, and discovery in the Microsoft Store.
 

3. Will existing Amazon Appstore apps automatically be included on Windows?

The Amazon Appstore team will be in touch with developers later this year to share details on how to publish to Windows. Developers who aren’t currently part of the Amazon Appstore can submit their Android apps here.
 

How to add Touch interactions to Android-based Fire TV applications

If you are building an app for Amazon Fire TV, it is good practice to implement the navigation and interaction of your app UI with the remote control. This can be achieved in multiple ways, but the key concept is to map the controls of the movement and interactions inside your apps to the D-Pad and buttons present on the Fire TV remote. The Fire TV documentation on UX best practices covers this basic aspects of app navigation and input.

With Fire TV expanding to automotive, it’s important to now add touch interactions to Fire TV apps on top of the D-Pad navigation. Customers will both be able to use remote controls, and touch on these devices.

In this tutorial we will see how to modify Android-based Fire TV apps designed for D-Pad to add touch interaction and how to provide a good touch-based UX.

The tutorial will cover 5 key steps:

 

  • Step 1: Understanding UI Directional Navigation and focus with D-Pad
  • Step 2: Applying Directional Navigation to TV apps layouts
  • Step 3: Adding touch interactions for clicks: OnClickListeners
  • Step 4: Managing view focus between D-Pad and touch interactions
  • Step 5: Additional best practices and testing touch on Fire TV

 

Step 1: Understanding UI Directional Navigation and focus with D-Pad

Android-based applications for Fire TV should follow clear platform-level patterns for remote-based navigation. Since Fire OS is built on top of Android, it follows the same layout and design patterns as standard Android apps.

In order to map app UI navigation automatically to the remote D-Pad, and specify in what order the different Android Views should be navigated by the customer, we need to use Android’s Directional Navigation (see Android’s documentation here). This is a best practice, and if your Android application doesn’t follow this pattern, it’s important to apply the following changes as this impacts how the Touch behaviour connects to the D-Pad behaviour.

The Directional Navigation requires us to specify for each “focusable” view what is the next or previous view that needs to be selected. This will allow the system to automatically map what is the next view that will be focused on when a user presses the navigation buttons on their remote D-Pad (Up, Down, Left, Right).

This is achieved by adding to our layout XML files views the following tags:

android:nextFocusDown, android:nextFocusRight, android:nextFocusLeft, android:nextFocusUp

followed by the id of the view we want the app to select next based on the order.

So for example

<TextView android:id="@+id/Item1"
    	  android:nextFocusRight="@+id/Item2"/>

Allows the TextView called Item1 to move to the view called Item2 when the customer presses the “Right” button on their D-Pad. This applies to all directions in navigation.

 

Step 2: Applying Directional Navigation to TV apps layouts

Before we apply touch interactions to our Fire TV app, we need to make sure that we create a consistent Directional Navigation experience between D-pad and touch navigation.

This is quite simple for basic apps interfaces, but Media and Entertainment TV Apps interfaces can be quite complex, as more often than not they need to display dynamic content. Hence, most views might be generated at runtime.

In order to achieve this, most developers use Android Views that can easily hold dynamic content. A good example of this is the RecyclerView. The RecyclerView is a component which allows dynamic content to be parsed from an adapter. RecyclerView is efficient and it implements one of the standard Android patterns: the ViewHolder.

However, since the content of a RecyclerView is dynamic, we need to make sure that the navigation between the views which are generated inside RecyclerViews is correct.

In order to demonstrate this, we created a simple application which simulates the standard implementation of a TV interface. This application has two main UI components:

  • A first LinearLayout called “menuLayout”, containing a RecyclerView called “recyclerViewMenu” which itself contains the left-side menu with all the categories
  • A second LinearLayout called “rowsLayout” containing other RecyclerViews which instead contain all the movies and content that can be played

On the left you can see the menuLayout in black, and on the right the rowsLayout in grey

 

While this is an oversimplification for the sake of this tutorial, as your app might have more complex nesting for its views, this represents the skeleton of a dynamic Media/TV App UI.

What you want to do now is to define how the directional navigation works on this layout.

The first thing that we want to make sure of is that we can actually move from our categories menu to the content rows. So what we do is to set nextFocusRight to the first row RecyclerView for our LinearLayout:

<LinearLayout
   android:id="@+id/menuLayout"
   [...]
   android:nextFocusRight="@id/rowRecyclerView1">

This way, once the user clicks on the right button, it will automatically move the focus to the first RecyclerView on the right.

Another thing that we need to do is to set up how the navigation between the items of the RecyclerView itself works. Since the views of a RecyclerView are created dynamically at runtime, it is not practical to manually set the direction of navigation on each individual view; it cannot be achieved using the XML layout anyway. Instead, in order to do this, we need to use a very specific tag on the RecyclerView called descendantFocusability:

<androidx.recyclerview.widget.RecyclerView
   android:id="@+id/recyclerViewMenu"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:descendantFocusability="afterDescendants" />

By setting descendantFocusability to afterDescendants we ensure that automatically, once the views are dynamically generated, the RecyclerView itself provides focus to the items inside the RecyclerView (in this case, it gives focus to the categories defined inside the RecyclerView menu).

Note: it is important to apply this to all our RecyclerViews, as this automatically defines the relationship between the items. The great news is that we don’t have to manually define the relationship between each item because Android automatically takes care of that for us as a framework level feature.

We need to apply this to all the RecyclerViews in our right side layout as well.We need to define the Directional Navigation between each one of the RecyclerView (for sake of simplicity, in our example we defined 4 rows through 4 dedicated RecyclerView)

At the end, our RecyclerViews should look like this:

<androidx.recyclerview.widget.RecyclerView
   android:id="@+id/rowRecyclerView1"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:descendantFocusability="afterDescendants"
   android:nextFocusDown="@id/rowRecyclerView2" />

<androidx.recyclerview.widget.RecyclerView
   android:id="@+id/rowRecyclerView2"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:descendantFocusability="afterDescendants"
   android:nextFocusDown="@id/recyclerView3" />

<androidx.recyclerview.widget.RecyclerView
   android:id="@+id/rowRecyclerView3"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:descendantFocusability="afterDescendants"
   android:nextFocusDown="@id/rowRecyclerView4" />

<androidx.recyclerview.widget.RecyclerView
   android:id="@+id/rowRecyclerView4"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:descendantFocusability="afterDescendants"/>

Notice how the last RecyclerView, rowRecyclerView4, doesn’t have the next Focus down target. The reason for that is there is no further RecyclerView to navigate to.

Once we complete this step, we now have a fully navigable UI using the D-Pad. We can now look into how to properly touch-enable our interface by modifying the content of our RecyclerViews.

You can see how the UI is fully navigable using the remote even though the views are generated dynamically.

 

Step 3: Adding touch interactions for clicks: OnClickListeners

The next step is to add touch interactions when the user clicks on an item. Luckily for us, Android was built for touch in mind. To add click actions to our applications UI, we can use standard Android components which will allow us to cover both the D-Pad interaction and the touch interaction. 

The best and easiest way to implement click actions or touch actions on a view is to use the standard Android OnClickListener. OnClickListener allows both touch clicks and d-pad button clicks to be performed on a view. onClickListener triggers a method called onClick() where you can execute any desired operation.

Note: If you have implemented the click action on your or D-Pad based UI in any other way, you might need to add the OnClickListener on top of any custom implementation you have. This is to ensure D-Pad clicks and touch clicks both execute the desired operation.

While on a D-Pad style navigation the size of the view is not important, , it is very relevant for touch interactions. Therefore, it’s better to use larger views and areas in our UI to provide a good user experience.

In our simple application we are going to apply the OnClickListener to the layout itself and not to the views inside of the layout. This  could be achieved also by expanding the internal views to fill the entire layout area and apply the OnClickListener to the individual views like TextView or ImageView, however applying it to the entire layout it’s a simple solution that allows us to fulfil our goal and doesn’t require to change the look and feel of the UI at all.

The views are dynamic and created by the RecyclerViews, so we need to apply individual on click listeners to each one of the created elements of each RecyclerView.We do this by modifying the code for the RecyclerView adaptors, getting a reference to the layout of each individual item of the RecyclerView and applying the onClickListener in the onBindViewHolder() method of the adapter:

public class MenuItemsAdapter extends RecyclerView.Adapter<MenuItemsAdapter.ViewHolder> {

  private String[] localDataSet;

   /**
    * Provide a reference to the type of views that you are using
    * (custom ViewHolder).
    */
   public class ViewHolder extends RecyclerView.ViewHolder {
       private final TextView textView;
       private final ConstraintLayout menuConstraintLayout;

       public ViewHolder(View view) {
           super(view);
           // Define click listener for the ViewHolder's View
           textView = (TextView) view.findViewById(R.id.textView);
           menuConstraintLayout = view.findViewById(R.id.menuconstraintLayout);
       }

       public TextView getTextView() {
           return textView;
       }

       public ConstraintLayout getMenuConstraintLayout() {
           return menuConstraintLayout;
       }
   }

   /**
    * Initialize the dataset of the Adapter.
    *
    * @param dataSet String[] containing the data to populate views to be used
    * by RecyclerView.
    */
   public MenuItemsAdapter(String[] dataSet) {
       localDataSet = dataSet;
   }

   // Create new views (invoked by the layout manager)
   @Override
   public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
       // Create a new view, which defines the UI of the list item
       View view = LayoutInflater.from(viewGroup.getContext())
               .inflate(R.layout.menulayout, viewGroup, false);

       return new ViewHolder(view);
   }



   // Replace the contents of a view (invoked by the layout manager)
   @Override
   public void onBindViewHolder(ViewHolder viewHolder, final int position) {

       // Get element from your dataset at this position and replace the
       // contents of the view with that element
       viewHolder.getTextView().setText(localDataSet[position]);
       viewHolder.getMenuConstraintLayout().setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
             //In this sample app we are just logging the Click, 
//but here you could for example open a new Activity or select 
//a specific Category  

Log.e("Click ", "Clicked "+localDataSet[position]);
           }
       });
   }

   // Return the size of your dataset (invoked by the layout manager)
   @Override
   public int getItemCount() {
       return localDataSet.length;
   }
}

In order to show if an item is focused on or clicked, it’s important to use backgrounds and drawables that contain the different states in which a specific view can find itself.

This is easily achieved using a selector drawable, which can contain multiple states like focused and pressed (clicked)

Menuselectordrawable.xml (used as background for our Menu Layout)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_pressed="true"
       android:drawable="@android:color/holo_blue_bright" /> <!-- pressed -->
   <item android:state_focused="true"
       android:drawable="@android:color/holo_orange_light" /> <!-- focused -->
   <item android:state_hovered="true"
       android:drawable="@android:color/holo_green_light" /> <!-- hovered -->
   <item android:drawable="@android:color/background_dark" /> <!-- default -->
</selector>

In the menulayout.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/menuconstraintLayout"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/menuselectordrawable"
   android:focusable="true"
   android:focusableInTouchMode="true">

At this point, all of our UI views are clickable and will show a different background color when clicked on (blue) and when focused on (orange)

You can see the onClickListeners being correctly triggered via the remote control.

 

Step 4: Managing view focus between D-Pad and touch interactions

The next step is to build a consistent experience between the d-pad and touch interactions. This means making sure that the directional navigation works consistently if we are using a remote or if we are interacting using touch.

As we mentioned above, Android was built with touchscreen and touch interactions in mind.  This means that the underlying layer managing our apps UI and views is mostly touch-enabled already.

In Android, most of the views are visible and focusable by default. Actually, views inherit a parameter called focusable, which by default is set to “auto”, meaning that is up to the platform itself to determine if this view should be focusable or not. Views like Buttons, TextView, EditText are focusable by default as those are main UI components, while layouts and layout inflators are usually not automatically focusable by default, as they are usually used just to define the UI structure.

In order to make our app fully touch-enabled, we need to make sure that the most important views in our app are focusable, and also we need to make sure that they can be focused on when the customer uses touch.

For this reason, we are going to edit two parameters in our views: focusable and focusableInTouchMode.

Going back to our sample app, we created two new separate layouts which are used to populate the individual items inside the “Categories” RecyclerView and the “rows” RecyclerView.

 

We need to make sure that:

  1. The whole layout is treated as touch surface.
  2. We are enabling users to focus on the layout both using the D-Pad and touch.

We do this by setting both focusable and focusableInTouchMode to true.

 

menuLayout.xml (defines the individual content of the Categories on the left, which contains only a TextView)

<androidx.constraintlayout.widget.ConstraintLayout 
   [...]
   android:id="@+id/menuconstraintLayout"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/menuselectordrawable"
   android:focusable="true"
   android:focusableInTouchMode="true">

   <TextView
       android:id="@+id/textView"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
      [...] />

cardLayout.xml (defines the individual content of the Movies rows on the right. Each card contains a ImageView and a TextView)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
[...]
   android:id="@+id/cardconstraintLayout"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:background="@drawable/selectordrawable"
   android:focusable="true"
   android:focusableInTouchMode="true"
>

   <ImageView
       android:id="@+id/imageView"
       android:layout_width="150dp"
       android:layout_height="100dp"
       [...] />

   <TextView
       android:id="@+id/textView"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       [...] />
</androidx.constraintlayout.widget.ConstraintLayout>

By doing this, we ensure that if the user touches the UI or if they navigate through the d-pad controllers, in both cases the right UI element will be focused on. See clip below for a demonstration.

In this clip you can see how the views are correctly clicked and focused on using touch interaction.

 

Step 5: Additional best practices and testing Touch on Fire TV

After completing the steps above, we will have successful touch-enabled the most important components of our app UI.

There are additional simple steps to ensure that we are providing a great user experience for both touch and d-pad navigation:

 

  • Ensuring that all the views that need any kind of interaction have an OnClickListener assigned to them and can be focused on
  • Remember that touch interaction also includes the gestures and scrolling. Therefore do not just rely on the standard behaviours of views using D-Pad Navigation but make sure that least include ways to be scrolled through gestures (for example using scroll views and RecyclerView is where possible).
  • Secondary activities of your applications (for example a Detail page or the Playback UI) need to be also touch enabled so make sure that if you have any settings page those are touch enabled as well and use the same patterns described above.

 

How can you test Touch on Fire TV devices without a touchscreen?

The easiest solution is to connect a wireless mouse to your Fire TV. Mouse on Android simulates touch interaction. You can do this by:

  1. Going to Settings
  2. Go to Remote and Bluetooth Devices
  3. Go to Other Bluetooth devices
  4. Follow the on-screen instructions on how to connect your Bluetooth mouse
  5. After connecting the mouse, go back to your app. The mouse will show a cursor on screen you can use to simulate touch interactions, including clicks and gestures.

 

Conclusion

This tutorial gave you a practical first overview on how to touch enable your Fire TV application. 

For more details on these please check out our documentation:

In-App Search using the Video Skills Kit (VSK) on Fire TV

 

Video Skills Kit (VSK) for Fire TV allows customers to more easily discover, find, and engage with content in your app without relying on a remote. A prerequisite to integrating your app with the VSK is to first ingest your catalog and then integrate with Universal Search and Browse on Fire TV. Catalog integration is currently only available to selected developers. VSK works together with Catalog Integration to surface your content in multiple ways across Fire TV.

VSK allows you to voice-enable the experience in your app. Customers can say “Alexa, watch Batman” (SearchAndPlay) or “Alexa, find Batman” (SearchAndDisplayResults) and Alexa will send a directive to your app, where you can take the customerinto playback or show search results. Customers can skip the use of a verb and simply say “Batman“, which is treated by Alexa as a search request. Alexa also supports more ambiguous requests such as “Alexa, find Tom Hanks movies” to find movies by actor, or “Alexa, find comedies” to search by genre.

 

How does VSK work on Fire TV?

With the App-only implementation for VSK, the Alexa Video Skill API sends directives directly to your app on a Fire TV device. Fire TV has a service called the “VSK Agent” that receives the Alexa directives and broadcasts them as an intent, which your app then handles through a BroadcastReceiver. The entire VSK integration is done directly within your Android code. If you already have Catalog Integration completed, and your app already has logic to handle text inputs for searches and other lookups, the integration can be completed in a short amount of time (a couple of weeks or less).

Alexa service in the cloud does the hard work of interpreting the customer’s request, determining the intent, and then packaging it into a directive so that you can process the requests with your own app’s logic. Directives sent to your app contain a structured and resolved representation of the request, where we include entitles such as Video, Actor, Genre and MediaType. See SearchAndPlay and SearchAndDisplayResults for a more comprehensive list of search and play utterances and the directives sent.

 

Best practices for building a great search experience

Here are some of the best practices for building a great search experience using VSK.

  • Declare search as a static capability if your app allows all customers to browse content regardless of the customer’s state (signed in) and other factors (subscription level). Otherwise, you can declare search as a dynamic capability to gate the feature.
  • Customers can say “Alexa, find Breaking Bad season 2 episode 3” to search (or watch) a TV series by Season and Episode. You can use Season and Episode fields to take the customer to the episode. If you’re missing either season or episode number, you should determine this based on the customer’s last watched episode.
  • Customers can say “Alexa, find Tom Hanks movies” to find movies by the actor, or “Alexa, find comedies” to search by genre. You have the option to show search results using the Actor, Franchise or Genre fields, or take the customer to special pages dedicated to that particular entity. If your app does not support lookup by these fields, you should fallback to a literal text search of the value sent through in the directive.
  • Leverage the SearchText field to help improve the relevancy of results that customers see in your app. For ambiguous requests (those that do not contain a title name), search text will give you an unstructured and more complete view of what the customer has asked – this includes additional entities and unresolved words. For example, “Alexa, watch popular comedy tv shows in HD” will give you the transcribed value “h.d. popular comedy tv shows”. Note that there is no word order or formatting guarantee. See SearchText for more information.
  • Search results that you present to the customer should include relevant artwork applicable to the titles. The artwork should make it easier for the customer to identify the content you are recommending in the search.

 

Handling SearchAndDisplayResults directives

Here is a SearchAndDisplayResults directive Alexa might send in response to a customer’s request to search for “Alexa, find Batman”.

EXTRA_DIRECTIVE_NAMESPACE: Alexa.RemoteVideoPlayer
EXTRA_DIRECTIVE_NAME: SearchAndDisplayResults
EXTRA_DIRECTIVE_PAYLOAD_VERSION: 3
EXTRA_DIRECTIVE_PAYLOAD: payload

payload contains the following:

{
    "payload": {
        "entities": [
            {
                "externalIds": {
                    "ENTITY_ID": "0"
                },
                "type": "Franchise",
                "uri": "entity://avers/franchise/Batman",
                "value": "Batman"
            }
        ],
        "searchText": [
            {
                "transcribed": "batman"
            }
        ],
        "timeWindow": {
            "end": "2016-09-07T23:59:00+00:00",
            "start": "2016-09-01T00:00:00+00:00"
        }
    }
}

With VSK integration, you create a BroadcastReciever class in your app. The VSK Agent packages the directive in an intent, which is passed into the onReceive method. With the support of a JSON parser, you can retrieve both the customer’s transcribed search request under transcribed and the entities object, which contains an array of entity objects to search, such as a Title, Genre, Actor, Franchise, Season, Episode, or MediaType. In this example, you should show the customer search results for “batman” in your app.

Once your app handled the directive successfully (or not), your BroadcastReciever class should send a success intent back with a status in the form of a true (for success) or false (for failure) value.

 

Get Started

Learn more about integrating VSK through our the developer documentation here. You can also follow this high-level video tutorial about integrating the VSK into your Fire TV app.

Coming Soon: Amazon Appstore Small Business Accelerator Program

Authored by Palanidaran Chidambaram, Director, Amazon Appstore

 

To further support our developers, today we are announcing the Amazon Appstore Small Business Accelerator Program. This new program enables developers to build a scalable business by reducing cloud infrastructure costs, while also offering better revenue share to help them get started on their own day one.

Starting in Q4, for developers that earn less than $1 million in revenue in the previous calendar year, we are increasing developer revenue share and adding AWS credit options. This brings total program benefits up to an equivalent of 90 percent of revenue. 

When the program launches, all qualifying small developers will receive an 80/20 revenue share by default. Additionally, we will provide AWS promotional credits in an amount equivalent to 10 percent of revenue, so that developers can take advantage of the benefits of building on the cloud.

By helping small businesses get started with AWS through credits, we are making it easier for them to build and grow their app businesses. AWS gives developers easy access to a broad range of technologies so they can innovate faster and build nearly anything they can imagine.

In a recent survey of mobile developers over 94% indicated they use cloud services in their application development efforts.

With AWS, developers can access more than 200 fully featured services so that they can spend less time managing infrastructure and can focus more attention on customer feedback and growing their app businesses. They can deploy technology services in a matter of minutes, and get from idea to implementation several orders of magnitude faster than before.

We also will help developers promote their content in new ways by highlighting smaller developers within our Appstore experience via a new dedicated application row.

We believe these investments in our global developer community will generate more innovation within Amazon Appstore and increase the selection of apps for our customers.

The Small Business Accelerator Program is one of many projects we are undertaking to grow and support the developer community across Amazon so that developers of all sizes can continue to build for our Appstore and for our customers. We’ll have more implementation details to announce later this year.

 

Thank you for building with us.


FAQs:

 

How does eligibility for the Appstore Small Business Accelerator program work?

  • Developers who earned up to $1 million in the prior calendar year and developers new to Amazon Appstore are eligible.
  • If an eligible developer’s revenue exceeds $1 million in the current year, they will revert to the standard royalty rate and no longer receive AWS credits for the rest of that year.
  • If a developer’s revenue falls below $1 million in a future year, the developer will be eligible in the next calendar year.

 

How will the AWS credits work?

Developers with less than $1 million in Appstore revenue in a calendar year will receive 10% of their revenue as promotional credit for AWS services from infrastructure technologies like compute, storage, and databases–to emerging technologies, such as machine learning and artificial intelligence, data lakes and analytics, and Internet of Things. To receive the credit, when the program launches, developers can provide their AWS Account ID in the Appstore developer portal. The credit will be sent monthly and developers can choose which eligible services to apply the credit to.

 

How long are the AWS credits valid?

The AWS promotional credits can be used for 12 months from the date they were granted.

新世代「Fire HD 10」と「Fire HD 10 Plus」が登場:Fire OSに2画面表示機能を新搭載

(本ブログは、こちらの英語記事を翻訳したものです)

 

Amazonは4月27日(火)、新世代タブレット「Fire HD 10」と「Fire HD 10 Plus」を発表しました。エンターテインメントやビデオ通話をワイドスクリーンで楽しめる洗練されたデザインになっています。映画はもちろん、ZoomやAlexaでの通話や、ウェブブラウジング、ゲーム、読書など、この新しいタブレット1台で日々のあらゆるシーンに対応可能。家族や友達とも手軽につながることができ、新機能としてマルチタスクを可能にする2画面表示機能も搭載されています。また今回の発売に合わせて、取り外し可能なMade for Amazonのキーボード付きカバーが新たに登場。生産性アプリの数も拡充されています。

この新世代タブレットは開発者の皆さまにとっても、新規ユーザーとの関係を築いたり、アプリの利用・リーチを促進したりなど、新たな価値の創出に役立つはずです。

 

生産性アプリの高まるニーズ

Fireタブレットシリーズはこれまで、主にゲームやエンターテインメントの用途で使用されてきましたが、2020年になって業務効率化やコラボレーションの促進に役立つアプリが人気を博してきました。昨年、Amazonアプリストアにおける生産性アプリのユーザーエンゲージメントが前年比226%向上を記録。同アプリの月間アクティブユーザー数も昨年をとおして62%増加しました(本ブログでの指標は、全世界における数値を基にしています)。キーボード付きカバーとMicrosoft 365 Personal 1年版がセットになった「エッセンシャルセット」(Fire HD 10版Fire HD 10 Plus版)で、快適な入力操作と生産性アプリをぜひお試しください。

Fireタブレットでのマルチタスクに役立つアプリを開発するなら、今が絶好の機会です。やることリストの作成やリマインダーの設定、Eメールへの返信、コラボレーションの促進などを行えるアプリを開発している場合は、Amazonアプリストアでの配信をご検討ください。利用を促せるよう、アプリを新機能に対応させることも大切です。

 

Fire OSの新機能:2画面表示機能

Fire HD 10タブレットには、Fire OSの新たな機能として、2画面表示機能が搭載されています。10.1インチのディスプレイで、2画面表示に対応している2つのアプリを同時に開くことができるほか、ウィンドウ間でファイルをドラッグアンドドロップすることも可能です。この新機能の登場でマルチタスクが容易・快適になり、アプリのエンゲージメント向上も見込めます。

2画面表示機能の実装については、2画面表示機能のサポート宣言をご参照ください。

 

性能と耐久性の向上

新Fire HD 10は、高速かつ応答性に優れたパワフルなタブレットです。オクタコアプロセッサを搭載し、RAMも前世代機より50%増量。2メガピクセル以上の解像度で10%明るくなったディスプレイで、アプリを鮮やかに表示することができます。
新タブレットの詳細や開発に関しては、 以下のリソースをご参照ください。

 

 

Tips & tricks for Adobe Primetime Single Sign-On (SSO) on Amazon Fire TV

 

Have you have followed the Adobe Primetime Single Sign-On (SSO) integration documentation, but it’s not working as expected?

A common problem that users face is when they are not able to select a Multi-Channel Video Programming Distributor (MVPD) to log into from a list of MVPDs within your app. Another scenario is users who have successfully logged into a selected MVPD, but keep getting asked to log in every time they try to play content within your app.

The tips in this blog will help you get past some of these very issues.

 

Recap of SSO on Fire TV

SSO allows customers who authenticate in one SSO app to not have to authenticate again when logging into another SSO-enabled app. Adobe provides the Primetime authentication API to facilitate this method of authentication for third party TV Everywhere (TVE) apps on Fire TV.

Adobe provides Fire TV client developers with a stub library with its APIs. Developers need to use Fire OS system level APIs to retrieve a personalized token and use it when calling Adobe APIs. And, the Fire OS system level APIs are encapsulated within a Fire TV system app, called the SSO companion app.  

Here is a set of diagrams that explains the SSO workflow.

There are 4 key steps in the SSO workflow:

  1. Initialization: The Android client application initiates Adobe Primetime authentication using the Adobe Primetime authentication native Amazon Fire OS library (AccessEnabler).
  2. Authentication: This starts the authentication flow, or gets confirmation that the user is already authenticated.
  3. Authorization: This is the authorization flow and ensures that the user is authenticated and authorized to watch the requested media. It returns a short media token.
  4. Media token issuance: The short media token is then validated. If valid, it is issued to the Android client application and the media is played for the user.

Here is a breakdown of each of these steps in the SSO process.

Step 1: Initialization

In this step, the Android client application initializes the Adobe Primetime Authentication native Amazon Fire OS library (AccessEnabler) that has been integrated with the application. It establishes the identity of the application using a personalized token, and then proceeds to the Authentication flow.

 

Step 2: Authentication

The Android client application now starts the authentication flow, or gets confirmation that the user is already authenticated. If the user is not authenticated, the user is presented with a list of MVPD providers. After the user selects a provider, the provider page is opened for the user to login. Upon successful login by the user, the authentication token is retrieved from the backend Adobe server. The token is validated and the user proceeds to the Authorization flow.

Step 3: Authorization

The Android client application next gets the authorization token, and then validates the authentication and authorization tokens. This means checking whether the user is authenticated and authorized to watch the requested media. If there is an authentication (AuthN) error, then the authentication flow is re-started. If there is an authorization (AuthZ) error, then the user is not authorized to watch the requested media and a relevant error message is displayed to the user. If authorization is successful, a short media token is returned by Adobe’s server.

Step 4: Media Token Issuance

Next, the short-lived media token returned from the authorization flow is validated by the Adobe server. If the validation succeeds, the Android client application plays the requested media for the user. However, if the validation fails, The AuthZ token was invalid, the media request is refused, and an error message is displayed to the user.

Now that you have an overview of how the SSO process flow works, let’s get into some of the issues you can face and how to solve them.

 

Tip #1: App not authorized to use SSO on Fire TV

A common SSO error, as we mentioned above, is that when users select a valid MVPD provider (see figure Step 2: Authentication) to log into in order to play their content, instead of seeing the MVPD provider’s login page, they loop back into the provider picker page.

 

The user is following the entitlement steps in this workflow (also see figure 1: High-Level Single Sign-on Flow).

Your call to authenticate the user initially should successfully log the user into to a selected MVPD using valid credentials and store the returned authentication token in the backend server. Subsequent call(s) to authenticate should ideally get confirmation that the user is already authenticated, and the user should then be authorized to single-sign on into the app. However, these calls fail, and the user keeps getting asked to login into the MVPD.

This error may simply be a function of your app not being authorized or allow-listed to use Single-Sign-On (SSO) on Fire TV platforms.

In the workflow in Figure 1, before the SSO companion app checks if the authentication is complete, under the hood, it checks to see if the app is allow-listed, i.e. whether the app is authorized to use SSO on Fire TV. If not, it does not allow the user to proceed beyond the MVPD list display page.

To determine if this is indeed the reason for the login issue, look for the following error in your device logs:

E/OttSso_OttSsoService: Trying to verify app com.yourappname.yourpackagename but Approved apps list size is 0.

This error means that your app needs to be authorized to use SSO on Fire TV platforms. Please work with your Fire TV Solutions Architect at Amazon to get this done.

Once your app package name has been authorized for SSO, you need to wait for 24 hours for the device cache to be refreshed. If you are still facing the same error, check your package name. Please note that both the debug and production package names need to be allow-listed.

If you are still running into the same errors, you will need to clear the companion app cache manually with the following commands:

adb shell pm clear com.amazon.tv.ottssocompanionapp
adb shell am force-stop com.amazon.tv.ottssocompanionapp

Now when the user goes through your app login workflow again, instead of the E/OttSso_OttSsoService error in your device logs, they will be able to log in successfully with valid credentials. And the following line will appear in the device logs as proof that your app is now allow-listed for SSO on Fire TV:

I OttSso_OttSsoService: app setup complete, number of approved apps 

 

Tip #2: Adobe SDK and SSO Companion version mismatch

The Adobe SDK that your app has integrated with is a stub library which makes calls to the SSO companion system app on Fire TV to deliver SSO functionality. For SSO to work correctly with your apps on Fire TV, both the SSO companion app and the Adobe stub library integrated within your app should always be up-to-date with their most recent versions.

To check the version of this app via ADB, use the following command:

Mac:

adb shell dumpsys package com.amazon.tv.ottssocompanionapp | grep versionCode

Windows:

adb shell dumpsys package com.amazon.tv.ottssocompanionapp | find /I "versionCode"

Results:

Old version output:

In the example stated above, the last updated version number of the SSO companion app on this specific device is 4810. However, the latest version of the Adobe SDK requires the system SSO companion app to be of version number 5510 or greater. To update the SSO companion app in SMP devices, go to device Settings->My Fire TV->About->Check for Updates. In Fire TV Edition devices, go to device Settings->Device & Software->About->Check for Updates. Run this command repeatedly, until there are no more system updates left to be received. When you run your adb version command again, the results should now be as follows:

To prevent your app users from facing SSO issues because they have not updated their device system OS recently, the app should perform a version check and nudge the users to update their app and device OS.

 

For more information about Single-Sign On, please see this documentation on Adobe Primetime Authentication Fire TV SDK.

 

Authored by Priya Rajan, Amazon Solutions Architect

Amazon Fireタブレット:生産性アプリの高まるニーズとエンゲージメント

(本ブログは、こちらの英語記事を翻訳したものです)

ここ数年、職場と自宅の境目が曖昧になるにつれ、Amazon Fireタブレットで生産性アプリを活用するユーザーが増加しています。メモ・カレンダー・タスク管理といった、プライベートの管理や業務効率化、コラボレーションの促進に役立つアプリが人気です。2020年には、Amazonアプリストアにおける生産性アプリのユーザーエンゲージメントが前年比226%向上を記録同アプリの月間アクティブユーザー数も昨年をとおして62%増加しました(本ブログでの指標は、全世界における数値を基にしています)。ユーザーの働き方・生産性の保ち方が大きく変わった今、生産性アプリのニーズは今後も伸び続けると思われます。

このトレンドにアプリをどう対応させ、ユーザーの生活をより良いものにできるか。どのようなアプリがFireタブレットユーザーのニーズを満たすのか。これからアプリ開発に役立つ分析情報をご紹介します。
 

プライベートの生産性向上につながるアプリ
世界中で日々使用されているFireタブレット。現在、エンターテインメントやゲームのアプリだけでなく、プライベートの管理や生産性向上を目的としたアプリのニーズも高まっています。

Amazonアプリストアには全世界で10,000点を超える生産性アプリが公開されています(2021年3月時点)。その中でも、パソコンを開かずにTo Doリストやリマインダーの作成、Eメールの返信といったタスクを簡単に実行できるアプリが特に人気です。Fireタブレットユーザーは多忙を極める中、このようなアプリを駆使して生産性を向上させています。

仕事関連の生産性アプリ
2020年は特に、Eメール・ビデオ・スプレッドシート・ドキュメントなど、リモートワークに役立つ仕事関連の生産性アプリが普及しました。ユーザーが業務の迅速化と効率化を図る中、世界中の開発者がそうしたニーズに対応するアプリの開発に取り組んでいます。Amazonアプリストアでは昨年、仕事関連アプリの申請数が135%増加しました。
 

コラボレーションや創造性を促進するアプリ
現代のバーチャルな環境において、コラボレーションや創造的なアイデアを促すことは簡単ではありません。Fireタブレットでは昨年、ブレインストーミング・描画・コラボレーション・会話に関連するアプリを使用するユーザーが30%増えました。教育や在宅学習に関連するビデオ・コラボレーションアプリも、2020年以降ニーズが25%以上高まっています。

Amazonデバイス対応の生産性アプリを初めて開発する場合でも、Amazonアプリストアでは簡単にFireタブレット対応アプリを公開・配信することができます。Fireタブレットには、Fire OS 7(Android 9 Pieベース)が搭載されていて、Amazonのアプリテストサービスを利用すれば、短い時間でAndroidアプリの互換性テストを行えます。詳細はこちらをご参照ください。Amazon開発者アカウントを作成して、さっそく始めてみましょう。

Amazonアプリストアで公開中のアプリをアップデートして、Fireタブレットの最新モデルに対応させる方法については、以下のリソースをご確認ください。

Amazonアプリストアの生産性アプリに関する最新情報(英語のみ)をご希望の方は、こちらをクリックしてください。

 

New Fire HD 10 tablets and Fire OS split screen feature

Today, Amazon announced a new lineup of Fire 10 HD tablets, the all-new Fire HD 10 and first Fire HD 10 Plus, with an updated design built for widescreen entertainment and video calls. Whether it’s watching movies, making Zoom or Alexa calls, browsing the web, playing games, reading books or magazines – this new tablet is designed to keep customers enjoying downtime while connecting with family and friends. As part of the new Fire tablet launch, Amazon also introduced a new, detachable keyboard case, split screen multitasking, and an enhanced productivity app selection.

For developers, this creates new, interesting opportunities to engage with new customers, grow usage, and broaden app reach.

Increased focus on productivity
Historically, Fire tablets have been used by customers primarily for gaming and entertainment. However, during the course of 2020, as customers looked to get work done faster and collaborate across teams virtually, we saw a 62% increase in productivity app users month over month across the Tablet Appstore, and a 226% growth in app engagement amongst productivity customers. Enter the Productivity Bundle, featuring an all-new Bluetooth keyboard with detachable case, balanced for stability and comfortable typing.

As a developer, now is a great time to think about how your apps can help customers multitask on their Fire tablets. If your app can help someone create a to-do list, set a reminder, respond to an email, or encourage collaboration, consider adding it to the Amazon Appstore, or ensuring it’s up to date to drive greater usage amongst customers.

New Fire OS feature: split screen
The Fire HD 10 tablet introduces the new split screen feature for Fire OS. Customers can open two compatible apps side-by-side on the 10.1“ display as well as drag and drop files and objects between windows. It’s multitasking made easier and an app engagement win for developers.

Check out the split screen technical documentation to get started implementing the features.

Increased performance and durability
For gaming and entertainment developers, the new Fire HD 10 Plus is our most powerful tablet to date. With 50% more RAM, a powerful octa-core processor, and a 10% brighter display with over two million pixels, your apps will look sharper and be more responsive.
 

Interested in learning more or ready to get started developing? Check out these resources: