Amazon Developer Blogs

Amazon Developer Blogs

Showing posts tagged with Android

May 08, 2015

Ankur Prasad

How can I get started with Android development even though I don’t have any experience with mobile programming? – We are often asked this question by aspiring app developers.

The Programming Mobile Applications for Android Handheld Systems offered by Coursera, an online learning provider with over 12 million students, is a great place to get started. The course includes short video lectures, interactive quizzes, programming labs, and peer review assignments, supported by active communities of learners and instructors. The latest edition of the course kicked off on Wednesday, May 6th. You can enroll anytime within the next two weeks to get started on your journey to become an Android developer.

Exclusive Offer for Amazon Developers From Coursera

We are also excited to announce an exclusive offer for all course participants. Enroll in the course today and create a free Amazon developer account to get free access to:

The HTML and CSS for Beginners with HTML5 eBook

The HTML5 Mobile Game Development by Example online tutorial

How to Get Started

Go the  Programming Mobile Applications for Android Handheld Systems course home page. Login to your Coursera account. If you do not have an account, create one for free in couple of minutes. Enroll in the course by clicking on the Join for Free button. You will learn how about app stores, how to create a developer account and receive details on how to participate in the Amazon Appstore offer to receive your rewards as part of the course work.

 

Continue on Your Journey!

This is part of a series of six courses that provides a comprehensive overview of the Android platform, starting with Android fundamentals, such as activities, fragments and user interfaces, more advanced features, such as notifications, animation and working with sensors, to advanced topics, including Android concurrency and services, to security and cloud integration.

This is an excellent resource for any developer wishing to enter the growing mobile app industry. We’ve seen lots of great apps come out of this program. By completing the entire series of courses, you’ll have the opportunity earn a verified certificate from Coursera as well.

 

 

November 10, 2014

Corey Badcock

Vision Mobile recently shared a new chart showing a higher percentage of Amazon Fire developers above the app poverty line versus other platforms. More specifically, 59% of developers distributing their apps on the Amazon Appstore make more than $500 per month versus <50% on other platforms. Tweet: 59% of #devs distributing #apps to Amazon #Appstore make more than $500 per month versus <50% on other platforms http://ctt.ec/9Y1Z3+ The chart also showed that developers continue to experience increased monetization in the Appstore - Amazon had a bigger proportion of developers making $5,000+ a month compared to developers on other platforms. Tweet: #Amazon #Appstore had a bigger proportion of #developers making $5,000+ a month compared to #devs on other platforms http://ctt.ec/05hxK+ We’re excited to see developers like you expand their reach and monetize apps through the Amazon Appstore.

VM Graph

Today the Amazon Appstore is available on more than just Fire devices including the all-new Amazon Fire TV Stick. The Amazon Appstore for Android is also pre-loaded on BlackBerry 10 devices and carriers including O2, EE, Deutsche Telecom and others on millions of Android devices. This wide reach gives your app access to even more customers. Plus, the latest Amazon shopping app fully integrates apps and games into the shopping experience enjoyed by millions of customers. So when customers are searching for products in the Amazon shopping app, they’ll also discover relevant apps and games that they may also enjoy.  Here’s what some developers are saying about their experience with Amazon:

“When we compared our 2014 data, we noticed that ARPU on Amazon was 70% higher than on Android and 15% higher than on iOS”. Tweet: “When we compared our 2014 data, we noticed that #ARPU on Amazon was 70% higher than on #Android and 15% higher than on #iOS”. @AmazonAppDev                                                                         

– Elad Kushnir, VP of Business Development at Playtika

 

“The Average Revenue Per Download (ARPD) on Amazon is actually higher than on Android.”Tweet: “The Average #Revenue Per #Download (ARPD) on #Amazon is actually higher than on #Android.”  @AmazonAppDev   

– Jean-Baptiste, CEO at DJIT

Check out the infographic below to learn more about where your apps will be available once you distribute them on the Amazon Appstore then get started and submit your apps here.

P.S. The holidays are the best time of the year to submit your apps. Read our latest blog post to learn more: Three Important Stats About Holiday Device Sales

 

 

July 10, 2014

David Isbitski

With the launch of the Fire, Amazon’s first Android-based phone, you can now create experiences where customers interact in an entirely new way with your apps. With Dynamic Perspective, apps can have peek, tilt and zoom capabilities all based on customer head movements. You can also use the Firefly button to identify virtually anything and enable actions your customers can take based on what they identify. By enhancing or optimizing your apps for Fire, you have the opportunity to enable experiences that combine realistic visuals and bring new depth to what customers can do on a phone. And while you think about the new experiences you can offer your user, you can get the current version of you app running on Fire with little or no modification. Here are 10 tips to help you get your apps running on Fire phone today!

Tip 1 – Register for a Free Amazon Developer Account

Fire uses the Amazon Appstore exclusively, and we’ve streamlined the process to make it easy to submit your app. Registration is free, fast, has no annual subscription cost, and supports both free and paid apps. Once your Fire phone app is submitted you also have the option to distribute the apps across Kindle Fire, Fire TV and Android devices simply by selecting those device targets in the developer console. The boxes indicating your intent to publish on other devices will be pre-checked in the console. Most Fire apps will also work on Kindle Fire tablets and Android devices, so just keep those checked if you are not sure. To get started:

  1. Sign in or register for a free developer Amazon Apps & Games Developer Portal account. If you do not already have one, you will be prompted to create an account
  2. Submit your payment and tax information if you intend to sell a paid app or offer in app items for purchase.

Tip 2 – Download the Fire SDKs

Fire phone development APIs fall into two categories: Dynamic Perspective SDK and Firefly SDK. Both SDKs are available through the standard Android SDK Manager as a single add-on and support a variety of programming languages.

To download the add-on simply open the Android SDK Manager from a command line or from within Android Studio and do the following:

  1. Add the following user-defined site, in the Manage Add-on Sites dialog: https://s3.amazonaws.com/android-sdk-manager/redist/addon.xml
  2. Expand Android 4.2.2 (API 17) and click SDK Platform and Amazon Fire Phone SDK Addon.

Macintosh HD:Users:dave:Desktop:Screen Shot 2014-07-01 at 9.34.32 PM.png

  1. Accept license agreement and install the packages.
  2. Set your project up in Eclipse and specify Amazon Fire Phone SDK in the Compile With drop-down.

The SDK includes everything you need to get started including multiple sample projects and Android Studio gradle support.

You also have the option to download the Fire Phone SDK directly without installing the add-on here.

Tip 3 – Test Your APK compatibility with the Amazon Testing Service

Fire is based on the latest version of Fire OS 3.5, which is based on Android API level 17. Android app compatibility is supported on Fire OS, so if an app runs on Android it can run on Fire with little or no effort. Simply drag and drop your Android APK and receive feedback on your app's compatibility within 90 seconds. You will also have access to additional Fire phone test results that enable you to see how your app looks and performs on Fire phone. The test results are presented in 6 hours and include carousel, peek and tilt actions.

Checking APK compatibility and submitting can be done in just a few steps:

  1. Drag and drop your APK to the app-testing control here.
  2. If your app passes testing, you can submit it to the Amazon Appstore right away. If testing reveals any issues, you will see a list of issues to address. 

Tip 4 – Become Familiar with the Fire Phone Design Guidelines

Fire represents a huge leap forward in mobile user experiences. As a developer, you’ll want to design the best customer experience possible for this new platform. To help you achieve that, we’ve outlined the core design principles that will allow you to take advantage of Fire’s unique Dynamic Perspective features in our guide here.

The good news is that if you are an Android developer your app will work on Fire with little or no work, and as you will see, just a few modifications to your app’s user experience will let it better take advantage of all that the Fire SDK has to offer.

For additional best practices for designing Fire phone user experiences check out our blog post here.

Tip 5 - Add the Fire Phone Android Theme to Your App

The quickest optimization you can make is to set the application Theme in your Android app’s AndroidManifest.xml file. This updated Amazon theme will set app fonts, color pallet and skinned controls to match Fire phone’s design guidelines.

Simply set the android:theme argument to the application section of the Android Manifest to Theme.DeviceDefault, as introduced in Android 4.0, and your application will pick up the skinned controls that match Fire phone.

Tip 6 – Utilize the Fire Foundation Controls

The Fire Foundation Controls are included in the Dynamic Perspective SDK and give your app 2D controls designed and built for use with the device. These controls currently include SidePanel, HeaderNavigationBar, TabBar, ToolBar and MediaController. All of these controls can be implemented in three steps just as you would with any Android control.

Step 1: Prepare the Android Manifest
The Android manifest needs to be modified to include a <uses-library> tag to load the Foundation Controls library (in addition to setting the theme as mentioned in Tip 3).


 

Step 2. Place the control in your XML Layout file

In this example Android layout file we are referencing the new header navigation bar and utilizing two additional files. Strings.xml will contain the names of our menu items and header_menu.xml file defines the menu items for the HeaderNavigationBar's actions menu.

XML layout for HeaderNavigationBar inside of a RelativeLayout view:

Strings.xml containing menu item names:

Header_menu.xml containing action menu items:

Step 3. Implementing the Control

All of the APIs for Fire phone will be installed into your <Android_SDK>/sdk/add-ons/addon-amazon_fire_phone_sdk_addon-amazon-17 folder including the SDK samples. To access the controls you will need to reference them from your own app. For example, to implement the HeaderNavigationBar make sure you reference the amazon.widget.* package and implement the control. The following code shows how to inflate the XML layout into a view, obtain a reference to the HeaderNavigationBar, use the reference to set a click listener on the actions menu, and implement up navigation.

In the case of the HeaderNavigationBar we will also disable the Android title bar before inflating the layout. We can also programmatically change menu items by setting properties directly on the HeaderNavigationBar like so:

For more details on implementing Foundation Controls in your Android app check out our Implementing Foundation Controls for Fire phone guide here.

Tip 7 - Implement a Side Panel Layout

One easily identifiable layout characteristic of Amazon Fire apps is the Side Panel layout included as part of the Fire Foundation Controls. Implementing the Side Panel layout will go a long way to giving your app that Fire phone look and feel.

With this control, no matter what the current view in your app, a user can always access your menu or a context aware page just by executing a quick swipe or gesture.

For example, doing a quick right-flick of the phone (or swiping in from the left) can expose a navigation pane. You can also put a context-sensitive pane a flick away in the other direction. In the picture above, the middle content panel is a Music Store. The left panel is a navigation panel, and the right panel is context sensitive, and when the user is looking at music in the content panel, the right panel will show recommendations.

SidePanel Layout works very similar to the HeaderNavigationBar described above. You will need to reference the EAC library in your Android Manifest like above, reference the same amazon.widget library in your java code and then define the left, right and content panels in your XML layout file.

A full Side Panel sample project is included with the Fire SDK under the /Samples/SidePanels folder and you can get more details about implementing a Side Panel layout here

If you don't have a Fire phone you can also use the simulator included in the SDK to test your SidePanel implementations.

Tip 8 – Adding Depth and Perspective to Your Android App Interface

In addition to the 2D Foundation Controls, Dynamic Perspective includes a rich set of APIs and Controls to help developers incorporate peek, tilt and zoom capabilities within their apps while adding a sense of realistic depth and perspective. These controls work behind the scenes with Fire’s advanced camera and sensors to automatically adjust their appearance based on how your application is being viewed. These new UI Controls are part of the Euclid package included in the Fire phone SDK.

For the most part, Euclid controls are very similar to their Android and Foundation Controls counterparts. Euclid controls retain the name of the original base control, but with a "Z" prepended to the name. For example, a Button control becomes a ZButton control.

       

Figure 1- Example of Euclid Controls. From left to right: ZCheckbox, ZButton, ZSwitch and ZRadioButton

Euclid simplifies the process of adding 3D effects to your Android apps. Because most Euclid layout and widget classes are derived from either standard Android or Amazon Foundation Control classes, you are probably already familiar with the most common methods and attributes of Euclid controls and should be able to convert your app to use the new Dynamic Perspective UI with few code updates.

The following aspects of a control remain unchanged when you swap a stock Android control for its Euclid equivalent, such as changing a Button to a ZButton:

  • Click handler methods: User interaction is handled via your existing onClick() method or View.OnClickListener object.
  • Screen position methods: Layout in the X and Y planes follow the same rules as 2D widgets.
  • Layout methods: Euclid controls follow Android rules for scaling, sizing, and padding, and auto-resize based on layout parameters.
  • Support methods: Euclid controls often inherit Android widget support for testing, accessibility, and localization.

The biggest difference between Euclid and 2D widgets is how their visual assets are produced and rendered. These differences provide new behaviors but also set some limits on what you can change. Euclid widgets are artist-created textured mesh files, including collections of vertices, edges and faces that define the shape of 3D objects.

Although you can set the color of a 3D widget, you cannot add a border, set a custom background, or make changes in View.OnDraw(). However, 3D controls do provide the same access to behaviors such as animations and head tracking without additional code.

The following summary highlights the changes between 2D and 3D controls:

  • Layout parameters: 3D object layout parameters include depth in addition to height and width. While 2D Android layouts are a nested hierarchy of flat rectangles, 3D layouts are a nested hierarchy of rectangular boxes.
  • Delegate classes: All 3D methods are passed to delegate classes to handle 3D operations, such as layout and animation. You do not need to extend the delegate classes unless you want to modify the stock control animations or layout.
  • Missing or overridden class methods: Some 2D Android base class methods have been removed from the 3D controls because these methods are either not relevant to a 3D environment or have been replaced with true 3D paradigms. For example, stock Android controls support rotation using a faux 3D mode, whereas Euclid replaces these methods with a simplified 3D orientation method.
  • Draw method: Because they are not rendered dynamically, 3D controls do not directly use the Draw method. Instead, you must build a tree of transformations and execute a drawing command using ZSceneNode and ZRenderable. This retained approach better matches the model of the underlying 3D graphics library. Note that this change is transparent if you are using the stock 3D controls in the toolkit.
  • Unsupported base class attributes: Some 2D base class attributes are not supported in 3D, such as the Android faux shadow parameter. See the API reference documentation for information about specific control attributes.
  • 3D-specific methods and attributes: 3D controls have 3D-specific methods and attributes, such as the ability to supply layout attributes using orientation_Zin a linear layout or depthGravity.

For more information on implementing Euclid controls be sure to check out our Dynamic Perspective UI Migration Guide here. For suggestions on when to use the standard Android widgets, 2D controls and the new Euclid controls check out our comparison matrix here.

Tip 9 – Firefly SDK: Apps that Discover the World around You

With the Firefly SDK, developers can build apps that recognize real world objects - QR and bar codes, artwork, songs, movies and more - and let customers interact with them. Firefly combines Amazon's deep catalog of physical and digital content with multiple image, text and audio recognition technologies to quickly identify over 100 million movies, TV episodes, songs and products. It can also recognize URLs, email addresses and phone numbers. Customers simply press the Firefly button to discover helpful information and take action in seconds. You can use the Firefly SDK to supplement item identification or build actionable options for customers after an item is recognized. For example, iHeartRadio used the Firefly SDK’s built-in music recognizer and music database to identify a song playing. Then they built their own Firefly action to create a station based on the song Firefly recognized.

Integration with Firefly requires the creation of a plug in. You can get complete details on implementing a Firefly plugin on our developer portal here.

Tip 10 – New Developer Incentives for Fire Phone Apps

The immersive apps you create for Fire phone are also eligible for new developer promotions. We have updated Appstore Developer Select and Amazon Mobile Ads API with more incentives. 

  • Appstore Developer Select: Optimize your apps for Fire phone and get enhanced merchandising and 500,000 Amazon Coins incentives for your customers. Get the details here.
  • Amazon Mobile Ads API: Developers earn $6 for every thousand interstitial ads displayed across any supported device in August and September (up to one million impressions per app per month) when they distribute their apps on Fire phones and send the first ad request from a qualified app. Get the details here.

Now is the time to submit your apps and games! Apps that are submitted and approved by July 18 will be in the Amazon Appstore when Fire ships on July 25.

Be sure to check out these additional Fire phone developer resources:

-Dave (@TheDaveDev)

 

May 29, 2014

Mike Hines

Amazon Fire TV offers an exciting opportunity for game developers to reach more customers, by making your apps and games accessible in the living room.

This quick video will give you an overview of Amazon Fire TV.  It will cover how Fire TV can help Android developers (big and small) increase their customer base, how to monetize on Fire TV, how to optimize for a 10-foot experience, and cover how to qualify for 500K Amazon Coins ($5,000 value) for promotion for each of your qualifying paid apps or apps with in-app purchasing.  For more information about getting started with Amazon Fire TV, see our online documentation:

 

May 22, 2014

David Isbitski

With the release of the latest version of the Amazon Appstore for Android, customers using the Amazon Appstore on Android tablets and phones have more ways to discover and purchase apps.

New Features for Customers

The Amazon Appstore for Android is continuously updated with new features that improve the customer experience and make it easier for developers to monetize their apps. Here are a few recent updates:

More Ways to Buy Apps with Amazon Coins

Amazon Coins can be purchased directly inside the Amazon Appstore for Android. Customers save up to 10% on apps, games and in-app items by purchasing Amazon Coins. Customers are shown their current Coins balance at the top of the screen as well as during checkout.

   

Figure 1- Available Amazon Coins displayed at top with ability to purchase at discount when clicking

Any of your apps or games that reward Amazon Coins when purchased can also be easily discovered in the Amazon Appstore for Android. Customers can search only for those apps and games that reward Amazon Coins from the navigation menu. We also feature apps and games rewarding Coins directly on the home screen.

Amazon Coins are a great way for your apps to get noticed in the Amazon Appstore. As a developer with a qualified app in the Appstore Developer Select program, customers who purchase your app will be rewarded with Amazon Coins for simply downloading your app. They can then use these Coins to buy other apps and in-app items.

   

Figure2- Apps and games that reward Amazon Coins can be viewed from the menu and on the main screen

Purchasing Directly from Search

Customers now get search hints whenever they’re searching for new apps and games. The title, publisher, customer rating and price are all displayed on the search hint. If a customer clicks on the button to make a purchase (Free or Paid), then more details about the app or game will be displayed, along with a “Get App” button that allows customers to immediately download your app or game. 

      

Figure 3- Purchasing a new game directly from search

Publish Your App to the Amazon Appstore

With the Amazon Appstore, customers can purchase your apps and games from a web browser, Kindle Fire tablets, Amazon Fire TV and select Android devices. Customers can find your apps and games in a variety of ways inside the Amazon Appstore.

If you have not submitted your Android app yet to the Amazon Appstore, registration is free and simple to complete and over 75% of Android tablets we tested work on Kindle Fire devices with no additional development required. Amazon also offers a free Mobile App SDK that supports In App Purchasing, Mobile Ads, A/B Testing, Analytics and more. Once your app is in the Amazon Appstore you can expand your reach to Kindle Fire and Amazon Fire TV devices at any time directly from within the developer console.

You may also want to check out these additional developer resources:

-Dave (@TheDaveDev)

 

May 12, 2014

Russell Beattie

For the past several years, HTML5 web app developers have been using the Apache Cordova project to create an incredible array of apps targeting native platforms. Many, such as the Wikipedia Foundation's mobile app, have had tens of millions of downloads across platforms. Cordova is the fundamental tool which enables developers to use open web technologies - HTML5, CSS3 and JavaScript - to create both fundamental and innovative mobile apps. This is why Amazon supports the Cordova project and enables developers to target the Amazon Fire OS platform. We want to enable web developers to take advantage of the advanced capabilities of the Chromium-based Amazon WebView integrated into Kindle Fire tablets running Fire OS.

We've covered the basics of setting up your Amazon Fire OS development environment for Cordova, so for this post, I'm going to create a new web app from scratch, covering all the varied little details you'll need to know to get your app from idea to Appstore. To do this, I created a simple drawing app that shows off both mobile and platform specific capabilities, and used Cordova to wrap it up into a native app ready for publication.

For the sake of simplicity, I developed an app targeting just Amazon devices. Though much of the power of Cordova is the fact that it allows developers to create cross platform apps, it can also be used as a way of quickly creating apps targeted at a single specific platform. This lets me use some more advanced HTML5 capabilities available on the Fire OS platform - in this case the accelerated 2D drawing canvas - and it also lets me cut some corners and use my rusty Java skills to add a few lines of native code to enable some needed functionality. In the future, I'll take this bit of native code and turn it into a plugin that can be used to target a wider range of devices.

I called the app Simple Draw, and it's available on the Amazon Appstore right now, downloadable for free. If you have a Kindle Fire device, go grab the app and try it out. It's a very simple drawing app targeted at young children - you can draw with your finger in various neon colors, clear the screen, or save the drawing as an image, which you can view in your Photos and share with others.

Here's everything you'd need to do to create this app yourself.

Setup

First, we'll start with the basics - setting up a new Cordova project and adding in support for Fire OS: 

$ cordova create simpledraw com.example.html5.simpledraw SimpleDraw
$ cd simpledraw
$ cordova platform add amazon-fireos

This will create our new Cordova project directory, pre-fill it with the skeleton folders, and then add in the appropriate Fire OS support files (amazon-fireos). (The first time you run through this process, you'll be prompted to download the AWV SDK found here) Make sure you change the package name to be unique to you or your company, rather than com.example.html5 in the above example.

The resulting directory should look like the following - I expanded a couple important folders to show where we're going to be tinkering.

Web Assets

Now that we've got somewhere to put our app's files, we can go in and clear out the placeholder files and folders that are in the project’s www folder. This is where your app's web files go. The Simple Draw web app above only needs an index.html and a main.js JavaScript file, but other apps could have various text files, images, sound files, etc.

Let's take a quick look at both files.

HTML

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Draw</title>
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
        <style>
            html, body { height: 100%; margin: 0; padding: 0; background: #fff; color: #fff}
        </style>
    </head>
    <body>
        <script src="main.js"></script>
    </body>
</html>

You'll notice there's not much there. It's really just a placeholder for a full-screen app that uses the HTML5 Canvas, so it doesn't need to be very complicated. It's important to set the viewport meta tag correctly, so my app knows that it's meant to be used on a handheld device, and to then call the JavaScript file at the end to make sure the DOM is loaded by the time I want to start manipulating it.

JavaScript

Next is the JavaScript, which is a bit longer, but is relatively straight forward and doesn't rely on any external libraries. The script creates a new full-screen canvas element, then listens for touch events that are used to draw on and to select from the menu bar at the bottom. There is a colorful gradient to choose your color and a couple icons at the bottom left which are used to clear the screen or save the image to your device's Pictures directory. Everything except that last bit can be done using pure JavaScript.

var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
var context = canvas.getContext("2d");
context.fillStyle = "#000";
context.lineCap = 'round'

document.body.appendChild(canvas);

var pictureCanvas = document.createElement("canvas");
var pictureContext = pictureCanvas.getContext("2d");

var width;
var height;

var menuSize = 40;
var lineColor = '#fff';
var lineWidth = 6;
var isDown = false;
var points = [];

// listen for events
window.addEventListener("resize", reset, false);

canvas.addEventListener("touchstart", pointerDown, false);
canvas.addEventListener("touchmove", pointerMove, false);
canvas.addEventListener("touchend", pointerUp, false);

document.body.addEventListener("touchcancel", pointerUp, false);

//set up and begin
reset();
requestAnimationFrame(animate);

// functions
 function reset(e){
    width  =  window.innerWidth;
    height = window.innerHeight;
    canvas.width = width;
    canvas.height = height;
    pictureCanvas.width = width;
    pictureCanvas.height = height - menuSize;
    context.fillRect(0,0, width, height);
    drawMenuBar();
    lineColor = "#fff";
    points = [];
 }

function drawMenuBar(){
    // color gradient
    var grad = context.createLinearGradient(menuSize * 2, height - menuSize, width, height);
    grad.addColorStop(0, 'black');
    grad.addColorStop(1 / 8, 'red');
    grad.addColorStop(2 / 8, 'orange');
    grad.addColorStop(3 / 8, 'yellow');
    grad.addColorStop(4 / 8, 'green')
    grad.addColorStop(5 / 8, 'aqua');
    grad.addColorStop(6 / 8, 'blue');
    grad.addColorStop(7 / 8, 'purple');
    grad.addColorStop(1, 'white');
    context.fillStyle = grad;
    context.fillRect(menuSize * 2, height - menuSize, width, height);

    // icons
    var refreshIcon = new Image();
    refreshIcon.onload = function(){
        context.drawImage(refreshIcon, -2 , height - menuSize);
    }

 

    refreshIcon.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAACg0lEQVRYCe2XMa8pQRTHx/MSjRBRENEpCBEJEoUQvgO1UqGlFirxaURoVSqh0IioFKIRiYRCKObt2XdnMruse8bam1vsSTZzdpzzPz9nszOzDkIIVa5fa39+LdkXmA1o9gnZHbQ7aLYDZvP/mhWA/FQqReLxOAmFQqrcfr8nq9WKLJfLT8irCzUs1lKXx+Oh3W6XbrdbamTwW6fToRArqy/Ey4FBYrVapYfDwYjrYR5iIUcoKuPLAbbb7QcA7ATkvgGJB2w0Gg8s8BhbrRZNJpPU7XarF/gw9+zxg4YkJA4wk8nQ+/2uAez3+9TlchkWhN8gRjTQAC0JSBzgZDIR69Bms4kuArGigdZHAXO5nKhPB4OBTAE1FnJEA00k5Pcd7PV6ojaNRqNYcR4Xi8U0GqD5McDZbMbFF4sFVvghDnKZgSYGEHWaCYfDitZ/m8/nzJUexVxR85UQCtDv93ON4/HIfVlHzBU1X+mgAN8RflZUhBI1n8WyORTgbrdj8SSbzXJf1hFzRc1XOihAZd3iGul0mihvMb/HOspbTCCXmajJ5ozGb98m2XXQ6XTSWq2m0bV0HVT+GdXvJJFIRAMAMeyCNe50OvFt0PKdBAqLe/F4POYwDIqNlUqFLXUU/B/biwEATiLX65UadS+RSNDz+cwBL5cL95lj2WmGdahUKj3tntfrpZvNhnGoo/70Y/l5kEHqR4fDQUejkQZOvPnRE7UeDu7r9brIo/HX67WpbxLHV0FlMGfBYJAUi0VSKBRIuVxWv/KUzpLb7UYCgQBR3uq3CnwMUF/d5/ORfD6vQg+HQzKdTvUhqHvLAFHVEUGorQ6hY1mIDWi2tXYH7Q6a7YDZ/H90B3qb+wyF3wAAAABJRU5ErkJggg==";

    var downloadIcon = new Image();
    downloadIcon.onload = function(){
        context.drawImage(downloadIcon, menuSize, height - menuSize);
    }
    downloadIcon.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAABCklEQVRYCe2X0QmDUAxFtegA4hCKfy4huIvgCG4hiLMIziHuoP4LqQFfwVLa2puWR0ngka/7OJ4EVNdxHNqOtXWxlmwHU0B0QmpQDaIG0LzIDlZV5RDR4aBgJi8CaC77RldA1KoaVIOoATSvO6gGUQNoXndQDaIG0Lz1O8gPyD/up06SJLQsy/aN+l61bXvq/juec3AmnOc5rev6krDve/J9//eADFqW5VPAcRwpDEMEjrOfGTS5pmkeQs7zTHEco3A4oOd51HXdAZJHn2WZBBwOyCaDIKBhGG6QRVFIwckAMmQURTRNE9V1LQknB8iQaZoSj9zsp0R390u2ZmdZ/yZRQHRx1ODfG7wCaGXbMjKT0dAAAAAASUVORK5CYII=";

    //icons border
    context.strokeStyle = "#fff";
    context.lineWidth = 2;
    context.beginPath();
    context.moveTo(menuSize, height-menuSize);
    context.lineTo(menuSize, height);
    context.moveTo(menuSize * 2, height-menuSize);
    context.lineTo(menuSize * 2, height);
    context.stroke();
}

function saveImage(){
        if(confirm('Save Image?')){
            pictureContext.drawImage(canvas, 0, 0);
            var dataUrl = pictureCanvas.toDataURL("image/png");
            if(typeof SimpleDraw !== 'undefined'){
                SimpleDraw.savePNG(dataUrl);
            }
        }
}

function eraseImage(){
    if(confirm('Erase Image?')){
        reset();
    }
}

function drawLine(){
    if(points.length > 1){
        context.strokeStyle = lineColor;
        context.lineWidth = lineWidth;
        context.lineCap = 'round'
        context.lineJoin = 'round';
        context.shadowBlur = lineWidth/2;
        context.shadowColor = lineColor
        context.beginPath();
        context.moveTo(points[0].x, points[0].y);
        for (var i = 1; i < points.length; i++) {
            context.lineTo(points[i].x, points[i].y);
        }
        context.stroke();
    }
}

// events
function animate(time) {
    drawLine();
    requestAnimationFrame(animate);
}

function pointerUp() {
    isDown = false;
    points = [];
}

function pointerDown(e) {
    e.preventDefault();

    var point = {};
    point.x = e.targetTouches[0].pageX;
    point.y = e.targetTouches[0].pageY;

    if(point.y > height - menuSize){
        if(point.x < menuSize){
            eraseImage();
            return;
        }
        if(point.x > menuSize && point.x < menuSize * 2){
            saveImage();
            return;
        }
        if(point.x > menuSize * 2){
            var data = context.getImageData(point.x, point.y, 1, 1).data;
            lineColor = 'rgb(' + data[0] + ',' + data[1] + ',' + data[2] + ')';
        }
    }  else {
        isDown = true;
        points.push(point);
    }

}

function pointerMove(e) {
    e.preventDefault();

    var point = {};
    point.x = e.targetTouches[0].pageX;
    point.y = e.targetTouches[0].pageY;

    if(isDown && point.y < height - menuSize){
        points.push(point);
    }
}

A few notes about the Javascript:

  • For the menu, I used an image program to create some basic icons, which I converted into data:// URLs. This makes the script a bit more contained. Images still take time to load even from a data URL, so I added onload listeners to draw the icons to the canvas.
  • Rather than draw to the canvas every time the event fired, I call the drawLine() function using requestAnimationFrame. This makes sure the screen is ready to be redrawn, and makes the app a bit more performant.
  • Since modern desktop browsers enable touch-event emulation, I didn't bother adding in mouse events as I'm targeting only mobile devices.
  • The saveImage() function has a reference to a SimpleDraw object. This doesn't exist in the web engine until we add it using the Java wrapper (below).

So we're all set with the main functionality of the app, and can quickly test the script by building/running the application on the device.

Please note: Cordova apps for Fire OS don't currently support emulation because of the integrated nature of Amazon WebView.

Plug your Kindle Fire into your computer via a USB cable and perform:

$ cordova run

On first run, this will compile the application using the Android Developer Toolkit, then push the app's debug version to your Kindle Fire so you can test.

Hey, it works! Well, almost - it doesn't actually save the images, so we'll have to wire that up next.

Native

When I first started testing out the functionality of the app, I assumed I'd be able to use the Cordova FileSystem API plugin to save the resulting image to the local file system. So I added the plugin via the command line (see the Cordova docs on how to do this), and used it to save the canvas image data as files. But I couldn't see them from the Photo gallery! That's not useful for this particular application - so I uninstalled that plugin, and decided to add that bit of native functionality myself.

The problem is that Fire OS (and other Android systems) keeps a separate database of images that needs to be updated in order for the images to appear in the photo browser. So in addition to saving the file, I needed to update the system to recognize the fact that the file is an image and to update the database. To do this, I needed to add a few lines of Java code to add in a custom JavaScript Interface in Cordova's native app wrapper code, found deep within the platforms folder here:

/simpledraw/platforms/amazon-fireos/src/com/example/html5/simpledraw/SimpleDraw.java

If you've done any sort of Java development, you'll recognize what that long path is - it's the standard Java directory system based on the name of the package. I had to do some digging on the web to find the right APIs to wire together, but in the end it was only a few lines of Java. I would have preferred to stay within JavaScript, but having the option to dive into native code if I needed to was very useful.

Here's the resulting SimpleDraw.java CordovaActivity class:

package com.example.html5.simpledraw;

import org.apache.cordova.*;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.Gravity;
import android.webkit.JavascriptInterface;
import android.widget.Toast;

public class SimpleDraw extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        super.init();

        //super.getFactory().enableDeveloperToolsUnix(this.getPackageName() + ".devtools");

        this.appView.addJavascriptInterface(new JSObject(), "SimpleDraw");

        super.loadUrl(Config.getStartUrl());

    }

    public class JSObject {

        @JavascriptInterface
        public void savePNG(final String dataUrl) {

            runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
                    String fileName = "drawing-" + df.format(new Date()) + ".png";

                    byte bytes[] = Base64.decode(dataUrl.substring(dataUrl.indexOf(",") + 1), Base64.DEFAULT);

                    Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

                    MediaStore.Images.Media.insertImage(getContentResolver(), bmp, fileName, fileName);

                    Toast toast = Toast.makeText(getApplicationContext(), "Image saved!", Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    toast.show();


                }
            });

        }
    }

}

Notes about the native code:

  • The native functionality is exposed to the web engine using the addJavascriptInterface() method, which takes a parameter defining the name of the JavaScript object you want to use - in this case I named it the same as the project, but it could be anything.
  • The commented out line in the onCreate() method can be used to enable access to Chromium's remote Developer Tools. You can then connect to your device remotely using this command, then browsing to localhost:9222 in your browser: 
adb forward tcp:9222 localabstract:com.example.html5.simpledraw.devtools
  • From JavaScript, the canvas is converted into an image/png data URL using the toDataURL() method. This is what’s passed to the Java class via the SimpleDraw.savePNG() method. It's then converted into an array of bytes to be saved as an image file.
  • Rather than using the basic File API, I used the built-in MediaStore class to save the converted PNG image to the file system, which automatically updates the device's internal data table so it appears instantly in the Photo gallery.

AndroidManifest.xml

In order for the app to be able to save files to the device's local storage, it needs to have the right permissions. This is done by editing the AndroidManifest.xml file found in the /platforms/amazon-fireos directory.

In the example below, you can see that the WRITE_EXTERNAL_STORAGE permission has been added to the list of user-permissions, allowing the app to save images to the file system. Additionally, the android:screenOrientation flag has been set in the application element to lock the screen to landscape mode only.

The resulting file looks like this: 

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" android:windowSoftInputMode="adjustPan" package="com.lab126.html5.simpledraw" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/app_name" android:name="SimpleDraw" android:screenOrientation="landscape" android:theme="@android:style/Theme.Black.NoTitleBar">

... more xml configuration here ...

</manifest>

Now when you test out the app and click the download arrow, the image will be saved and you'll get a native Toast message pop up confirming the process. 

If you check in the Photos app, you'll be able to see your image. Hooray! So the app now works, but we're still a few steps away from publishing it to the Amazon Appstore.

Config.xml

The Cordova config.xml settings file can be found in your main project folder. Enter in your contact details, the name and description of your app, and then add in Fullscreen and BackgroundColor preference tags (see below) which will make your app fill the entire screen, and prevent any sort of color flash as it loads.

Here's what the config.xml file looks like: 

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.html5.simpledraw" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>SimpleDraw</name>
    <description>
        A sample drawing app using Cordova for Amazon Fire OS
    </description>
    <author email="beattier@amazon.com" href="http://www.amazon.com">
        Russell Beattie, HTML5 Platform Technical Evangelist
    </author>
    <content src="index.html" />
    <access origin="*" />
    <preference name="Fullscreen" value="true" />
    <preference name="BackgroundColor" value="0xff000000"/>
</widget>

Icons

Next we'll need to replace the different sized app icons that our project used before we are ready to publish. These images are found in the /platforms/amazon-fireos/res directory, and will need to be created and copied over manually. I used a drawing program to whip up a quick app icon and then exported it as a giant 512px square image (you'll use this later when submitting your app to the Appstore). I then shrunk the images as needed and saved them as icon.png files in the following folders:

/res/drawable = 96px

/res/drawable-hdpi = 72px

/res/drawable-ldpi = 36px

/res/drawable-mdpi = 48px

/res/drawable-xhdpi = 96px

Now when you build and run your project, the generic Cordova icon will be replaced by your app's custom icon.

Signing

We're almost there! One last step before we're ready to publish the app is to create a signed -release version of the app's .apk file. Up until now, the Cordova build process has created -debug versions of the app for testing, but now we'll set up the files needed to sign the apk when the --release flag is passed to the build command.

First, you'll need to either create or locate your Java keystore. If you haven't created one yet, definitely check out the Android documentation which summarizes the keystore process quite well. However the following command will get you started:

 

$ keytool -genkey -v -keystore my-release-key.keystore -alias myapps -keyalg RSA -keysize 2048 -validity 10000

This will prompt you for all the information you need to enter and create a new keystore file for you to use to self-sign your app. Put the keystore somewhere safe and accessible from your Cordova project, and don't forget the password!

Next, you need to create a new text file called ant.properties in the base of the amazon-fireos directory: /platforms/amazon-fireos/ant.properties. In it, add two lines pointing at the appropriate directory: 

key.store=/Users/example/keystore/my-release-key.keystore
key.alias=myapps

Now you can create a release version of your app to submit to the Amazon Appstore by just using the Cordova command line tool. Call the build command and add a --release flag like this:

$ cordova build --release

This time it will go through the normal build cycle, and then stop to ask you for your password to your keystore and alias. Once it is complete, there will be a brand new signed apk ending in -release.apk saved in the platform's ant-build directory. For example /platforms/amazon-fireos/ant-build/SimpleDraw-release.apk .

Submitting your app

Now that you have your apk ready to go, you can submit it to the Amazon Appstore! You'll need to gather some screenshots, that big icon image from earlier, and fill out some details describing your app on the site, but within a short time the submission process will be complete.

To start the process, head to the Amazon Developer Portal and click on the "Submit Android App" button (you'll need an Amazon developer account of course – that’s free).  That will guide you through the process - for more information about the type of information you need to answer, definitely check out our helpful submission documentation as well.

Good luck!

Hopefully this will save you some time when developing your own Cordova app for Amazon Fire OS. Though it may seem like a lot of steps the first time through, it's really only a few extra files that need to be created or changed, and the end result is a fun new app created using familiar, yet powerful, web technologies. Good luck with your app - and definitely contact us if you have any questions or concerns!

 

May 02, 2014

Rob Pulciani

At the Amazon Appstore, we’re continuing to create opportunities and services that help app developers reach more customers and make more money. Lately, we’ve highlighted some stories from app publishers who have had success distributing Kindle Fire and Android apps in the Amazon Appstore. You may have read about Soundtracker who increased average session length by 400% and Big Bubble Blue who generated up to 15% better ARPU. Many other developers are experiencing similar success and a recent article from BI Intelligence indicates that Amazon Appstore is “generating strong revenue results.”  

“Popular Kindle Fire apps are generating 59 cents of revenue for every dollar earned by top apps in the Google Play store, according to a Distimo study. Download volumes are about half those on Google Play for top app titles — impressive considering how many more Android devices are in circulation.”

75% of Android tablet apps we tested work on Kindle Fire, with no added development necessary. And with apps available in almost 200 countries and strong monetization potential, there hasn’t been a better time to try the Amazon Appstore. Sign up for a free developer account and get started.


Check out the full Business Insider report here.

 

April 17, 2014

David Isbitski

Amazon Fire TV offers your existing Android apps an entirely new set of potential customers to engage with. It also gives your customers the ability to experience your app across Kindle Fire Tablets, Android phones and tablets, and now Amazon Fire TV – all through the same Amazon Appstore. If a customer has already bought your app that you have made available for Fire TV, they can download it onto their new Amazon Fire TV instantly, without having to purchase an additional version. 

Adding Amazon Fire TV support to your existing Android App is as simple as following a few guidelines, compiling and uploading a new TV version of your apk, and then adding Amazon Fire TV as one of your app’s device targets inside the Developer Console.  

Amazon Fire TV opens up new discoverability possibilities for your app across many new customers. Most updates to your apps for Amazon Fire TV should be minor, and if you have been following the guidelines from Android on Designing for Multiple Screens all along, your app may already be ready for a large TV resolution. 

While you may be familiar with targeting Android tablets and phones, there are a few things you need to consider for your app to run correctly on Amazon Fire TV. This includes understanding the layout, dimensions and orientation of Amazon Fire TV views, changes to the user experience when interacting with a TV (10’ away on average), UI and navigation patterns, as well as some other TV-specific gotchas such as overscan and color reproduction.

Understanding Amazon Fire TV Video Output

You can think of the Amazon Fire TV screen as an Android device that is locked to landscape orientation, with a constant width of 960dp and with a height of 540dp. The rendering surface is always 1920x1080 with a screen density of 320dpi. Output is automatically scaled for 720p and 480p output resolutions.

The following table shows how the various video outputs of Amazon Fire TV map to their Android counterparts.

TV setting

Output resolution

(pixels)

Render surface

(pixels)

Density identifier

screen density

(dpi)

Display resolution

(dp)

Screen size identifier

1080p

1920 x 1080

1920 x 1080

xhdpi

320

960x540

large

720p

1280 x 720

1920 x 1080

xhdpi

320

960x540

large

480p

640 x 480

1920 x 1080

xhdpi

320

960x540

large



By following the Android best practices guide for Supporting Multiple Screens, you can create a different layout configuration just for Amazon Fire TV so that your existing layout adapts when it runs on the device. This is the same process you are most likely already using for generating different drawables and layouts and including them in your app’s /res directory. 

You can get a detailed overview of the resource configurations available for Amazon Fire TV here.

Thinking About the 10-Foot User Experience

TV interfaces in general are often referred to as 10-Foot User Interfaces (10-ft UI) because the user is viewing the screen from 10 or more feet away. Although the screen itself can be very large, the screen resolution is lower, and distance from the screen means a smaller angle of view.

The design choices you would make for an application or web page running on a desktop computer, tablet, or phone are fundamentally different from those of a TV, as users typically view those screens from much closer distances. In addition, as the television is used in a more relaxed fashion than a computer, a tablet or a phone, the UI on the TV should not require as much attention and precision. 10-ft UI may require you to rethink the design, layout, and navigation of an existing app.

Keep the design of your screen in a 10-ft UI simple and clean, with low information density. Limit the number of design elements or UI components (menus, buttons, images) on the screen, and ensure that those elements are large enough and spaced far enough apart to be read from a distance. Present a clear set of actions or options for each screen. Minimize the amount of text, as users do not read a lot of text on a television screen. Avoid requiring the user to input a lot of information and provide reasonable defaults where possible.

In your existing Android app for a phone or tablet, you can assume that touch is always present, and your UI elements reflect that. For example, if I run the existing Android Snake Game from my AWS re:Invent 2013 demo on a Kindle Fire, tapping the menu button with my finger brings up the standard Android options menu.

Figure 1- Android Options Menu for Touch on Kindle Fire

However, running the same app on an Amazon Fire TV shows a slightly different experience when interacting with the options menu. Instead of tapping our finger on a screen, we press the Menu button on the Amazon Fire TV remote or game controller, which brings up the Android options menu with the first item in the ListView (“New Game”) automatically highlighted.

Figure 2- Android Options Menu on Amazon Fire TV automatically highlights currently selected item for the user

This allows your users to know exactly where they are in the options menu. Pressing the SELECT button on the remote (the A  button on a game controller) raises that UI element’s ItemSelected event . 

Note that all of this works automatically, and you do not have to wire up any of the on screen highlighting for any of your user interface elements – that is done for you by FireOS itself. This does, however, affect the flow of interaction your customer has with your app when using a remote or a controller. Thoroughly test your app running on a TV screen with a remote or controller and make changes to the interaction where appropriate. 

For more helpful tips on modifying your app to work with remote and controllers be sure to check out our post with helpful tips.

Updating Your Android Views for TV

The Amazon Fire TV screen is always displayed in landscape orientation, with a display resolution of 960dp wide and 540dp high. In terms of Android supported screen size configurations, you should target large. If you have not created any large-screen assets, you need to verify that your existing sizes scale well.

Depending on the orientation you are using for your existing Android app, you may see some inaccurate screen sizing when running against the TV screen for the first time. In the example below I am using the code from my previous Ad Mediation post, which was set to run in portrait. 

Figure 3- App scaling and running in forced landscape

The first time the app runs you can see the scaling that occurs to accommodate the device screen size for an app forced into portrait mode. To fix this, call setRotation on any View like so:

 
myView.setRotation(90f);

This rotates the current view 90 degrees and places it into landscape mode. Another way to do this is to set the orientation of your main view inside of its layout file so that all children are rotated as well.

In fact, simply updating the orientation of the View of my main activity to run horizontally instantly fixed all of my screen issues and my app ran perfectly.

Figure 4- App scaled correctly and set to landscape

When testing out the Snake Game from the above example, I encountered a similar scaling and rotation issue.

Figure 5- Snake Game Demo running incorrectly

Instead of setting the orientation of the entire View you can also change the orientation of your activity itself. For example, inside the androidmanifest.xml file for my game, I provided an attribute for the orientation of the SnakeGameActivity.

Setting the android:screenOrientation to be landscape fixed all scaling issues with the game and made it instantly playable.

Figure 6- Snake Game fixed and running in landscape

With just a few adjustments to your apps’ Android Views and updates to their associated resource images, your apps can be displayed on an Amazon Fire TV connected screen with minimal changes.

Understanding TV Overscan, Text and Color

Overscan is the physical space TV hardware manufactures reserve around the displayable area of a TV screen and something you should be aware of when targeting Amazon Fire TV with your app. This space can exist on TVs of any size and limits the area in which your app is able to render its user interface. 

Figure 7- TV Overscan examples.

To avoid any issues with overscan, I recommend that you avoid placing any of your app's UI elements within the outer 5% of any edge on the screen.

Any onscreen text or UI elements should be fully within the inner 90% (the safe zone) of your user interface. Your text should also use larger type sizes (at least 14sp) so that they are viewable on large screens. Amazon Fire TV uses Helvetica Neue Regular as the system font throughout all of the system’s interfaces.

When testing your app you may also find that the colors are not represented the same when shown on a TV display as they are on a tablet. Because TV screens have a higher contrast, they have a tendency to make colors seem more saturated, brighter, and vibrant. The range of colors that can be displayed is also less than that of a PC or mobile device screen. Cool colors (blue, purple, grey) work better than warmer colors (red, orange) on a TV and a good rule to follow is to avoid using less saturated colors in your apps.

Figure 8- Color Saturation on TV Displays

Understanding Amazon Fire TV Navigation

If you choose to add an updated user interface to your app to better match that of Amazon Fire TV’s UI, there are a couple of guidelines you should follow. 

Figure 9- Navigation Screen Types on Amazon Fire TV

All navigation starts with the home screen which consists of a global navigation menu on the left and a set of content tiles on the right. 

Figure 10 - Home Screen

The global navigation menu is the primary system menu. It appears in a row on the left side of the screen. The global navigation menu allows the user to choose major content categories or other options including Search, Home, Movies, TV, Music, Games, Apps, and so on. Each item in the global navigation menu can be selected with the Up and Down directional buttons.

When the user focuses on any item in the global navigation menu, the home view for that node appears on the right side of the screen. Each node has its own home view with its own content. The overall system home view, sometimes called the launcher, is accessible with the Home key on the Amazon Fire TV remote, or by selecting Home from the global navigation menu.

Figure 11- Outer Space Has Been Focused on by User

Each home view contains multiple horizontal content rows. The title tile for the row indicates the type of content (for example, Most Popular, My Movies, Recommended for You). The remaining tiles show examples of that content. From these content rows, the user can:

  • Navigate between rows with the Up and Down directional buttons.
  • Move back to the navigation menu with the Left button.
  • Choose Select or Right to select a row and view a 1D list for that row.

Be sure to check out the Design and User Experience Guidelines for additional information on all of the screen types and important tips on creating an engaging user experience for Amazon Fire TV.

In addition to the global navigation, menu notifications are also displayed in a certain way within the base Amazon Fire TV user interface.

Figure 12- Informational Notification

Amazon Fire TV includes three kinds of notifications you can use inside of your own apps: Informational, Media and Modal. Informational Notifications can be used for general messages to the user, with optional actions. Media Notifications are used when the user is interacting with media inside your application (music with artist and title for example). Modal notifications are used for alerts that require user input. Modal notifications may appear at any time over your application. A modal notification takes the focus and the user must take actions to dismiss that notification.

Note: Modal notifications can only be generated by the Amazon Fire TV user interface in response to critical issues (such as an unavailable network connection). System-wide modal notifications cannot be generated by individual apps. You can use alert dialogs (AlertDialog) to create modal alerts within your app.

Figure 13- Modal Notification

Amazon Fire TV Notifications are slightly different from standard Android Notifications. Although the API for Android notifications is available in the Amazon Fire TV SDK, and apps that use that API will compile, standard Android notifications do not appear in any way on Fire TV. You must convert your app to use the Fire TV notifications API. 

One you have installed the Amazon Fire TV SDK Add-on, you will then need to import the Amazon device notification namespaces:

	import com.amazon.device.notification.AmazonNotification;
	import com.amazon.device.notification.AmazonNotificationManager;

Next, use AmazonNotification.Builder to create a notification object, as you would a standard Android Notification. The AmazonNotification.Builder class has a new required method, setType(), which indicates the type of notification. You have these notification types to choose from -- TYPE_INFO maps to Information Notifications and TYPE_MEDIA corresponds to Media Notifications.

Once you decide on the type of Notification to create you need to set up the Builder object like below:

 	AmazonNotification.Builder builder = new AmazonNotification.Builder(getApplicationContext());
	builder.setSmallIcon(R.drawable.notification_icon);
	builder.setContentTitle(title);
	builder.setContentText(text);
	builder.setType(AmazonNotification.Builder.TYPE_INFO);

Lastly, register the Notification object with the AmazonNotificationManager, as you would a standard Android Notification. You should also assign it an ID to update or cancel the Notification later.

 
        AmazonNotificationManager notificationManager = (AmazonNotificationManager)     
        getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(notificationId, builder.build())

Please note that unlike the Kindle Fire, there is currently no Notification Tray on Amazon Fire TV so if your customer is in an immersive mode app, they will not see the Notification.

For full details and more sample code on implementing notifications, check out our developer documentation here.

Handling Web Content

If your app contains any web content, you will need to do some slight modifications. By default, Amazon Fire TV does not include a Web Browser, but web content is allowed using the Android’s WebView. To use web content, set the WebClient of the WebView and override url overloading. This can be done by calling the setWebViewClient method of the WebVew to a new WebViewClient whose shouldOverrideUrlLoading property has been set to return false. 

This code ensures that your app does not attempt to load an external browser with web content and instead loads it into the WebView. You can see the url being loaded successfully into the WebView below.

Figure 14- WebView HTML content loaded successfully

Note that if you attempt to do a direct call to WebView.loadUrl without setting a new WebViewClient whose shouldOverrideUrlLoading method returns false like above you will see an error like this one:

Figure 15- webview.loadUrl security message

If you would like to link to other apps on the Amazon Appstore, for example, to cross-promote your own offerings, you can also use Android Intents with amzn:// urls, just as you can on the Kindle Fire. If you “deep link” to an app that is not ready for Amazon Fire TV we still show the detail page for the app, but customers are not able to download it. Check out this post for more information.  

Conclusion

Once your app is updated for Amazon Fire TV, your app’s listing on the Amazon Appstore runs across all the available devices you chose when you submit your app. Customers pay for your app once and begin to engage across all of their Kindle Fire tablets, Android phones and tablets, and now Amazon Fire TV. The opportunities for your customers to discover and engage with your app continue to grow!

In addition to the tips I’ve included here, be sure to check out these additional resources:

Purchase an Amazon Fire TV

Amazon Fire TV SDK Frequently Asked Questions

Amazon Fire TV SDK

Device Specifications

Display and Layout

User Interface

Design and User Experience Guidelines

Android Developer Multiple Screen Guidance

Supporting Different Screen Sizes

Supporting Different Densities

-Dave (@TheDaveDev)

 

April 16, 2014

Mike Hines

Amazon WebView (AWV) is a Chromium-derived web runtime exclusive to Fire OS. AWV makes better performing and more powerful apps possible by providing support for a faster JavaScript engine (V8), remote debugging, and hardware optimizations for Kindle Fire devices including an accelerated 2D Canvas. Enabling your Cordova project to support AWV gives you access to HTML5 features not supported by Android’s built in WebView such as: CSS Calc, Form Validation, getUserMedia, IndexedDB, Web Workers, WebSockets and WebGL.

For developers who are not familiar with Cordova, it is an open source solution that provides tools and templates that wrap web code and assets, allowing you to publish your web code and assets as if they were native apps. Cordova is also customizable via its plugin architecture which allows developers to extend the framework in order to access OS level APIs like the built-in contact list, as well as physical hardware on the device itself like the camera.  Cordova also makes it possible for two way communication from the web app wrapper to the device’s native language.

To ensure that all core Cordova plugins will be natively supported, Amazon worked with the Apache community when adding Cordova support for the Amazon Fire OS platform. Here is how to set it up on your local computer, enable Amazon Web View and create a project from scratch.

1. Install Tools

You need to make sure you have all the required tools and libraries needed to compile and package an Android application. Download and install the following (please note these links will take you to third-party sites):

You'll need to have Java installed, and the Android SDK from developer.android.com/sdk which includes the Android Developer Toolkit (adt). You may be presented with a choice of where to install the SDK, otherwise move the downloaded adt-bundle tree to wherever you store development tools.

For Cordova command-line tools to work, you need to include the Android SDK's tools and platform-tools directories in your PATH environment:

To modify the PATH environment on Mac, Linux, etc.:

  • Use a text editor to create or modify the ~/.bash_profile file, adding a line such as the following, depending on where the SDK installs:
export PATH= $ {PATH}:/Development/adt-bundle/sdk/platform-tools:/Development/adt-bundle/sdk/tools

You will also need to enable Java, Ant and/or Node from the command line. Open a command prompt and type "java", then "ant" then "node". Reinstall, or append to the PATH whichever fail to run.

This will expose the tools in newly opened terminal windows. Otherwise run this to make them available in the current session:

$ source ~/.bash_profile

To modify the PATH environment on Windows 7:

  • Click on the Start menu in the lower-left corner of the desktop, right-click on Computer, then click Properties.
  • Click Advanced System Settings in the column on the left.
  • In the resulting dialog box, press Environment Variables.
  • Select the PATH variable and press Edit.
  • Append the following to the PATH based on where you installed the SDK, for example:
;C:\Development\adt-bundle\sdk\platform-tools;C:\Development\adt-bundle\sdk\tools
  • Save the value and close both dialog boxes.

You will also need to enable Java, Ant and/or Node from the command line. Open a command prompt and type "java", then "ant" then "node". Reinstall, or append to the PATH whichever fail to run:

;%JAVA_HOME%\bin;%ANT_HOME%\bin

2. Install Cordova

Make sure you are able to invoke npm (Node Package Manager) on your command line; it's added as a part of Node.js. (You can install Node.js from the nodejs.org homepage and type NPM in the command line to validate the installation.)

To install Cordova, open a command prompt/terminal and use:

$ npm install -g cordova

On Unix-like systems, you may need to append "sudo" to ensure it is installed correctly. See Cordova's documentation for the Command-Line Interface for more details.

3. Create Cordova Project

Create project. Open a command line/terminal in a directory where you'd like to have your project stored and run the following commands to create a project and add the files needed to build for Amazon Fire OS:

$ cordova create hello com.example.hello HelloWorld

Add Amazon Fire OS platform.  Change into the newly created project directory and add the files needed for the amazon-fireos platform target.

$ cd hello
$ cordova platform add amazon-fireos

4. Install the Amazon WebView SDK

The first time you try to add the amazon-fireos platform you will be instructed add the Amazon WebView SDK. Download and extract the Amazon WebView SDK zip file from the Amazon Developer Portal.

Copy awv_interface.jar from the unzipped folder into the amazon-fireos directory found in Cordova's global working directory. Note: You'll need to create the libs/ folder manually.

On Mac/Linux:

$ mkdir ~/.cordova/lib/amazon-fireos/cordova/3.4.0/framework/libs
$ cp awv_interface.jar ~/.cordova/lib/amazon-fireos/cordova/3.4.0/framework/libs/

On Windows:

> mkdir %USERPROFILE%\.cordova\lib\amazon-fireos\cordova\3.4.0\framework\libs
> cp awv_interface.jar %USERPROFILE%\.cordova\lib\amazon-fireos\cordova\3.4.0\framework\libs

Then you will need to remove and re-add the platform:

$ cordova platform rm amazon-fireos 
$ cordova platform add amazon-fireos

5. Build your Project

Add HTML5 assets. Your web app's assets - HTML, CSS, JavaScript, images, etc.  - should be placed in the project's www folder. You can use the sample placeholder files installed as a template, or you can replace them completely with your web apps's files.

Add support for Android devices if needed. If your app is going to be used on non-Fire OS devices running Android, you can provide a fallback to the stock Android WebView engine by adding the awv_android_factory.jar file found in the AWV SDK bundle into your Cordova project under the platform libraries folder. For example:

./hello/platforms/amazon-fireos/libs/awv_android_factory.jar

Adding the code above will allow you to submit the app to the Amazon Appstore and target non-Kindle Fire devices as well as all Kindle Fire devices.

Build and deploy your project. Make sure that USB debugging is enabled on your device as described on the Android Developer Site, and use a mini USB cable to plug it into your system. (Note: Currently, testing via an emulator is not supported for Amazon WebView based apps.)

Then you can build and deploy the app to the device with the following single command:

$ cordova run

What You Can Do Now

With Amazon Web View support enabled for Cordova, you can build higher performance apps with tools like WebGL, CSS Calc and Web Workers, debug your app remotely, and see performance gains through a faster JavaScript engine and access to accelerated hardware on Kindle Fire devices.

To learn more, follow these links (some of which will take you to third-party sites):

 

 

 

April 10, 2014

Jesse Freeman

Add Remote and Game Controller Support to Your Amazon Fire TV Game in ­10 Steps

One of the most exciting prospects of publishing your game on Amazon Fire TV is that you can run Android games directly on the TV. If you are already building games for Android, you can use the same codebase you currently have, and make that game playable on Amazon Fire TV.

One thing to consider is how to add support for user input from the newly announced Amazon Fire TV remote and Amazon Fire game controller. Luckily, basic controller support is already built into Android.  You can leverage the Android input device APIs and the game controller API from the Amazon Fire TV SDK to get your game ready to publish in no time. Here are the top ten things you should do in order to get your game ready for Amazon Fire TV customers.

1. Think Remote First

An Amazon Fire TV remote is included with every Amazon Fire TV. That means at the very least, your app should support simple four-way navigation and selection input from the remote itself. Let’s take a look at the button layout:

 As you can see above, the remote has a standard set of navigational buttons and a single selection button in the center. That is your player’s primary means of input.  The remote also has some additional proprietary buttons including home, back and menu buttons which respond exactly how you would expect them to on any Android device. I highly suggest referring to the Guidelines for Controller Behavior for our recommendations around supporting the Amazon Fire TV remote in your game.

Also consider that the Amazon Fire TV remote is the most common input device users of Fire TV use. By designing games that will take advantage of the remote, you increase your chances of appealing to a broader audience. While you can publish games that only use the Amazon Fire game controller to the store, keep in mind that not everyone has a game controller -- those games that leverage the remote input will have a broader audience appeal.

2. Navigating the UI with a Remote

Now that we have gone through basic remote input, let’s look at how to implement the user flow in your game’s navigation. When it comes to basic UI, I simply focus on supporting 6 core inputs you receive from the Amazon Fire TV remote:

Action

Amazon Remote Button

Amazon Game Controller Button

Other Game Controller Button

Behavior

Select/
Main Action

D-Pad Center

A

A

Select the item in focus, confirm menu options or prompts, or perform the main game action.

Cancel/Back

Back

Back

B

B

Cancel the current operation, or return to the previous screen.

 

Intercept this action to provide confirmation dialogs ("Are you sure you want to quit?")

Up

Down

Left

Right

D-Pad

D-Pad

Left Stick

D-Pad

Left Stick

Move the input focus in the appropriate direction.

 

On game controllers, the left stick should have the same behavior as the D-Pad.

It is critical that you design your UI with the remote in mind. This means putting the starting focus at the correct location in the UI. This is often the most likely object your users will interact with first. Let’s look at a simple weapons store screen in Super Resident Raver and see how the UI flow works with basic directional input events:

 

Here you can see the game places the player’s focus in the store area, at number one. From there, the player can move DOWN to buy something via the Buy button, or continue moving down to the Continue button to move to the next screen. When the player is inside the actual store area, they can move from item to item using the LEFT or RIGHT navigation buttons. If they move up from the top of the item area or down from the Continue button, the focus moves to the Quit Button and the entire UI makes a full circle.

Not only should it be clear where the player can navigate to, but the game should also make sure that UI flow never lets the player get stuck or makes the user keep back tracking to find the operations they want, or missed when moving around too quickly.

3. Capturing Remote Key Events

Android has built-in support for D-Pad key events. These function similarly on the Amazon Fire TV as they did in the past when Android phones had rocker D-Pads. Let’s walk through a quick example of how to actually implement this in your own game. Just like you would support this in any Android project, simply override the onKeyDown() method in your View and use a switch statement to test the key code value that gets passed in.

Here we have some basic logic that captures the main input events from the Amazon Fire TV remote.

@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
    boolean handled = false;
 
    switch (keyCode){
        case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_BUTTON_A:
                // ... handle selections
                handled = true;
                break;
        case KeyEvent.KEYCODE_DPAD_UP:
                // ... handle up action
                handled = true;
                break;
        case KeyEvent.KEYCODE_DPAD_RIGHT:
                // ... handle right action
                handled = true;
                break;
        case KeyEvent.KEYCODE_DPAD_DOWN:
                // ... handle down action
                handled = true;
                break;
        case KeyEvent.KEYCODE_DPAD_LEFT:
                // ... handle left action
                handled = true;
                break;
     }
     return handled || super.onKeyDown(keyCode, event);
}

Now we have the building blocks for moving through our game’s UI, and we can also use this code for simple movement in a game. In addition, you can build upon this foundation by adding support for the Amazon Fire game controller.

4. Adding Controller Support

Amazon Fire TV supports up to seven Bluetooth gamepads at the same time. Here is the key layout for the optional Amazon Fire TV game controller.

Since controller support is built into Android, if you have previously worked with adding controllers to your Android game, working with Fire TV controllers will be very familiar. Leverage the default onKeyDown() method for the controller buttons just like we used for the remote, and use onGenericMotionEvent() for capturing the joystick’s movement events. This is a key concept to understand since it means if you build your game to support navigation or in-game control via the built-in KeyEvent handler, you won’t have much additional work to do in order to capture the analog movement events from the controller that are not part of the remote.

Let’s look at the two  methods in Android for handling the Amazon Fire game controller events. The first is exactly the same as what we use for the Amazon Fire TV remote support:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
    boolean handled = false;
 
    switch (keyCode){
        case KeyEvent.KEYCODE_BUTTON_X:
                // ... handle x button 
                handled = true;
                break;
            }
     return handled || super.onKeyDown(keyCode, event);
}

When it comes to dealing with movement input from the joystick, the second override we can make to capture those events are part of the View’s onGenericMotionEvent() method like this:

@Override
public boolean onGenericMotionEvent(MotionEvent event){
    // get changes in value from left joystick
    float deltaX = event.getAxisValue(MotionEvent.AXIS_X);
    float deltaY = event.getAxisValue(MotionEvent.AXIS_Y);
           
    return true || super.onGenericMotionEvent(event);
}

You can see the full list of controller input events here. As you may have noticed from the reference table, especially with the D-Pad controls, there are primary and secondary events. While the most granular way of getting analog movement input from a game controller is the MotionEvent, the secondary event is a useful fallback that allows you to support the Amazon Fire TV remote and Amazon game controller at the same time. Another example of this is the A button which has a secondary event of KEYCODE_DPAD_CENTER.

If your game only supports the D-Pad, take advantage of the onKeyDown() method and listen for the secondary event types while ignoring overriding onGenericMotionEvent(). Likewise you can simply listen to KEYCODE_DPAD_CENTER events ignore KEYCODE_BUTTON_A events for the controller’s A button. This ensures that your game works with the included Amazon Fire TV remote and also the optional Amazon Fire game controller. The only caveat is that if you listen to both primary and secondary events you may get multiple events saying the same thing so be prepared to handle that in your code.

5. Using the GameController API

Using the built-in event handlers is helpful for Android-based games that use of Views, some games may use a custom engine or need more direct access to the current input event on a frame by frame basis. The GameController API, part of the Amazon Fire TV’s SDK offers the following things:

  • Methods to associate game controllers with the player numbers as defined by the Amazon Fire TV.
  • Methods to query controller state at any time.
  • Input event constants specific to gamepads.
  • Behavior to enable you to process gamepad input events on a per-frame basis (that is, within a game loop).

To use the GameController API simply import the correct classes from the SDK:

import com.amazon.device.gamecontroller.GameController;
import com.amazon.device.gamecontroller.GameController.DeviceNotFoundException;
import com.amazon.device.gamecontroller.GameController.PlayerNumberNotFoundException;
import com.amazon.device.gamecontroller.GameController.NotInitializedException;

From there you will have to initialize the GameController in your onCreate() method:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    //Initialize GameController with the context to attach to the game controller service
    GameController.init(this);
}

If you don’t initialize the GameController before accessing any of its APIs, it throws a NotInitializedException exception. Once you know it is properly initialized, you can begin using it. Here are some important APIs to get more granular data over each controller’s input state:

  • Getting GameController Objects by Player - simply use GameController.getControllerByPlayer() and supply the player number for access to that particular controller. There is a constant you can use to iterate through all the controllers called GameController.MAX_Players, which is capped at 4 by default.
  • Test for Key Down - Once your have the reference to the player’s controller you can call getKeyValue() on it and pass in a constant such as GameController.BUTTON_TRIGGER_LEFT to see if that key is pressed. It will return a true or false value.
  • Get Axis Value - Likewise you can also access the analogue stick by calling getAxisValue() on the reference to the player’s controller and supply a constant such as GameController.AXIS_STICK_LEFT_X to return a float value you can use to determine the direction it is being pushed in.
  • Testing Changes In Value - Finally you can test if a change has occurred since the last frame by calling getAxisValue() and supplying a constant such as GameController.AXIS_STICK_LEFT_Y. This will return a Boolean to help you decide if you need to apply a new change in the game.

While the above code is simply here to illustrate how this works, I suggest going through the GameController API documentation to see more sample code that you can use in your own game. Also, make sure you check out the GameController Event Constants as well.

6. Supporting Multiple Controllers

Now that we have covered the basics of the GameController API, let’s talk about multi-player games on the Amazon Fire TV. While you can connect up to seven Bluetooth game controllers to the Amazon Fire TV, only four of those controllers are assigned to player numbers in the GameController API. Getting the player’s number from the API is an easy way to manage your game’s players. You can use this by calling GameController.getPlayerNumber() and supply an Android Device ID to get the player number for that device. Likewise, there is a helper method to get you the Android Device ID if you call GameController.getDeviceID() and pass in a player number. You can iterate through all the devices by using the GameController.MAX_PLAYERS constant.

If your game supports more than four players, you can manage controllers and player numbers manually. For most games though, four is a great experience for local multi-player and you will find that the Amazon Fire TV is more than capable of keeping up with the action. While you can also do remote multi-player via standard networking APIs, keep in mind that you will have to manage that system separately from the game running on the Amazon Fire TV.

7. Handling Interruptions In Your Game

Your game should be prepared to handle interruptions. At the very least, make sure you support Android’s native onPause() and onResume() methods in your View. This is critical when the following events or situations happen:

·         Remote or Controller Drops - if you lose the connection to the main input of the device, possibly due to a battery or connection issue, you want to make sure your game is able to pause itself immediately. You should also build in some simple way to test that the controller is still active. This is critical in multi-player games; if one player drops you need to immediately pause the game.

·         User Presses the Home Button - if the user presses the home button on the controller, no event is raised, but onPause() is called. Your game exits back to the home screen.

·         User Performs a Search - once the user tries to perform a search, the event cannot be intercepted and onPause() will be called in your View.

·         User Presses the GameCircle Button - this immediately takes the user to the GameCircle dashboard while in your game.

It’s also important to capture ‘back’ events and handle exiting the game from a ‘back’ button properly. If you are on the home screen of your game and you receive a back button event, your game should prompt the user if they actually want to quit.

8. Building Controller Friendly UI

Each interactive UI element should have the following states:

  •           Enabled
  •           Disabled
  •           Highlighted
  •           Selected

These states are critical to helping your player understand where they currently are in the UI and also what action they can do. Sometimes you may need to have multiple states such as Disabled Selected in the case of the Resident Raver store scenario where it’s possible to select an item that can’t be purchased just to see what the price is.

On the same topic, it’s also important to take the Highlight state of the other UI elements into consideration. Here is a screenshot with the main UIs Selected states visible.  The selected state moves as the player moves around from main UI element to main UI element.

Finally, no matter what you end up designing, make sure there is consistency in each button state so that the player can intuitively understand where they are on the screen and what they need to do next.

9. Handling Joystick Dead Zone

Like all controllers, the joystick needs to be properly calibrated. Many things can happen that may mess-up the alignment of the joystick. At the very least, you need to account for adding a joystick dead zone to ignore joystick movements that are not large enough to cause an actual require a movement event to be recognized. Here is an example of how you can calculate this by using the GameController API.

gameController = GameController.getControllerByPlayer(1)
float x = gameController.getAxisValue(GameController.AXIS_STICK_LEFT_X);
float y = gameController.getAxisValue(GameController.AXIS_STICK_LEFT_Y);
float value = (float) Math.sqrt(x * x + y * y);

Here the formula returns a value between 0 and 1. You can choose how aggressively you want to ignore controller drift. A good place to start is somewhere above 0.25f - 0.35f. Test that the value is greater than your allowed dead zone value before applying the movement. In addition to this, I also suggest allowing the user to recalibrate their joystick in the options menu. Nothing is more frustrating than an unresponsive or “sticky” joystick control in a game.

10. Clearly Display What the Controls Are

Before any of my games start, I always show a screen with the game’s controls. While most people skip right over this, there will be a few who stop to read it in order to figure out what they will need to do in the actual game.

This also means making sure you remove any reference to touch controls, especially if you ported the game over from mobile. Also make sure you remove on screen pause buttons and sound buttons. Sound in your game should be managed via the TV’s remote. The only exception is if you have two separate user configurable volumes for the sounds effects and music which I would still keep in as long as it can be modified via the remote or controller directly.

Wrapping Up

There is a lot to consider as you begin to add support for the Amazon Fire TV remote and Amazon Fire game controllers to your game. It helps to take a step back and map out how this should all work. Having poor controls in your game will not go over well with your players, so nailing tight, responsive, and intuitive controls is critical to launching a successful game on the Amazon Fire TV. Also,look to other similar TV based gaming experiences for inspiration on how your UI and game controls should work.

For More Information

Amazon Fire TV Remote Input: Learn how to handle input from the Amazon Fire TV remote.

Amazon Fire Game Controller Input: Learn how to handle input from game controllers (both the Amazon Fire game controller and other game controllers).

GameController API: The Fire TV SDK includes a utility API for games to help you manage game controller input. This API includes the ability to associate player numbers with controllers and to manage input events on a frame-based basis.

Identifying Controllers: Users may pair up to seven Bluetooth controllers to the device at a time. Learn how to identify different controllers paired with the system and interpret input from those controllers.

Controller Behavior Guidelines: For consistency with the Fire TV user interface and across different apps we suggest you implement the guidelines in this document for controller behavior.

Controller Image Assets: If your app or game provides instructions or help screens for how to use a controller, you may freely use the controller images and button hints on this page in your app.

 

- Jesse Freeman (@jessefreeman)