Beginning TiVo Programming 0470054271, 9780470054277, 9780470140949

With TiVo Home Media Engine SDK you can build new and exciting applications for broadband-connected Series 2 devices. In

253 48 5MB

English Pages 330 Year 2007

Report DMCA / Copyright

DOWNLOAD PDF FILE

Beginning TiVo Programming
 0470054271, 9780470054277, 9780470140949

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Beginning

TiVo® Programming John Brosnan Kyle Copeland

Beginning

TiVo® Programming

Beginning

TiVo® Programming John Brosnan Kyle Copeland

Beginning TiVo® Programming Published by Wiley Publishing, Inc. 10475 Crosspoint Boulevard Indianapolis, IN 46256 www.wiley.com Copyright © 2007 by Wiley Publishing, Inc., Indianapolis, Indiana ISBN: 978-0-470-05427-7 Manufactured in the United States of America 10 9 8 7 6 5 4 3 2 1 1B/SV/QR/QX/IN Library of Congress Cataloging-in-Publication Data: Brosnan, John, 1978Beginning TiVo programming / John Brosnan, Kyle Copeland. p. cm. ISBN-13: 978-0-470-05427-7 (paper/website) ISBN-10: 0-470-05427-1 (paper/website) 1. Interactive television. 2. Home video systems--Automatic control. I. Copeland, Kyle, 1975- II. Title. TK6679.3.B76 2007 621.388’33--dc22 2006038753 No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Legal Department, Wiley Publishing, Inc., 10475 Crosspoint Blvd., Indianapolis, IN 46256, (317) 572-3447, fax (317) 572-4355, or online at http://www.wiley.com/go/permissions. LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND THE AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS WORK AND SPECIFICALLY DISCLAIM ALL WARRANTIES, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES OR PROMOTIONAL MATERIALS. THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY SITUATION. THIS WORK IS SOLD WITH THE UNDERSTANDING THAT THE PUBLISHER IS NOT ENGAGED IN RENDERING LEGAL, ACCOUNTING, OR OTHER PROFESSIONAL SERVICES. IF PROFESSIONAL ASSISTANCE IS REQUIRED, THE SERVICES OF A COMPETENT PROFESSIONAL PERSON SHOULD BE SOUGHT. NEITHER THE PUBLISHER NOR THE AUTHOR SHALL BE LIABLE FOR DAMAGES ARISING HEREFROM. THE FACT THAT AN ORGANIZATION OR WEBSITE IS REFERRED TO IN THIS WORK AS A CITATION AND/OR A POTENTIAL SOURCE OF FURTHER INFORMATION DOES NOT MEAN THAT THE AUTHOR OR THE PUBLISHER ENDORSES THE INFORMATION THE ORGANIZATION OR WEBSITE MAY PROVIDE OR RECOMMENDATIONS IT MAY MAKE. FURTHER, READERS SHOULD BE AWARE THAT INTERNET WEBSITES LISTED IN THIS WORK MAY HAVE CHANGED OR DISAPPEARED BETWEEN WHEN THIS WORK WAS WRITTEN AND WHEN IT IS READ. For general information on our other products and services please contact our Customer Care Department within the United States at (800) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. TiVo is a registered trademark of TiVO, Inc. All other trademarks are the property of their respective owners. Wiley Publishing, Inc., is not associated with any product or vendor mentioned in this book. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.

About the Authors John Brosnan co-wrote the TiVo HME Developer Challenge grand-prize winning application, AudioFaucet. He has been involved in HME applications for other companies and brings a strong background in Java. John has been a Java programmer for the past five years, primarily in the telecom industry, writing web enterprise applications. Kyle Copeland co-wrote the TiVo HME Developer Challenge grand-prize winning application, AudioFaucet, and has been involved in the ongoing development for AudioFaucet. Working in the cable industry for the past ten years developing products for consumers nationwide has given Kyle great insight into the customer experience, and a rich background in developing products and services for consumers.

Credits Executive Editor

Vice President and Executive Publisher

Chris Webb

Joseph B. Wikert

Development Editor

Graphics and Production Specialists

Rosanne Koneval

David Staas

Carrie A. Foster Barbara Moore Heather Ryan Alicia B. South

Production Editor

Quality Control Technician

Eric Charbonneau

Christy Pingleton

Copy Editor

Project Coordinator

Kim Cofer

Erin Smith

Editorial Manager

Proofreading

Mary Beth Wakefield

Techbooks

Production Manager

Indexing

Tim Tate

Julie Kawabata

Vice President and Executive Group Publisher

Anniversary Logo Design

Richard Swadley

Richard Pacifico

Technical Editor

Acknowledgments First, a big thanks to our families and the dog for giving us the time to complete this book. Thanks also to TiVo for making a little box that is fun to use. Lastly, thanks to our editors for guiding us along the path of writing this book.

Contents Acknowledgments Introduction Chapter 1: Introduction to TiVo Applications The TiVo Platform Brief History of Software Development for TiVo Home Media Option and TiVo Desktop TiVo Desktop as a Server HMO Protocol

HMO Applications TiVo Server-Hosted Applications Desktop Applications

Home Media Engine Software Development Kit

How HME Interacts with TiVo What HME Is and Isn’t

Summary Questions

Chapter 2: Getting the TiVo Box Ready for HME TiVo Requirements for HME Supported TiVo Boxes Series1 Standalone Series2 Standalone DirectTV Integrated TiVo (DirectTiVo) Series3

Active TiVo Service Subscription Checking the Version of TiVo Software Forcing a Connection to the TiVo Service

ix xxi

1 1 2 3 4 6

7 7 7

8 10

11 11

12 12

13 13 13 14 15 15 16

17 17 18

Contents The Household Network Wired vs. Wireless Network Adapters Wired Adapters Wireless Adapters

Adding TiVo Boxes to a Household Network Setting up Wired Access Setting up Wireless Access TCP/IP Settings

Music, Photos, & More Summary Questions

Chapter 3: Your Development Environment Required Software Java SDK Windows Mac OS X Linux and Unix

Text Editor

Getting the TiVo HME SDK Exploring the SDK Classpath

Recommended Software Ant Log4j JDIC JUnit Subversion

Setting up Eclipse Installation Running Eclipse Starting a New Project

Running the Sample Applications Starting the Applications Using the Sample Applications in Eclipse

xii

19 20 20 20 21

21 21 22 22

23 24 25

27 27 28 28 29 29

30

30 30 31

32 32 33 33 33 33

33 34 34 35

39 40 41

Contents The HME Simulator Limitations of the Simulator

Summary Questions

Chapter 4: Your First TiVo HME Application Hello World Creating Hello World Running the Example in the Simulator Simulator in Discovery Mode Simulator in Direct Mode

Starting Hello World on the TiVo Box Handling Events

Application Lifecycle Startup Running Events

44 46

46 46

47 47 47 50 50 52

53 56

57 57 57

Errors

58

Shutdown

58

Summary Questions

Chapter 5: Displaying Resources

58 59

61

Understanding Views

61

Introduction to Views

61

View Hierarchy Drawing Order and Hiding Views Properties of Views Translation Scaling Visibility, Transparency, and Focus

Extending Views Code Example

Text Creating Text Resources

61 63 64 64 65 66

67 69

72 72

xiii

Contents Image Resources Supported Graphic Formats Creating Image Resources Size, Scaling, and Alignment Updating the Weather Application with Graphics

Sounds Creating Sound Resources Built-in Sounds

Summary Questions

80 80 80 87 89

92 92 93

93 94

Chapter 6: Events

95

Types of Events

95

Device Info Init Info Application Info Idle Info Key Event Font Info

96 97 97 97 98 98

Event Flow Key Events Optional Keys Events Example

Sending Custom Events Ticker Events Focus Events Application Event Handling Summary Questions

Chapter 7: Going Bananas How to Include Bananas in Your Application Reasons to Use Bananas Bananas Sample Application

BApplication Other Features of BApplication

xiv

98 98 100 101

105 106 112 114 115 116

117 117 119 119

122 124

Contents BScreen New Methods in BScreen Pushing and Popping BScreens Transitions Creating Custom Transitions

BView BList Using BLists Styling the List Managing the List BList Example BList Methods Focus

BText BButton Using BButtons

BKeyboard Using the Keyboard Widget

BSkin BDirSkin BZipSkin BResSkin Example

Summary Questions

Chapter 8: Using Bananas Events Event Model New Events in Bananas

Using Actions Custom Actions

Custom Widgets Weather Application Example Summary Questions

125 126 127 129 130

134 136 138 138 139 139 142 144

146 147 147

149 151

154 155 155 155 155

157 158

159 159 161

164 164

166 170 178 178

xv

Contents Chapter 9: Advanced Resources Streaming Resources Streaming Graphics Streaming Audio MPEG Video Backgrounds Creating MPEG Video Backgrounds Using TiVo’s MKLOOP FFMPEG Wrapper Using a Web-Based MKLOOP FFMPEG Wrapper

Setting MPEG Video Backgrounds MPEG Video Background Caveats Simulator Not Pixel Perfect Root View Method Behavior System Reboots

Resource Management Caching and Removing Resources Debugging the Resource Tree Resource Limitations Pixel Buffer and Rendering Engine Best Practices for Predictable Rendering Debugging Software Rendering CPU Resource Concerns Network Resource Constraints

Summary Questions

Chapter 10: Advanced HME Application Lifecycle

179 179 179 180 181 182 182 183

183 184 184 187 190 191

191 191 192 193 194 195 196 197 198

198 199

201

HME SDK Architecture Impact Overriding the Factory

201 202

Accessing Files and Resources Changing the Application Name Handling Arguments Common Actions

205 206 207 208

Using Factory for Shared Data

208

Singletons

210

xvi

Contents Threads Using Threads Java 4 Threads Java 5 Executor

Stopping Threads Correctly on Application Exit Keeping Shared Threads Running between Applications

Calling Other Applications Transitioning to Another Application Running the Example Transitioning Back to the Original Application

Summary Questions

Chapter 11: Application Preferences Per-TiVo Preferences

211 212 212 212

214 215

215 215 217 220

220 220

223 223

Using Per-TiVo Preferences How the Data Is Stored

223 225

Per-Application Preferences

227

Using Persistent Data Using the Java Preference System Details of Java Preference API Converting BWeatherApp to use Java Preferences

Why Use the Preferences API?

Other Methods of Saving Preference Data Summary Questions

Chapter 12: Animation Animation Resources What Can Be Animated

Moving Views Animating Transparency Graphics Scaling Visibility Animating Events

227 228 228 229

230

230 231 231

233 233 234

235 236 237 237 238

xvii

Contents Chaining Animations Putting It All Together Summary Questions

Chapter 13: Connecting to External Resources Data from the Web Setting the Resource as a URL Retrieving the Resource and Saving It Locally

SOAP, RSS, & XML

238 240 242 242

243 243 243 244

246

SOAP RSS XML Data

246 247 248

JDBC Other Options Summary Questions

248 251 251 251

Chapter 14: Deploying an HME Application Jar from Command Line Creating a Web Start Application Using Web Start with HME

OS X Native App

253 255 256

258

Creating an Application Icon Bundler

258 258

Preparing Your Resources Creating a Jar Bundle

259 259

Final Touches Packaging Creating the Disk Image Stylizing the Disk Image Compressing and Locking Down the Disk Image Launching a Disk Image Automatically Upon Download Displaying a Software License Agreement

xviii

253

261 263 263 264 267 267 268

Contents Windows Native App Creating an Application Icon Bundler Installer Packaging

Selling Your Application Summary Questions

Chapter 15: Tips and Troubleshooting Logging Common Problems Additional Resources Summary

Appendix A: Exercise Answers Index

268 268 269 269 270

270 270 270

271 272 274 275 275

277 283

xix

Introduction The impetus for the book came from a desire to share the knowledge gained while developing applications for the TiVo HME platform, and to help others gain access to the market created by TiVo HME applications. TiVo HME (Java applications for TiVo) are a new development, and one of the first set-top box platforms to allow user-written code to run on an unmodified system.

Who This Book Is For The target readers for this book are TiVo users with some programming expertise who are interested in creating a TiVo HME application. The book covers the fundamentals of building applications for TiVo, and the process of building an application that is user friendly. This book is ideal for readers looking to bring their vision of a TiVo application to users.

What This Book Covers The main goal of this book is to get you started writing polished applications using the TiVo HME SDK. TiVo users have grown accustomed to a powerful, friendly user interface that is intuitive and simple to use. This book walks you through writing applications, utilizing the basic and more advanced features of HME to build new and exciting applications to extend the TiVo experience. The key features this book covers are ❑

Configuring and getting comfortable in your development environment



The HME Event model



Displaying images and text



Playing audio files and streams



Optimizing the behavior of your application



Packaging your application for deployment

You should take from this book a solid understanding of the way the TiVo HME SDK functions, and an understanding of how to build applications that will be responsive and intuitive for the user as well as set up a solid development process for producing quality applications.

Introduction

How This Book Is Structured This book is designed to guide you through setting up a development environment for writing TiVo HME applications. The book starts by describing software development for the TiVo platform. You will learn the basic building blocks of designing applications for TiVo and how to respond to events. Exercises and examples illustrate the concepts throughout the book. After covering the basics of developing applications for TiVo, you will read about a component library from TiVo that makes developing advanced applications easier. The end of the book covers information regarding polishing the final product and packaging applications for your users.

What You Need to Use This Book The book contains many programming examples. Applications for TiVo boxes are written in Java, so a basic understanding of the Java language and syntax will be needed. The installation of software needed for developing TiVo HME applications is covered in the book. A TiVo box (Series 2 or Series 3) is also needed for certain examples and sections of the book. The book does cover configuration that needs to take place on the TiVo box itself.

Conventions To help you get the most from the text and keep track of what’s happening, we’ve used a number of conventions throughout the book.

Try It Out The Try It Out is an exercise you should work through, following the text in the book.

1. 2. 3.

It usually consists of a set of steps. Each step has a number. Follow the steps through with your copy of the database.

How It Works After each Try It Out, the code you’ve typed will be explained in detail.

Boxes like this one hold important, not-to-be-forgotten information that is directly relevant to the surrounding text.

Tips, hints, tricks, and asides to the current discussion are offset and placed in italics like this.

xxii

Introduction As for styles in the text: ❑

We highlight new terms and important words when we introduce them.



We show keyboard strokes like this: Ctrl+A.



We show file names, URLs, and code within the text like so: persistence.properties.



We present code in two different ways:

In code examples we highlight new and important code with a gray background. The gray highlighting is not used for code that’s less important in the present context, or has been shown before.

Source Code As you work through the examples in this book, you may choose either to type in all the code manually or to use the source code files that accompany the book. All of the source code used in this book is available for download at http://www.wrox.com. Once at the site, simply locate the book’s title (either by using the Search box or by using one of the title lists) and click the Download Code link on the book’s detail page to obtain all the source code for the book. Because many books have similar titles, you may find it easiest to search by ISBN; this book’s ISBN is 978-0-470-05427-7 Once you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/download .aspx to see the code available for this book and all other Wrox books.

Errata We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata you may save another reader hours of frustration and at the same time you will be helping us provide even higher quality information. To find the errata page for this book, go to http://www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list including links to each book’s errata is also available at www.wrox.com/misc-pages/booklist.shtml. If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport .shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.

xxiii

Introduction

p2p.wrox.com For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a Web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. At http://p2p.wrox.com you will find a number of different forums that will help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:

1. 2. 3. 4.

Go to p2p.wrox.com and click the Register link. Read the terms of use and click Agree. Complete the required information to join as well as any optional information you wish to provide and click Submit. You will receive an e-mail with information describing how to verify your account and complete the joining process.

You can read messages in the forums without joining P2P, but in order to post your own messages, you must join. Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.

xxiv

Beginning

TiVo® Programming

1 Introduction to TiVo Applications What is TiVo? If you need an answer to that question, most likely this book isn’t going to be of much interest to you. However, if you are looking for a fun way to create new and exciting living room multimedia experiences leveraging the TiVo platform, you’ve found the right place to get you well on your way. This chapter introduces you to the TiVo platform and provides a good foundation before you begin writing applications for yourself. In this chapter, you learn about the following: ❑

Home Media Option



Home Media Engine



TiVo HME SDK

The TiVo Platform Essentially, the TiVo platform is a small personal computer that up until recently was dressed as an easy to use, yet powerful, alternative to the household VCR. The current generation of TiVo hardware contains a low-powered MIPS CPU, a high-capacity internal hard drive, a modem for connecting to the TiVo servers over dial-up, a few USB ports for expansion opportunities, a small amount of video and system RAM, a video output system to connect to televisions, and a simple input system that uses the fantastic TiVo Remote. Though that might not seem like a powerful platform for providing DVR (digital video recorder) functionality (especially compared to the horsepower needed for running a Windows Media Center PC), TiVo has also included a hardwarebased MPEG-2 Encoder/Decoder chip to handle all of the heavy tasks like video encoding and decoding.

Chapter 1 When they designed the TiVo hardware platform, the wizards at TiVo decided to use Linux as the base operating system. Naturally, this made a good portion of the technical community quite pleased, because under the GPL (GNU General Public License) that covers Linux distributions, TiVo had an obligation to freely distribute the full source code for any changes that it makes to optimize the core OS to run its software. Almost immediately after getting their hands on the source code of the TiVo Linux distribution, a TiVo hacking community was born. It came as a surprise to many that for the most part, TiVo didn’t interfere with people tinkering with the software powering their box, unless of course the tinkerer’s goal was to avoid continuing to pay for TiVo’s subscription service. The first wave of TiVo hacks included simply growing the hard drive space, allowing users to add more recording capacity to their DVR. Following shortly thereafter, some brilliant hardware engineers outside of TiVo started devising a way to include the TiVo box in their home networks. Inside the TiVo box was a diagnostic slot that allowed the fabrication of an expansion board that would allow users to install a card, load some Linux drivers, and be on their way to a network-connected TiVo box. However, loading the Linux drivers proved difficult for the average end user. Shortly thereafter, engineers internal to TiVo embraced the idea of allowing users to have a network connected to their unit, and started to build an optimized driver set for the expansion cards directly into their software. This made TiVo discover a new set of inter-networked features that could be available to its users. This freed users of using their phone line to get software updates and electronic programming guide data. TiVo soon started working on a set of drivers and a TV-based user interface for configuring and controlling external USB adapters. These can connect to both Ethernet and Wi-Fi networks. These drivers, along with some great software, allow users to make TiVo part of their life beyond avoiding the drama of missing their favorite television show. Proving its commitment of transitioning TiVo boxes from a DVR to a digital lifestyle device, TiVo’s newest generation of hardware includes a physical Ethernet port, allowing TiVo boxes to connect directly to household networks out of the box without the need to consider external USB network adapters. To connect to Wi-Fi networks, TiVo created its own TiVo-branded Wi-Fi adapter, optimized to integrate with TiVo boxes and speed up communication by offloading encryption and other network overhead to specialized hardware on the adapter.

Brief Histor y of Software Development for TiVo It’s always good to start with a bit of history before diving into new application-building technology. TiVo HME offers a fairly rich environment for building end-user applications; however, it isn’t the first attempt that TiVo has made at entering the applications delivery market. TiVo created a set of rudimentary tools called TiVo HMO, which is targeted specifically to solve the problem of delivering personal music and photo content to the television through the TiVo box.

2

Introduction to TiVo Applications

Home Media Option and TiVo Desktop Home Media Option (HMO) was the first digital lifestyle software solution introduced by TiVo. HMO runs two basic types of applications: audio streaming to TiVo boxes over a home network and displaying digital photo slideshows. The user interface on the television used to select and view photos or to choose music to play was a simple set of templates that, for the most part, followed the standard TiVo user interface guidelines. The templates were then populated by the TiVo box itself after requesting the information from TiVo Desktop server software running on a desktop machine located on the household network. Originally TiVo charged an activation fee for Home Media Option on top of your normal subscription costs per TiVo box in your home. In order to show users the value in using a sidecar TiVo platform versus just renting a DVR directly from your video provider, TiVo subsequently dropped the activation fee for HMO features and now it comes standard with every TiVo subscription. In addition to allowing access to music and photos (Figure 1-1 and Figure 1-2) on the user’s desktop, TiVo also added a web-based interface for users to send program requests to their TiVo boxes via TiVo Central Online, hosted at TiVo.com. It also added Multi-Room Viewing, which brought the ability to stream or copy recordings from one TiVo box to another, provided both TiVo boxes were listed under the same account and on the same home network. This drove many users into adopting multiple networked TiVo boxes throughout their home and made the Photo and Music streaming services available in many more rooms in a household, all from a single TiVo Desktop server.

Figure 1-1

3

Chapter 1

Figure 1-2

TiVo Desktop as a Server Although HMO is limited to the capabilities of the display template frameworks that TiVo provides, it was the first time TiVo allowed end users to send their own personal content to TiVo boxes throughout their home and was a step in the right direction. In order to facilitate trafficking all of this foreign information into the TiVo world, a small software server called TiVo Desktop was released. As mentioned earlier, the TiVo Desktop runs on a Windows PC (Figure 1-3) or Macintosh (Figure 1-4) to serve music and photos to TiVo boxes throughout the household network. It is basically a simple web server that you can browse to with any browser if you know the specific URL format you need to use. The server is responsible for converting the audio and graphic content into a compatible MP3 or JPEG format and also for including the XML-based meta-data required to describe the content appropriately so the TiVo box will know the proper views to display on the television. Though the TiVo Desktop software continues to provide the photo and music browsing services today, the latest generation of applications are largely unconstrained in terms of the user interface that is displayed, and the types of information that are accessed. TiVo Desktop successfully set the stage for TiVo users to have independent software running on their personal computers within a home network to bring new functionality to their beloved TiVo boxes.

4

Introduction to TiVo Applications

Figure 1-3

Figure 1-4

5

Chapter 1 HMO Protocol TiVo opened the HMO protocol to developers to extend their existing software offerings or to create new music and photo applications that could leverage the TiVo box’s ability to display information on televisions throughout the household. The documentation for the HMO protocol is available at http://www .tivo.com/developer. The protocol itself consists mainly of HTTP requests from the TiVo box to the computer. In effect, the desktop machine becomes a mini web server in the HMO system, serving content in the way the TiVo box knows how to display. The most interesting thing about this is that any application on any computer can extend its functionality by simply adding a very thin web server layer and talking to TiVo’s specific XML and URL schemes. The main thing that makes HMO applications so easy to use from an end-user perspective is an auto discovery technology called TiVo Connect. Applications can register with a machine’s local beacon service to periodically broadcast information about the current suite of applications available that TiVo boxes on the household network can connect to. TiVo boxes would pick up these broadcast messages to automatically detect and alert users to the availability of expired or newly announced content that was available for use within the household. In Figure 1-5, the local HMO services on the Music, Photos & More screen is shown.

Figure 1-5

6

Introduction to TiVo Applications

HMO Applications There are two flavors of HMO applications: applications running on a personal computer locally within the user’s household network extending the functionality of TiVo Desktop, and server-hosted applications mostly used for promotional purposes.

TiVo Server-Hosted Applications HMO also brought the ability for TiVo to publish hosted services to the Music, Photos, Products, & More menu on any TiVo box connected to the global Internet. TiVo used the new network push opportunity to land two large advertising partners. On the music side, Universal Music and later Best Buy signed on to push New Music Tuesday content, which was periodically updated when artists or labels wanted to promote new works as they became available. For photos, TiVo inked a deal with Nikon to promote artsy samples of the world’s greatest photographers that used Nikon digital cameras. The Nikon Photo application is still available through the Music, Photos, Products, & More menu today.

Desktop Applications Initially there were several applications available for TiVo box owners to run on their desktops that leveraged HMO’s ability to display and interact with audio and visual content, but the main application that was born of the opening of the HMO protocol was the very popular JavaHMO. JavaHMO is a Javabased program that conveniently provides weather, movie listings, and a menagerie of other useful information via the photo album browsing interface frameworks of HMO. JavaHMO was a completely open source replacement for TiVo Desktop, allowing users to collect personal and web content and push it to the TiVo boxes throughout their home in a more innovative way than even TiVo had intended. It cleverly took advantage of the hooks that TiVo provided in its API for HMO, with the end result of the JavaHMO server being more aware of the type of content that was being collected and aggregated throughout the home. Due to the constraints of the TiVo-provided template frameworks for HMO, the screens simply referred to themselves as Music or Photos depending on what type of information was being pushed. Despite this, many users still found the applications created using the new Java-based server to be well worth the aggravation of learning how to interact with the UI on the TiVo. The initial intent of the open API from TiVo was to allow application providers to extend their existing applications to include new ways of pushing their existing content to networked TiVo boxes throughout a home network. This prompted a few media jukebox and photo shoebox software creators to extend their software to share user libraries with TiVo boxes on the household network while their programs were running. The first to enter the fray was JRiver Media Center, a media organization jukebox, which allowed users to enhance their Home Media Option experience by allowing them to share music playlists and browse photo slideshows already categorized within JRiver’s rich media organization environment. Many others soon followed. MoodLogic released a TiVo HMO music interface for its active music-mixing software that dynamically categorizes an entire music library based on the mood you are in at any given moment. Adobe added a “Publish to TiVo DVR” option in its Photoshop Album and Photoshop Elements photo organization and editing software, and soon thereafter Picasa followed suit adding similar functionality to its Digital Picture Organizer product.

7

Chapter 1 HMO fell short in gaining developer excitement, hampered by the inability to create truly unique and valuable applications for the TiVo platform because of the limitations of the template framework environment. However, all of this changed dramatically in early 2004 when TiVo purchased a small company called Strangeberry, which, led by Arthur Van Hoff, a seasoned software engineer from Sun’s Java labs, created a robust platform for delivering broadband content to low-powered television-connected devices. TiVo feverishly began work to merge the Strangeberry technology into its Series2 TiVo boxes, and by November of 2004, TiVo delivered the first early release version of a flexible and completely open source Java SDK initiative for creating network-powered applications for TiVo boxes, and dubbed it the Home Media Engine.

Home Media Engine Home Media Engine (HME) is truly designed to allow full-fledged applications to display on the TiVo box. Though Home Media Option gave birth to networking and access to music and photos on a desktop machine, the interface on the TiVo box remained constrained, and all events (such as pressing a button on the remote) were handled by software on the TiVo box. The basic model in Home Media Option, to make a directory structure of information available via HTTP for access from the TiVo, is extended in HME to create a full event processing system so HME applications can process remote control key presses, display custom interfaces, control sound effects and audio streams, and launch complex animations and screen transitions. This brought forth the ability to write and run truly custom network-powered applications on the TiVo box for the first time. As you can see in Figures 1-6 and 1-7, the user interface is far more flexible than the HMO interface (shown in Figures 1-1 and 1-2). HME builds on several components that were originally introduced in HMO: ❑

Network access: TiVo HME applications don’t actually run on the TiVo box itself — they typically run on a local desktop machine or on a server over the Internet.



Auto Discovery: TiVo HME applications announce their availability similar to the way HMO announcements function through ZeroConf. (“ZeroConf” describes a set of technologies that provide some level of automated network addressing and discovery.)

HME introduces a new protocol for communication with the TiVo box that allows you as the developer to lay out the graphics and play sounds on the TiVo box in almost any way you can think of, as long as you bear in mind that the TiVo box has limited resources and processing power to create the display. Despite the limitations of the TiVo hardware platform, you can create very sophisticated applications, and you can take steps when writing your applications to ensure what they intend to display onscreen survives.

8

Introduction to TiVo Applications The variety of applications for TiVo HME is far greater than what is available for HMO. The new generation of applications includes access to information in your Yahoo account such as local weather, movies in the area, and traffic information. Live 365 has a radio station application that streams audio from the Internet to the TiVo box and provides a great selection of music. Users of Fandango can use Fandango’s TiVo HME application to browse and purchase movie tickets. TiVo has produced applications that range from games to podcasting players to an application to predict who will be voted off of American Idol. Independent software developers have written applications, such as AudioFaucet (shown in Figure 1-6 and written by the authors of this book), to play audio from your music library. Open source applications such as Galleon (Figure 1-7, the rebirth of JavaHMO as an HME application) do everything the original JavaHMO did, but offer a more elegant user interface. Apps.tv, located at http://www.apps.tv, is a web site that hosts many HME applications that can run over the Internet. Like the applications that TiVo hosts, apps.tv-hosted applications run over the Internet and range in functionality from a browser for Flickr photo galleries to fun family games written by independent developers using the HME software development kit.

Figure 1-6

9

Chapter 1

Figure 1-7

Software Development Kit One of the reasons HME development has grown so quickly is because of the software development kit (SDK) that TiVo released along with HME. With all the plumbing for managing events from the TiVo box and built-in capabilities for displaying images and playing sounds through the TiVo box, the creation of an SDK for HME was a huge step forward in making development of HME applications simpler, faster, and more powerful. Applications that before had to rely on processing HTTP requests could now implement event models in the SDK and the application lifecycle, allowing much more sophisticated applications to be developed. The SDK for HME was released in November of 2004 as an open source project, and is available from http://tivohme.sourceforge.net. Developed in Java, the HME SDK allows developers to leverage a wide variety of other open source and free libraries available, as well as mature Java development tools such as Ant, NetBeans, and Eclipse. Along with the Java SDK, TiVo also introduced a library called “Bananas,” which has tools for displaying standard TiVo interface widgets such as lists, screens, and buttons and providing an application the ability to easily have the familiar look and feel of a built-in TiVo screen. As every TiVo user knows, a highly intuitive and responsive interface is one of the great successes of the TiVo experience.

10

Introduction to TiVo Applications The documentation for the protocol that HME uses to communicate with the TiVo box is also available in the HME documentation. This is significant because it means that programming languages other than Java can be used with the HME protocol. Although the official TiVo HME SDK is in Java, applications have been written in other languages using the open protocol for HME. This book covers the Java SDK, because it is the official SDK from TiVo and because the concepts of handling events and working with the processing limitations of the TiVo hardware to create an application are applicable to any HME development.

How HME Interacts with TiVo As mentioned earlier, the HME application runs either hosted on a server on the Internet or on a desktop machine within your home network. The TiVo box acts as a client, and displays the user interface as directed by the server, collecting input via remote control keys and sending the key press data back to the server for processing, as shown in Figure 1-8.

TiVo

Events

Home Network

Commands

Events

Desktop hosting HME Application

Commands

Events

Commands

Internet

Events

Server hosting HME Application

Remote Control

Commands

Figure 1-8

What HME Is and Isn’t HME, at the time of this writing, is a separate runtime environment on the TiVo box to run applications that provide access to information, games, and pretty much anything a creative developer can imagine. Access to internal information and other functions on the TiVo box outside of the HME subsystem and display model are not possible at this time. That is, HME does not allow access to any DVR functionality on the TiVo box, nor access to any of the local resources (such as recordings) that are stored on the TiVo boxes.

11

Chapter 1 HME runs only inside the runtime environment, which acts as a sort of sandbox for applications, in effect partitioning them safely from possibly interfering with normal DVR functionality. Therefore, HME does not allow an HME application to do the following: ❑

Display information over live TV



Overlay or manipulate any of the video content



Access to view or manipulate electronic guide data



Access to view or manipulate a user’s season passes or recording preferences

HME does, however, make the TiVo box that is already connected to your TV, sound system, and home theater into a platform with access to a far greater range of functionality, and provides the most natural way to bring new applications into the living room — using the TiVo box that has already endeared itself as a permanent part of the household’s digital lifestyle.

Summar y The TiVo platform is essentially a low-powered personal computer that up until recently was marketed as a simple and elegant alternative to a VCR. It’s built upon the Linux platform and therefore received quite a bit of attention initially from the developer community in order to make the TiVo more useful, including hacking hardware in order to add the TiVo to the household network. TiVo embraced that idea when building the Series2 hardware platform and included networking support in the form of USB ports with the reference platform. Later TiVo expanded the hardware to directly include a wired Ethernet port. TiVo HMO was introduced as the first application platform mainly intended for developers to extend their PC-based digital home media catalog applications to allow music and photos from those applications to be accessed directly from the TiVo box through a series of prebuilt templates designed by TiVo. The TiVo HME platform is intended to offer application developers a much more flexible method for developing full-fledged application interfaces for display to the TV through the TiVo box, limited in most cases only by the imagination and creativity of the developers themselves. Though HME applications display on the TiVo box, they do not allow access to play or overlay any video, manipulate DVR functionality, or access to any of the local resources (such as guide data, season passes, or recordings) that are stored on the TiVo box itself.

Questions 1. 2.

12

What are the core differences between HMO and HME? What are the main limitations of HME on the TiVo box?

2 Getting the TiVo Box Ready for HME The first steps in being able to leverage the exciting HME platform are to make sure that your TiVo box supports HME and has an active subscription, and to make your TiVo box an active participant of your household network. As a programmer, you might already be aware of what is required to allow a TiVo box to access HME content; however, it’s important to walk through the options anyway in order to help you easily support future users of your HME-based applications. In this chapter you learn: ❑

Which TiVo models support the HME applications



Various TiVo subscription models and which models support HME



How to make sure your TiVo box has the latest software updates installed



How to get the TiVo box online in a wired or wireless household network



How to use a few of TiVo’s hosted HME applications

TiVo Requirements for HME As mentioned earlier, the TiVo box platform is a small personal computer; however, not all TiVo box models are created equal. Depending on the model that you have, it may not have the hardware or software required to support HME applications. This section describes the currently available TiVo box models at the time of this writing, and outlines which specific platforms will allow you to get your TiVo box on the household network and allow you to use HME applications.

Supported TiVo Boxes TiVo boxes have been on the market since March 31, 1999, and through many partnerships with hardware vendors and service providers over time, have delivered a flurry of TiVo models to the market. TiVo boxes can be grouped into two categories: standalone and integrated.

Chapter 2 Standalone TiVo boxes are designed to act as a sidecar to any existing set-top box or just go in line with your analog video signal direct from your rabbit ears. Inside the box it has an MPEG encoder chip that takes any signal that is sent to its inputs and writes an encoded stream to the hard drive. The end users have the ability to choose the amount of compression that they would like the TiVo box to use while encoding their video. A higher compression ratio allows the TiVo box to fit more programming in the box, but the resulting video playback will be of a lower quality. Integrated TiVo boxes are built directly into a digital satellite receiver. They do not allow the input of external signals and do not contain an MPEG encoder chip. Instead, the integrated TiVo boxes take a digital signal stream being broadcast to the receiver and write that directly to the hard drive. The end user does not have the ability to adjust the quality of the compression being used, but the end result is that anything played back on an integrated TiVo box is in the exact quality in which it was received, preserving any HD (High Definition) or 5.1 surround sound data that was included in the original broadcast as well. Within each of these categories there are different generations of TiVo box hardware platforms. The initial TiVo box hardware platform is now referred to as Series1; it lacked any home-networking support and is therefore incapable of making use of any HME applications. The second generation of the TiVo box hardware platform (aptly named Series2) added many new features, one being the ability to easily join a household network and take part in HME application goodness. The latest generation of the TiVo box hardware platform, the Series3, adds even more horsepower to the platform and proves TiVo’s commitment to extending the household network-enabled home media experience.

Series1 Standalone The original TiVo box hardware platform was manufactured and distributed through Philips and Sony and is now referred to as Series1. The Series1 TiVo box was based on a lower-powered PowerPC processor and did not include USB ports for future expandability. It relied on an internal modem and an analog telephone line to connect to the TiVo servers and acquire subscription status and electronic programming guide information. A few talented enthusiasts put together an ingenious way to rip open the Series1 TiVo box and add a custom-built network adapter, but due to the lack of CPU horsepower and the warranty-voiding nature of breaking the factory seal on the box, TiVo never made available a PowerPC version of HMO or HME runtimes for the Series1 TiVo box. At first glance it can be difficult to differentiate from looking at the TiVo box if the platform is Series1 or Series2 because the initial runs of Series2 share the same Series1 enclosure. The following table shows the make/model numbers of the Series1 TiVo boxes to make it easy for you to know for sure if the TiVo box you own is a Series1 TiVo box and does not officially support TiVo-provided household network integration.

14

Equipment Manufacturer

Manufacturer Model Number

Network Support

Philips

PTV100

No

Philips

HDRxxx

No

Sony

SVR-2000

No

Getting the TiVo Box Ready for HME Series2 Standalone The second generation of TiVo box hardware platform was called Series2. TiVo moved the platform to a more powerful MIPS-based processor and created the platform with expandability in mind, adding two USB ports to the back of the box. This initially allowed users to free themselves of the telephone cable used to collect service and guide data from the TiVo server farm by adding a USB network adapter and adding the TiVo to a home network. Series2 also added the ability for manufacturers of a TiVo box to include an integrated internal DVD drive for playing back your favorite non-TiVoed movies and easy archiving of TiVo-recorded content to DVD without the need to transfer and convert the video on a PC. Out of the gate, the TiVo Series2 supported a small subset of wired Ethernet adapters and then shortly after added support for a select few wireless adapters. The newest member of the Series2 family is the Series2 DT (Dual Tuner) TiVo box, which has a built-in Ethernet port, saving the average user the extra effort required to find a compatible adapter online. More details about which adapters the Series2 platform officially and unofficially supports are found later in this chapter. Starting with Series2, TiVo also started to manufacture and distribute TiVo boxes itself, although TiVo continued to partner with hardware manufacturers to manufacture and distribute their own Series2based hardware. As stated earlier, it can be difficult to know which version of TiVo platform you are using at first glance. The following table shows a list of currently released Series2 TiVo boxes to make it easier to distinguish if your TiVo box can support household networking features. Equipment Manufacturer

Manufacturer Model Number

Network Support

TiVo (also AT&T)

TCDxxx

Yes

Hughes

HR10

Yes

Humax

DRT-800xxx

Yes

Humax

T800

Yes

Humax

T2500

Yes

Pioneer

810H or 57H

Yes

Pioneer

DVR-xxx

Yes

Sony

SVR-3000

Yes

Toshiba

RS-TXxx

Yes

Toshiba

SD-H400

Yes

DirectTV Integrated TiVo (DirectTiVo) In 1999, TiVo announced a deal with DirectTV, which brought forth a new set of TiVo platform hardware that included an integrated satellite decoder that is also capable of recording two programs on separate channels at the same time. TiVo fans quickly nicknamed this hardware platform the DirectTiVo. Initial DirectTiVo models were based on the Series1 hardware platform, but TiVo updated the DirectTiVo platform to the Series2 hardware reference platform in 2002.

15

Chapter 2 Whereas the DirectTiVo boxes based on the Series1 platform are unable to officially participate in household networks, the Series2-based hardware is capable of such tasks. Unfortunately for reasons that were never fully disclosed (many feel it was the possibility of the pristine digital content stored on the TiVo being easily shared over the Internet), TiVo was unable to convince DirectTV that household networking features were key for allowing DirectTV to expand its offering. As of this writing, DirectTiVo still relies on an internal modem and an analog telephone connection to acquire DirectTV’s program guide information and subscription status, even though the newer models include USB ports on the back of the box and technically could easily support being added to a household network. DirectTiVos have their own look and feel, including some buttons on the front bezel of the TiVo box that mimicked the main TiVo remote control buttons, allowing users to quickly interact with their TiVo boxes if they can’t easily find their remote. However, there is nothing stopping a DirectTV customer from using a standalone Series1 or standalone Series2 TiVo box in order to record their favorite shows. Because of this, it is possible that DirectTV subscribers could still be able to run HME applications on their standalone Series2 boxes. The following table is a matrix that calls out the DirectTV boxes specifically. Equipment Manufacturer

Manufacturer Model Number

TiVo Hardware Platform

Network Support

Hughes

GXCEBOT

Series1

No

Philips

DSR6xx

Series1

No

Sony

SAT-T60

Series1

No

Hughes

HDVRx

Series2

Not yet

Hughes

HR10-250

Series2

Not yet

Hughes

SD-DVRx

Series2

Not yet

Philips

DSR7xx

Series2

Not yet

RCA

DVRxx

Series2

Not yet

Samsung

SIR-Sxxxx

Series2

Not yet

Series3 In January 2006 at the Consumer Electronics Show, TiVo announced that it was going to be allowing everyday cable customers to join the HD time shifting trend without being tied to the often lowerquality cable DVR offerings. The box hardware platform is called Series3 and it supports full dual-tuner HD recording, embracing the CableCard standard that allows any television device to directly accept cable signals that can be decoded directly on the box, removing the need to rent a digital decoder box from the cable company. In many ways this box is a grown-up version of the HD versions of DirectTiVo. However, because TiVo has full control over the hardware and software platform this time around, this box fully supports the TiVo household network features, and much like the Series2 DT, includes a full-speed Ethernet port on the back of the box to prove it.

16

Getting the TiVo Box Ready for HME At the time of this writing, there is only one model of the TiVo box that makes use of the Series3 hardware platform, sometimes referred to by TiVo as the TiVo HD. TiVo-branded Series3 DVRs are easily identifiable by the unique and stylish front bezel, which includes a beautiful OLED digital display that supplies the current status of the box. Equipment Manufacturer

Manufacturer Model Number

Network Support

TiVo

TDC6xx

Yes

Active TiVo Service Subscription In order to use any of the TiVo box household network features, you need to be sure that your TiVo has an active TiVo Plus service subscription. Some of the Series2 TiVo boxes manufactured and distributed through TiVo hardware partners bundled a level of subscription service called TiVo Basic. A TiVo Basic service subscription doesn’t require a user to pay any ongoing fees to TiVo to use the basic DVR functionality in the box, but only includes three days’ worth of electronic programming guide data, and strips away most of TiVo’s unique features, including the household networking features required to use HME-powered applications. Any customer that either has a Lifetime TiVo Service enabled on their Series2 or Series3 TiVo box, or is paying a yearly or monthly fee to use their TiVo box, has a TiVo Plus subscription and is free to make use of all of the services TiVo has to offer, including those provided by HME. A user can upgrade at any time to TiVo Plus service by contacting TiVo.

Checking the Version of TiVo Software TiVo first enabled HME in version 7.1 of its TiVo box software platform, although in order to use any HME applications, you had to issue a backdoor code via your remote to the TiVo box. This was done mostly to allow developers to work on TiVo HME-based applications but keep the average TiVo user in the dark while they worked some of the major kinks out of the HME delivery system. HME was officially enabled in software version 7.2 for all active TiVo Plus service subscribers. It is fairly easy to see which version of software your TiVo box has running on it at the moment. On all software versions, the process starts by pressing the TiVo button on the remote control, which will bring you to the TiVo main menu titled “TiVo Central.” From the TiVo Central screen, navigate into “Messages & Settings” or “Messages & Setup,” then “Account and System Information” (some units will not have this screen based on their software version), and finally select “System Information.” From there, you will be able to see the software version information that is currently running on your TiVo box, as seen in Figure 2-1. If you have just acquired a Series2 TiVo box that has been sitting in a warehouse or bought at a garage sale, your TiVo box may very well have an older version of the software on the box. No need to fear however, because any TiVo that has an active service subscription will be upgraded to the latest software that TiVo has to offer once it connects to the TiVo servers.

17

Chapter 2

Figure 2-1

Unfortunately in order to use most USB network adapters, you may need to wait for your TiVo box to download and install the latest software updates utilizing an analog telephone line and the built-in modem on the TiVo box. This process can take a while to finish, but once you are on the latest software build, every supported network adapter will work for you going forward. If your TiVo box’s service was just activated, it may take a few days in order for your update to happen automatically. You can, however, speed up the process by forcing your TiVo box to make a connection to the TiVo servers.

Forcing a Connection to the TiVo Service By default, the TiVo box will use either an available supported network adapter or the built-in analog telephone modem to connect back to the TiVo server farm automatically every day or two to collect updated guide data, get subscription status, and check for TiVo box software updates. You can force a connection to the TiVo servers at any time directly from within the menu system on your TiVo box. The process varies slightly based on the version of software currently running on the TiVo box:

18



Software versions 3.x: On the TiVo Central screen, navigate into “Messages & Setup,” then “Recorder & Phone Settings,” and finally select “Make Daily Call Now.”



Software versions 4.x–7.1: On the TiVo Central screen, navigate into “Messages & Setup,” then “Settings,” then “Phone & Network Settings,” and finally select “Connect to TiVo Service Now.”



Software version 7.2+: On the TiVo Central screen, navigate into “Messages & Setup,” then “Phone & Network,” and finally select “Connect to TiVo Service Now.”

Getting the TiVo Box Ready for HME At the start of the connection process, a new screen appears that will show the progress of the connection. TiVo box software updates can be rather large compared to the relatively small amount of data that is downloaded during a normal call home. You can be pretty sure that you are receiving a software update if the progress screen stays on the downloading status indicator for a long period of time. When your TiVo box finds a software update, it will immediately download the update and queue it up to be automatically installed at 2:00 AM the following day. Once the connection to the TiVo service is complete, you will be brought back to the Phone and Network settings screen. If you see the Last Status area showing “Pending Restart,” your TiVo box has prepared itself to issue a system update and restart the following morning. There is no need to wait until the next day to start the update process. If you are pretty sure that your TiVo box is not set to record any new content in the next hour (time can vary based on the update), you can now gracefully restart the TiVo and kick off the software update right away. Again, this process varies slightly based on the version of software currently running on the TiVo box: ❑

Software versions 3.x: On the TiVo Central screen, navigate into “Messages & Setup,” then “System Reset,” and finally select “Restart the Recorder.”



Software versions 4.x-7.1: On the TiVo Central screen, navigate into “Messages & Setup,” then “Restart or Reset System,” and finally select “Restart the DVR.”



Software version 7.2+: On the TiVo Central screen, navigate into “Messages & Setup,” then “Restart or Reset System,” and finally select “Restart the TiVo DVR.”

The TiVo software will bring up a screen that challenges you to press the Thumbs Down button three times and then the Enter button just to be sure you really want to restart the box. In general, restarting your TiVo box isn’t something that you need to be afraid of; however, carefully read the screens while selecting settings in the Restart and Reset System menu because you could accidentally select other menu items that will remove all of your season passes and recordings. Once the TiVo system update is complete, you will be greeted by the TiVo startup animation as well as a full-screen message that welcomes you to the new software update and explains any new features that may have been added.

The Household Network Now that your TiVo box is up and running with the latest software release, you are ready to go ahead and configure the TiVo to join your household network if it isn’t already. There are a few things that you need to be aware of in order to make sure that the TiVo box is able to participate with HME hosting environments whether they are server based, as TiVo’s applications are, or hosted on a personal computer within your household network. By default, the TiVo HME environment requires a broadband Internet connection to be available in order to work; with some wizardry you can override the sections of the existing HME SDK that require this, and you’ll learn more about that once you write a few apps of your own. Most households today have a network within their home in order to allow their computers to share the broadband Internet connection delivered from their cable or DSL provider. For those that do not have an

19

Chapter 2 existing network, setting up one from scratch is rather simple and normally involves a quick trip to a local electronics store to pick up an inexpensive household router. There are some choices that need to be made along the way, as discussed next.

Wired vs. Wireless The first thing you will need to consider when getting your household network ready to accept your TiVo box is which method you will be using when you tie it to the household network. Though it may be difficult or unsightly to haul an Ethernet cable all the way from your router to the location of the TiVo box, a wired connection will be faster, less expensive, more secure, usually troublefree, and far easier to deploy. In our experience, wired adapters give the best HME experience and have the added benefit of increasing the download speed for TiVo2Go recordings. Wireless networks are invisible; however, they are far slower than a wired network, are usually more expensive, are often less secure (most people never bother to configure the security features on their wireless routers and even those that do are only slightly more secure than never configuring it in the first place), are plagued with signal loss issues depending on the environment that they are being deployed into, and tend to be a bit more tricky to configure and deploy. One other consideration: In the Fall 2006 Service Software Release, TiVo added support for Wi-Fi Protected Access (WPA) if you use the TiVo-branded wireless adapter, which is really the only secure way to protect the devices on a wireless network from intruders. If you do not have a TiVo-branded wireless adapter and have other wireless devices on your home network currently using WPA, you must disable it and use something less secure (like Wired Equivalency Privacy, or WEP) on all those devices in order to place your TiVo on that network. WEP really provides little or no actual protection; even 128-bit WEP is very easy for someone nearby your house to crack. Keep this in mind as you’re making your choice. The good news is that all current wireless routers also support wired connections as well, so even if you are only intending to deploy a wired network to the TiVo box, you may want to consider getting a wireless-enabled router, because the type of network adapters you decide to deploy within the home can easily change over time. You will need to weigh this decision based on security, the layout of your home, and the ability for you to easily snake wires between rooms if need be.

Network Adapters You will find that potential customers of your HME applications will ask you for advice in getting their various TiVo boxes online. In reality, the reference hardware inside of most of the common network adapters today are shared across multiple vendors. Much like TiVo sells its reference platform to manufacturers to support TiVo DVR functions in their products, network adapters often share the same few chipset variants inside their branded case. To get a complete up-to-date listing of the exact version of wired network adapters that are known to work with the various hardware versions of the TiVo box, be sure to check TiVo’s web site at www.tivo.com/adapters.

Wired Adapters Any TiVo Series2 DT or Series3 box includes a wired Ethernet interface integrated into the back of the box, which of course is fully supported by the TiVo software. Following is a chart of the officially TiVocertified USB wired network adapters that work on all Series2 TiVo boxes. TiVo has been working hard

20

Getting the TiVo Box Ready for HME to expand its wired network adapter support, but it is still possible today to get an adapter that seems to work for some tasks but just can’t handle others tasks very well at all (Auto discovery is an example). Equipment Manufacturer

Manufacturer Model Number

Linksys

USB200M Ver. 1

Linksys

USB200M Ver. 2

Linksys

100TX

Wireless Adapters Depending on the manufacture run of the TiVo box that you own, choosing a wireless adapter can be a daunting experience. TiVo recognized this challenge and in January of 2006 released a TiVo-branded 802.11g wireless network adapter. Unlike normal USB wireless network adapters, this one has specialized firmware and chipset components that make this the most compatible and fastest wireless network adapter available for the TiVo hardware platform. In fall 2006, TiVo added support to its adapter for WPA security, offering better security on your wireless home network. We highly suggest that if you do need to have your TiVo box join a wireless network that you seek out the TiVo-branded adapter. Following is a table of the officially TiVo-certified USB wireless network adapters that work on all Series2 and Series3 TiVo boxes, along with the wireless standard in which they can connect. Equipment Manufacturer

Manufacturer Model Number

Wireless Standard

D-Link

DWL-120 Version E

802.11b

Linksys

WUSB11 Version 2.6

802.11b

Linksys

WUSB11 Version 2.8

802.11b

TiVo

AG0100

802.11g

Adding TiVo Boxes to a Household Network TiVo has made it fairly easy to get your TiVo box online provided that you are running the latest versions of its software and have a compatible or built-in network adapter. It provides wizards that should walk you through the process of getting the router on your household network to welcome the TiVo box into its world. The following section describes how to find currently supported adapters and also goes over the steps required to activate the connection and configure any TCP/IP settings along the way.

Setting up Wired Access Often the only step required to get a TiVo box online via a wired household network is to attach the network adapter to one of the TiVo box’s USB ports and connect the Ethernet cable between the router and the Ethernet port on the network adapter. The TiVo box will try its best to recognize the network it is connected to and be handed an IP address via DHCP by the router. If you do not have DHCP set up on the router, you will need to go into the TCP/IP settings menu on the TiVo box and configure your IP settings manually. You will walk through that later in this chapter, because the settings are the same for both wired and wireless adapters.

21

Chapter 2 If you get stuck along the way, you can also check out TiVo’s extensive help on networking your TiVo at http://www.tivo.com/4.9.1.2.asp.

Setting up Wireless Access In order to allow your TiVo box to find and attach itself to your wireless household network, you need to set a few configuration settings on the TiVo box itself. If you have not yet connected the USB wireless adapter, you should do that at this time. The following directions assume you are running on TiVo box software version 7.2 or higher. On the TiVo Central screen, navigate into “Messages & Setup,” then “Settings,” then “Phone and Network,” and finally select “Change Network Settings.” You will then be presented with a list of nearby wireless networks. Be careful to select only a network that you know is yours. The applications that you are creating with the TiVo HME SDK will rely on your personal computer and the TiVo box itself to co-exist inside of the same logical network. If WEP or WPA encryption is enabled on your wireless gateway, you will be asked to enter the secure network key. Choose the proper key method and use the TiVo remote control to enter the key. The TiVo box will try its best to recognize the network it is connected to and be handed an IP address via DHCP by the router. After you finish entering the wireless configuration settings, the TiVo box will then attempt a test connection to the Internet. If this test is successful, you will be prompted that network configuration has completed. You may otherwise be prompted to manually configure the IP address settings for your TiVo box. You walk through that in the next section, because the process for applying the changes will be the same for both wired and wireless adapters.

TCP/IP Settings If you do not currently have DHCP enabled on your household network router, you need to tell the TiVo what settings it needs to connect to your network. Before you start, you should collect the appropriate IP address, subnet mask, router address, and DNS address. The following directions assume you are running on TiVo box software version 7.2 or higher. On the TiVo Central screen, navigate into “Messages & Setup,” then “Settings,” then “Phone and Network,” and finally select “Change Network Settings.” If you are connecting from a wireless adapter, you will see a few screens that go over your wireless network settings again. These settings should be remembered from your previous network configuration. Once you confirm the wireless network to join and enter any network security key you might need to access that network, you will then be brought to the IP address settings screen. The IP address settings screen will let you choose between getting your IP configuration settings via DHCP or allow you to enter specific IP address information for joining your household network. If in the future you decide to enable DHCP on your router, you can easily come back to this screen and reenable automatic IP configuration.

22

Getting the TiVo Box Ready for HME From the IP address screen, select the option to let you specify a static IP address. You will be greeted with a page reminding you to collect the appropriate IP network information needed to manually set up the network connection. Once you are sure you have all the needed information, press Select on the TiVo remote control to continue on. You will then be prompted to use the remote control buttons to enter an IP address. The TiVo box will then make a best guess for the rest of your configuration settings based on the IP address you entered. You can choose at that point to either accept the settings or enter the rest of the network information correctly yourself. After you have finished entering the IP information, the TiVo box will then attempt a test connection to the Internet. If this test is successful, you will be prompted that network configuration has completed. Again, if you have problems getting your TiVo connected to the network, see TiVo’s home networking help pages at http://www.tivo.com/4.9.1.2.asp. TiVo’s Customer Support can also help you out; you can find customer support contact information at http://www.tivo.com/5.9.4.asp.

Music, Photos, & More Once your TiVo box is connected to the Internet you will notice that a new menu appears on the TiVo Central screen called “Music, Photos, & More.” This is where all of TiVo’s network-powered applications live. By default, all network-enabled Series2 TiVo boxes have a few HME applications available to them, as shown in Figure 2-2, that are hosted directly from TiVo’s server farm over the Internet.

Figure 2-2

23

Chapter 2 Try It Out

TiVo Server-Hosted HME Applications

This is a great opportunity to start a few of the applications that TiVo has created using the HME SDK and get a good idea of what the HME platform is capable of. ❑

Yahoo! Photos: View photos that are shared online through Yahoo! Accounts.



Yahoo! Weather: Check your local five-day weather forecast.



Yahoo! Traffic: Get updates on your local traffic patterns before heading out on a journey.



Browse & Buy Movie Tickets: Access Fandango to research and buy local movie passes.



Live 365: Access a wide variety of Internet radio streams delivered directly to your TiVo box.



Podcaster: Listen to the latest home-brew talk shows about the subjects you enjoy most.



SameGame: Find connected orbs of like kind and clear the screen to achieve points.



Wordsmith: Build words with Scrabble-like tiles to spell your way to the high score.



Skull & Bones: Connect Four, pirate style. Can be played alone or with two players.

Summar y After reading through this chapter, you should now have a keen idea of what the prerequisites are for allowing your HME applications to run within the average household. When supporting your users, a few key concepts need to be kept in mind:

24



The original TiVo box models, now referred to as Series1, do not officially support network connections, nor do they have the software needed to run TiVo HME applications.



Second-generation TiVo box models, referred to as Series2, were built with expandability in mind and have the ability to support network connections via external USB adapters.



The current generation of TiVo box hardware, referred to as Series2 DT (Dual Tuner) and Series3, have built-in Ethernet ports allowing users to connect to networks without the need to bother with external adapters.



DirectTV-enabled Series2 TiVo box models, referred to as DirectTiVo, have USB ports that are currently software disabled due to a decision made by DirectTV. It is unclear if network-based applications will ever be allowed to run on DirectTiVo boxes.



TiVo HME was made active for all TiVo Plus and Lifetime subscribers in version 7.2 of their system software. Active TiVo subscribers are always updated to the latest and greatest TiVo box software platform when their unit makes its daily calls home.



As TiVo updates, the supported network adapters that can be connected over USB new drivers are added as part of the software update. You can see if you have a supported adapter at http://www.tivo.com/adapters.

Getting the TiVo Box Ready for HME

Questions 1.

What TiVo hardware reference platforms can network-enabled applications run on? Are there any exceptions to this rule?

2. 3.

Which levels of TiVo service support TiVo network-enabled applications? Which menu item within the TiVo must users go to in order to launch network-enabled applications?

25

3 Your Development Environment A well-tuned development environment is to a programmer what sharp tools are to a sculptor. Setting up a development environment that is flexible and efficient is one of the single most important steps a programmer can take toward being productive and producing high-quality work. This chapter covers setting up the TiVo HME SDK in your development environment and usage of common development tools in Java such as Ant and Eclipse. Though it is certainly not required to use an integrated development environment (IDE) like Eclipse, it definitely helps the developer overcome more mundane problems that can make learning a new technology much more difficult. By the end of this chapter, you will: ❑

Have the required software in order to use the TiVo HME SDK



Know the main libraries of the HME SDK



Be able to use the HME SDK in Eclipse



Be able to use the HME Simulator to test HME applications

Required Software In order to develop software using the TiVo HME SDK, you need some additional software along with the SDK to get started. At minimum, you need a Java SDK installed and a text editor to write your code.

Chapter 3

Java SDK First, to develop Java software, you need to make sure you have a current version of the Java SDK installed.

Windows To check to see if you have a Java SDK installed, open a command-line window in Windows. At the DOS prompt, type the following: C:\> javac ‘javac’ is not recognized as an internal or external command, operable program or batch file.

If the preceding output is shown, you can download a Java SDK at http://java.sun.com/downloads/. Output such as C:\ >javac -version javac 1.5.0_06 javac: no source files Usage: javac where possible options include: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are u sed -classpath Specify where to find user class files -cp Specify where to find user class files -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -endorseddirs Override location of endorsed standards path -d Specify where to place generated class files -encoding Specify character encoding used by source files -source Provide source compatibility with specified release -target Generate class files for specific VM version -version Version information -help Print a synopsis of standard options -X Print a synopsis of nonstandard options -J Pass directly to the runtime system

would indicate the Java SDK is already installed. The JDK 1.4.1 is the minimum required for the TiVo HME SDK and any version greater than 1.4.1 should work. The latest Java SDK at the time of writing this book is 1.5.0 release 7.

28

Your Development Environment Mac OS X Apple packages Mac OS X with the latest version of Java available at the time of release, so the newest Macs that ship with OS X 10.4 come with Java 1.5.0. Previous versions of Mac OS X may not have the most recent version of the Java SDK. Normally Java updates can be installed using Software Update (available from the Apple menu) or by downloading and installing the update manually from http://www.apple.com/support/downloads/ (search for Java). You can check to see which version of Java is installed on your system by opening the Terminal application (located in the Utilities folder inside the Applications folder) and running the following: $ javac -version javac 1.5.0_06 javac: no source files Usage: javac where possible options include: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are used -classpath Specify where to find user class files -cp Specify where to find user class files -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -endorseddirs Override location of endorsed standards path -d Specify where to place generated class files -encoding Specify character encoding used by source files -source Provide source compatibility with specified release -target Generate class files for specific VM version -version Version information -help Print a synopsis of standard options -X Print a synopsis of nonstandard options -J Pass directly to the runtime system

The first few lines of output will indicate the Java version installed on your system.

Linux and Unix The HME SDK is written entirely in Java, so it will run on any platform that supports at least the Java SDK 1.4 or better. Java SDKs can be downloaded for other operating systems from Sun’s web site, found at http://java.sun.com.

29

Chapter 3

Text Editor Which text editor you use to edit Java code does not really matter, only that you are comfortable using it. There are text editors that specialize in editing Java code and may make the work easier. JEdit is a text editor that is designed for editing Java code. It is available for download at http://www.jedit.org/. Text editors such as TextMate for Mac OS X or Notepad++ for Windows are other powerful text editors. For development, we generally use the Eclipse IDE, which provides a text editor as well as many other conveniences for coding in Java.

Getting the TiVo HME SDK The TiVo HME SDK is available for download from http://www.tivo.com/developer/. The core of the TiVo HME SDK is at version 1.4.0 at the time of writing. After downloading the ZIP file containing the TiVo HME SDK, unzip the file somewhere on your machine where you wish to store the SDK.

Exploring the SDK The unzipped folder hme_sdk_1.4 contains several files and folders: ❑

doc



hme-host-sample.jar



hme.jar



images



LICENSE-CPL.html



LICENSE-LGPL.txt



README.html



samples



simulator.jar



src.zip

The doc folder contains the documentation for the SDK, including a ZIP file of the Javadoc and hmedevguide.pdf, which is an overview of the SDK. The Javadoc is certainly documentation that you will frequently want to refer to when writing applications. It provides an explanation of the objects and methods that make up the SDK, and is frequently a great way to discover new methods and ways to do new things with your code.

30

Your Development Environment The two jar files, hme-host-sample.jar and hme.jar, are the libraries that you will include when building your application. These jar (Java Archives) files contain the HME objects that you will use throughout the book.

Classpath This section is only necessary if you’ll be using the HME SDK from the command line. If you intend to use Eclipse for your development, you can skip this section. CLASSPATH is the system variable that Java uses to determine where to search for libraries that are needed to run programs. It also can tell Java where to load resources such as images from.

To use the HME SDK at the command line, you will need to add the two previously mentioned jars to the CLASSPATH. In Mac OS X and Linux, at the command-line prompt, you would run export CLASSPATH=$CLASSPATH:/hme.jar:/hme-host-sample.jar

If you are running the bash shell or if you are using tcsh, type: set CLASSPATH $CLASSPATH:/hme.jar:/hme-host-sample.jar

On Windows, type: set CLASSPATH=%CLASSPATH%;\hme.jar;\hme-host-sample.jar

To set these variables for every command line: Linux or Mac OS X users: The preceding lines should go in your .bashrc or .tschrc file inside your home directory. Windows users:

1. 2. 3. 4.

Right-click My Computer and select Properties. Select the Advanced tab. Select Environment Variables. Edit the CLASSPATH variable as shown in Figure 3-1.

31

Chapter 3

Figure 3-1

Recommended Software There is a vast amount of Java software available, some of which has become a de-facto standard either for certain aspects of developing software in Java, such as Log4j, or for compiling and building Java software, such as Ant and maven. Though our focus is mainly on coding TiVo HME applications, frequently figuring out either the ancillary aspects of an application (such as logging) or an efficient build process can impede development. With that in mind, here are a few recommended software libraries and tools that make Java development easier.

Ant Ant is a build tool that compiles Java code into an executable. Though this sounds trivial for a few files, when building a large project, it can make the difference between a ten-minute build and a two-hour

32

Your Development Environment build. Ant is available at http://ant.apache.org/, and is installed on Mac OS X in /Developer/ Java/Ant/bin/ant. Ant uses a file called build.xml to determine dependencies of files and tasks. If you’re using an IDE such as Eclipse or NetBeans, it is normally not necessary to learn Ant or create build scripts — the IDE will do it for you.

Log4j Logging errors and debug information from a running application is a task just about every application, large or small, must implement. Log4j has become the de-facto standard in this area, and is widely used by Java developers. As of the 1.4 version of the SDK, TiVo includes its own logging facility, and Java also has its own built-in logging. Which logging approach you take depends on how extensive your logging needs are, and how many third-party Java libraries you’re willing to include with your application.

JDIC JDIC stands for Java Desktop Integration Components. The JDIC library makes integration with desktop systems, particularly on Windows, more complete, allowing access to additional Windows integration not possible using Java alone. The features of the library include the ability to put icons in the System Tray, access System Information, launch Browser windows, and other features that you can use to make your application have the look and feel of a native program.

JUnit This tool has become a standard in unit testing code. If you have never heard of it before, and are serious about writing and testing your code, you should check it out. It can change the way you write and develop applications. Eclipse provides built-in support for creating and running JUnit tests.

Subversion Subversion is a version control system that can be used from the command line and integrates nicely with Eclipse. With more than one person working on an application, version control is practically a must. Even with one developer, keeping track of past changes to the code and version is a powerful tool in determining when a bug was introduced.

Setting up Eclipse There are several integrated development environments (IDE) that are widely used in the Java community: Eclipse, NetBeans, IDEA, and JBuilder. The last two are commercial applications, whereas Eclipse and NetBeans are available for free. Developing code in an IDE can greatly increase your productivity and visibility into the code you are writing. Some would argue that the IDE can hide too much in an effort to make coding simpler, but the debugging environment Eclipse provides, as well as the convenience functions, really provide better visibility into what your application is doing, and how it is structured.

33

Chapter 3

Installation You can download Eclipse from http://www.eclipse.org/downloads/. Look for the “Eclipse SDK” (also called the “Eclipse Platform/SDK”). The package for Eclipse consists of a ZIP file. There is no installer, so you can simply place Eclipse on your system wherever it is most appropriate. On Windows, this would likely be Program Files, and on Macintosh, the Applications Folder. Presently, the current version of Eclipse is 3.2. Any explanations of how Eclipse works should be the same for versions 3.0 through 3.2, if you are running an older version already.

Running Eclipse To start Eclipse, double-click the Eclipse icon inside the eclipse folder that you unpacked during installation. When Eclipse is done loading, a screen similar to Figure 3-2 should be displayed.

Figure 3-2

34

Your Development Environment If you have any problems starting Eclipse at this stage, make sure you have a Java SDK installed on your system, as discussed earlier in the chapter. Additional information on getting help is available at http:// help.eclipse.org/. In this book, all of the Eclipse screen shots are shown using the Mac version of Eclipse. If you’re a Windows programmer, the commands will be the same unless otherwise noted.

Starting a New Project From the File menu, select New, then Project, as shown in Figure 3-3. If you’re prompted for a project type, select Java Project and click Next.

Figure 3-3

35

Chapter 3 The wizard will prompt you for a name for the project. Fill in a name (for example, “TiVoHME_Test”) and click Next. The “Create new project in workspace,” “Use default JRE” (in Windows this option is “Use default compiler compliance”), and “Use project folder as root for sources and class files” radio buttons are selected below the application name. Click Next. On the next screen, the wizard presents you with some of the default values for the project. This tab describes the layout of your project, the files that will be part of the project, and the libraries that will be used as part of the project. All this information can be edited after the project is created, but if you know what libraries are going to be used, this is a convenient place to add them while creating the project. In your case, you know you will be using the TiVO HME SDK libraries, so they should be added on this screen. Click the Libraries tab as shown in Figure 3-4.

Figure 3-4

36

Your Development Environment From the Libraries tab, click the Add External Jars... button on the right to locate the TiVo HME SDK Jars. The two jars from the SDK that you need to build an HME application are hme-host-sample.jar and hme.jar (Figure 3-5). After adding the jars, they should both show up in the Libraries list (Figure 3-6).

Figure 3-5

37

Chapter 3

Figure 3-6

Click Finish to complete the wizard. At this point, if you still see the “Welcome” screen, close it by clicking the little X next to the word “Welcome” on the tab. This displays the default Java development perspective (Figure 3-7). (A “perspective” in Eclipse terminology is a particular layout of windows that contain common things you’ll need. For example, the Java perspective contains windows such as the package explorer, editor, problems list, and outline.)

38

Your Development Environment

Figure 3-7

Running the Sample Applications Along with the HME SDK, TiVo provides sample applications that demonstrate the capabilities of HME programming. The example applications can be run as they are provided in the SDK, and will give you a good idea of the functionality that you will be using in your applications.

39

Chapter 3

Starting the Applications TiVo provides a script file, runsamples.sh, for Mac OS X or Linux, and runsamples.bat for Windows. It is part of the SDK and located in the samples directory. Run the script from the Terminal in Mac OS X, command prompt in Linux, or DOS prompt in Windows. The output should resemble the following: /Applications/Java/hme_sdk_1.4 $ cd samples/ /Applications/Java/hme_sdk_1.4/samples $ ls build.xml launcher.txt music pictures runsamples.sh samples.jar src /Applications/Java/hme_sdk_1.4/samples $ ./runsamples.sh HME SDK 1.4 (TiVo, Inc.) ADDING: pictures/sample1.jpg ADDING: pictures/sample2.jpg ADDING: pictures/sample3.jpg ADDING: pictures/sample4.jpg ADDING: pictures/sample5.jpg ADDING: pictures/sample6.jpg ADDING: pictures/sample7.jpg ADDED: cell1.mp3 ADDED: sample.mp3 . . . MDNS: http://10.37.129.2:7288/animate/ de Volkskrant, 15 articles SLEEPING MDNS: http://10.37.129.2:7288/clock/ MDNS: http://10.37.129.2:7288/fractal/ MDNS: http://10.37.129.2:7288/hello/ MDNS: http://10.37.129.2:7288/pictures/ MDNS: http://10.37.129.2:7288/music/ MDNS: http://10.37.129.2:7288/weather/ MDNS: http://10.37.129.2:7288/skullbones/ MDNS: http://10.37.129.2:7288/videobackground/ MDNS: http://10.37.129.2:7288/effects/ MDNS: http://10.37.129.2:7288/tictactoe/ MDNS: http://10.37.129.2:7288/fontinfo/ MDNS: http://10.37.129.2:7288/rss/ MDNS: http://10.37.129.2:7288/transition/

runsamples.bat

Some of the text in the middle of the output was removed because it is not relevant. The MDNS lines near the bottom of the output indicate that the application is broadcasting its location to the TiVo boxes on the network, and the URL that follows the “MDNS:” indicates the location that the TiVo box should connect to the application.

40

Your Development Environment Examining the runsamples script, you see: java -cp ../hme-host-sample.jar:samples.jar \ com.tivo.hme.host.sample.Main \ --launcher launcher.txt

Note: the preceding line was split for easier reading, but in the runsamples script, it is a single line. This makes use of one of the built-in classes in the SDK, com.tivo.hme.host.sample.Main, to start the applications. When the argument --launcher is passed to this program, it will search the test file for a list of applications to launch. The samples launch several applications, as you can see from the multiple MDNS: lines listed in the output. The samples.jar file, which is included in this command line, is where the sample applications are stored.

Try It Out

Run the Sample Applications on your TiVo

After you run the runsamples.sh or runsamples.bat file in the SDK, the applications will show up in your Music, Photos, Products, & More... menu on the TiVo. To use one of the applications, highlight it and press select or the right directional key. If this is the first time you have used an HME application, the TiVo will prompt you to enable local HME application access before you can continue. Follow the onscreen instructions to enable HME application access. If you don’t see the sample applications listed, you might try changing the settings of your computer’s firewall. Try disabling it temporarily to see if this is the cause of your problem. Another symptom of a firewall-related issue is when you can see the applications listed, but when you try to select one, you get a “Please Wait...” message for several minutes and eventually get an error message.

Using the Sample Applications in Eclipse When first starting Eclipse, it prompts for a workspace. The workspace is simply a directory on your system that contains all of your Eclipse projects. The location of the workspace is also the title of the window shown when Eclipse is running. When first setting up Eclipse earlier in the chapter, one of the steps was to create a new project. Now Eclipse should list that project when opened. You will use this project to import the sample applications and run them under Eclipse. In the directory where the HME SDK is unzipped, there will be a directory called samples. Inside this directory is another directory named src. The src directory contains all the files used to run the sample applications, and the files inside src are the ones that need to be imported into Eclipse.

41

Chapter 3 To import the files, drag the com directory onto the project name in Eclipse. Eclipse will copy the files into the project and organize them correctly (Figure 3-8).

Figure 3-8

42

Your Development Environment After Eclipse has processed the import, your Eclipse workspace should show all the files for the samples, as shown in Figure 3-9.

Figure 3-9

43

Chapter 3 Try It Out Running the Clock Program from Eclipse 1. From the Run menu, select Run.... 2. Select Java Application in the options on the left and click the new icon near the top of the options (it has a document with a + on it). (On Windows, click the New button at the bottom left.)

3.

On the Main tab, enter the main class name as com.tivo.hme.host.sample.Main. This is the same class that the runsamples script uses to start the application; it is the host environment for all TiVo HME applications, and will normally be the main class that will start up your application.

4.

On the Arguments tab, in the Program Arguments box, type com.tivo.hme.samples.clock.Clock. This is the program you want to run. Just like the runsamples script, you need to provide the name of the application for the HME host environment to run.

5. 6.

Click Apply and then Run. You should now see the Clock application on your TiVo box’s Music, Photos, Products, & More menu.

Note that if you have more than one network interface enabled on your PC (for example, wireless and wired) or virtual interfaces that are sometimes installed by VMWare and other virtual server software, you may need to specify the network interface to use manually. If this is the case, after com.tivo.hme.samples.clock.Clock, enter --intf . For instance, --intf en1 will specify the wireless network interface instead of the wired one on a Mac OS X system. You can stop the application by clicking the Terminate button (look for a red square near the lower right in Eclipse).

How it Works Running through the preceding steps will run the application just like the run_samples script, but instead of running at the command line, the HME application is actually running inside Eclipse. Running the application inside Eclipse is more convenient for quickly running applications that you are writing. Applications compiled and run from inside Eclipse can also be debugged inside Eclipse. That is, you can set points at which the application will pause, so you can examine the current state of the application, and you can run line by line through the code.

The HME Simulator The HME Simulator is included in the HME SDK in the simulator.jar file. You can run this from the command line by typing: java -jar simulator.jar

The Simulator will open a window that can be used to run and test TiVo HME applications without running the application on a TiVo box. The first time you run the Simulator, it may be necessary to select the Network menu and choose the network interface that’s on your home network.

44

Your Development Environment If you run the sample applications again (using the runsamples script) after starting the Simulator, you see that the sample applications appear on the Applications menu. From this menu, you can choose an application and run it in the Simulator just as you would on the TiVo box (Figure 3-10).

Figure 3-10

The Simulator command line can also take arguments to direct it to run an application without having to select the application. This mode is particularly useful when debugging applications. Command-Line Option

Description

-d

Turn on debugging.

-mute

Disable sound.

-s

Disable application discovery using mdns.

url or class

When started with a url, the Simulator will connect to that url at startup. If the first argument is not a url, the Simulator will pass all arguments to a Factory and connect to it.

45

Chapter 3 You can simulate TiVo remote control commands in the Simulator by using keyboard keys. For a list of these, select Help ➪ Keyboard Shortcuts in the Simulator.

Limitations of the Simulator Although the Simulator application is great for testing functionality of an application, there are areas in which the Simulator may give misleading results. For instance, the Simulator doesn’t have the resource limitations that the normal TiVo box would. In fact, because the Simulator is running on your computer, it has access to all the resources available on your machine. How does this affect the application? The most common problem you can run into is using too many graphics or too much animation. These may work great in the Simulator, but when running on a TiVo box, the resource limitations prevent different graphics in your interface from being displayed, or the time it takes to send information over the network to the TiVo box can affect the performance of your application. The Simulator also cannot display MPEGs the same way that the TiVo box can. Single-frame MPEGs can be used as a background image, primarily to save graphics memory on the TiVo box for image elements in an application’s interface. Because the Simulator does not have access to the MPEG background layer, only image backgrounds can be displayed. In short, the HME Simulator is great for quickly testing an application or for testing when you don’t have access to a TiVo box, but because of the need to accurately test the effects of communicating over a network and appropriately size graphic elements to manage the limited graphic resources on the TiVo effectively, it shouldn’t be the only thing relied on to test an application.

Summar y After this chapter, you should be familiar with how to run TiVo HME applications, and how to access them both through the TiVo box and from the Simulator application. The requirements for developing and running HME applications should also be installed and configured on your system, and you should have a familiarity with the files included in the HME SDK. You should be able to use the HME libraries and run the HME sample applications from within Eclipse as well as create HME projects in Eclipse.

Questions

46

1. 2.

What jars are needed to run TiVo HME applications?

3.

What does the output about MDNS mean? What does it signify?

What is the purpose of setting the network interface when running a TiVo HME application (using the --inf flag in the application)?

4 Your First TiVo HME Application The TiVo HME SDK provides a great amount of functionality for creating applications. The SDK does have a few requirements of the application in terms of the way it is written. An HME application must extend the Application class provided in the SDK; the Application superclass provides lifecycle methods and event-handling hooks to process events from the TiVo box and from other threads in the application. The lifecycle of an application takes place while the application is running through the TiVo box itself. That is, a new application is created and destroyed each time the application is launched from the TiVo box.

Hello World Let’s start with the classic Hello World example. Although a simple start, this application is a good way to examine the classes that must be extended in order to write an HME application, and a great opportunity to explore the hosting environment used to run applications.

Creating Hello World To create a new HME application in Eclipse, select File ➪ New Project. Select Java Project as the project type. Name the project “Ch4-01” and add the HME jars as you did in Chapter 3. To create the main Application class:

1. 2. 3. 4.

Right-click your project in the Package Explorer tab. Select New ➪ Class. Fill in the New Java Class form as shown in Figure 4-1. Click Finish.

You now have a Java file open in Eclipse named Example1Ch4.java that contains the start of your TiVo HME application.

Chapter 4

Figure 4-1

Eclipse Shortcut: When making a new class that you intend to extend from another class, clicking the Browse button next to the Superclass field will list all the classes you can extend from. The list is also searchable; in this case, you would search for “Application” and select the one from com.tivo.hme.sdk. The code that is generated is just the framework for the class. To really do anything, you need to implement at least the init(...) method from Application, which is the method called when the application is run on the TiVo box: package com.wiley.hme.ch4; import com.tivo.hme.interfaces.IContext; import com.tivo.hme.sdk.Application; public class Example1Ch4 extends Application { public void init(IContext arg0) throws Exception { // TODO Auto-generated method stub super.init(arg0); } }

48

Your First TiVo HME Application The highlighted code shows the function that must be added to override the init() method in your application. Eclipse Shortcut: To override methods, you can select Override/Implement Methods... from the Source menu and select methods to override by checking the box next to them. This ensures that you are overriding the correct method and makes it easier to get the method signature correct. Eclipse will also handle any additional import statements that are required because of the new method. Now that you have the init() method in your Application, it is time to put something interesting in there. At the moment, you are just calling super.init(), which passed the call to the superclass, Application. This will allow the application to run on the TiVo box, but the screen will just appear black. Let’s add some text so you know it is working correctly: package com.wiley.hme.ch4; import java.awt.Color; import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View;

public class Example1Ch4 extends Application { public void init(IContext arg0) throws Exception { super.init(arg0); View root = getRoot(); Resource text = createText(“default-36.font”, Color.red, root.setResource( text );

“Hello World”);

} }

In this listing, you added three lines to produce the text “Hello World” on the screen. The first line retrieves the root View object. The root view is the base layer for drawing on the display. The second line creates a Resource, which holds the text “Hello World.” The simplest explanation of Resources is that they are the “stuff” that is displayed in a view. Views are containers that define areas of the screen that can hold Resources. Resources are the data that is displayed (or played in the case of sound resources) on the TiVo box. In this case, you are using text, but Resources also describe images, sounds, and streams (such as an MP3 stream). Because Resources are the data that is shown on the screen, and Views are the boxes, to display the text you just created you must add it to a View in order to be seen. Because the text object is the only thing you are going to add to the View, you add it to the root view as shown in the third line. Even though the application is overriding the init() method, you still want to make sure to call super.init() to ensure that any initialization is performed in the parent Application class. When adding code that uses libraries you have not yet imported, you can select Source ➪ Organize Imports, and Eclipse will attempt to add the correct import statements for you (in this example, the ones for Resource and View). If there’s more than one available, Eclipse will present you with a choice for each one. This command will also remove any unnecessary import statements and keep your code clean.

49

Chapter 4

Running the Example in the Simulator The HME SDK contains an HME Simulator, which is contained in the jar file simulator.jar that is in the HME SDK main folder. This program shows how an application will display on the actual TiVo box, and is a quick way to get started testing an application without having to run it on the TiVo box each time. The Simulator can run your application one of two ways. You can run your HME application through the hosting environment and run the Simulator separately. The Simulator will then discover your application just like the TiVo box would, listening for MDNS announcements that an application is available for use. The other method, well suited for testing out an application as it is developed, is to run the application directly in the Simulator without any discovery.

Simulator in Discovery Mode There are two steps to running in discovery mode: ❑

Set up the run configuration in Eclipse for the application and start the application.



Run the Simulator.

Setting up the run configuration is similar to the steps in Chapter 3 for running the sample applications from within Eclipse:

1. 2.

From the Run menu, select Run....

3. 4.

On the Main tab, enter the main class name as com.tivo.hme.host.sample.Main.

5.

Click Apply and then click Run. Eclipse may ask you if you wish to save the file before launching if the file that was just edited changed. Eclipse will ask this, and you probably want to save to make sure any changes are compiled into the code about to be run.

Select Java Application in the options on the left and click the New icon near the top of the options (it has a document with a + on it), or the New button on the Windows version of Eclipse.

On the Arguments tab, in the Program Arguments box, type com.wiley.hme.ch4.Example1Ch4 — you need to provide the name of the application for the HME host environment to run.

The application is now running from within Eclipse. In the Console tab inside Eclipse, you should see output similar to the following: HME SDK 1.4 (TiVo, Inc.) LOG: added factory MDNS: http://192.168.1.107:7288/ch4/

If the output does not match this, or reports errors, check the run configuration created in the previous steps. Also, the Problems tab at the bottom of the Eclipse window will report any problems in the code that must be fixed before the application can run.

50

Your First TiVo HME Application In Windows and Mac OS X, double-clicking the simulator.jar file should launch the Simulator application. It can also be started from the command line using the command java -jar simulator.jar. (Tip: adding a shortcut to simulator.jar onto your Windows desktop or Quick Launch menu is very handy.) The Simulator will start up with a black screen. From the Network menu in the Simulator, choose your IP address, then from the Applications, choose the example, ch4 (see Figure 4-2). You may also need to choose the correct interface under the Network menu if you have not already done so.

Figure 4-2

The application will start up and display the text “Hello World” (Figure 4-3).

51

Chapter 4

Figure 4-3

Simulator in Direct Mode The simulator.jar program can also take as an argument the name of the application to run. Just as you set up com.tivo.hme.host.sample.Main to take the argument com.wiley.hme.ch4.Example1Ch4, you can set up a run configuration where the Simulator program takes the same argument. There is no discovery in this method, and it is quicker for running the application without additional steps in the Simulator. To set up this configuration, first the simulator.jar file must be in the “build path” of the project. To add the simulator.jar or any other jar file you need in the future to your build path:

1. 2. 3.

52

Right-click the main project in the Package Explorer tab in Eclipse and select Properties. Select the Java Build Path option in the list on the left, and then select the Libraries tab. Click Add External Jar... to locate the simulator.jar file and add it to the build path. The list of libraries should match Figure 4-4.

Your First TiVo HME Application

Figure 4-4

To set up the run configuration:

1. 2. 3. 4.

From the Run menu, select Run....

5.

Click Apply and then click Run.

Select Java Application in the options on the left and click the New icon or New button. On the Main tab, enter the main class name as com.tivo.hme.sim.Simulator. On the Arguments tab, in the Program Arguments box, type com.wiley.hme.ch4 .Example1Ch4 — you need to provide the name of the application for the HME host environment to run.

The Simulator will now start and automatically run the example application, and will look like Figure 4-3. You may need to select the application under the Application menu to launch it.

Starting Hello World on the TiVo Box The Simulator application is a great tool for quickly testing changes in an application, but ultimately all applications have to be tested on the TiVo box. The Simulator provides capabilities in terms of processing

53

Chapter 4 power and graphic resources that the TiVo box simply does not possess. Because an HME application runs over a network link and maintains a persistent connection, network latencies and communications are also not tested using the Simulator. To run the application on the TiVo, start the “Run...” target you created for using the Simulator in discovery mode by selecting Run... from the Run menu, locating the name of the configuration in the box on the left (under Java Application), and clicking the Run button. The TiVo box discovers applications on the local network the same way the Simulator does. On the TiVo box, navigate to the Music, Photos, & More menu and locate the application — applications running on local machines are generally at the bottom of the list of applications, so if you don’t see it at first, scroll all the way down (see Figure 4-5).

Figure 4-5

The “Hello World” example, when running on the TiVo box, appears the same as in the Simulator, with red text on a black background (Figure 4-3). When using the other applications in the Music, Photos, & More menu, you probably noticed that applications are exited by pressing the left directional key on the remote control. Pressing the left key in the Hello World application, however, doesn’t seem to have the same effect. The Hello World application can be exited using the TiVo button on the remote. This is because the other applications exit gracefully by handling the event for the left key. The TiVo button exits the application because it is a key that HME applications cannot override — it will always bring the user to the main TiVo screen so that the user experience when using HME applications is not completely different than using the other functionalities on the TiVo box.

54

Your First TiVo HME Application Try It Out

Setting a Custom Icon and Name for the Application

When browsing through the Music, Photos, & More menu, the example application does not have an icon or title like the rest of the TiVo-hosted applications. Setting a custom icon and name for the application is pretty simple. The TiVo receiver will check for a file named icon.png at the base URL published by the application, therefore an icon file would need to be in the base of the Java CLASSPATH. To add an icon, create a PNG graphic file named icon.png that is 34 pixels wide by 26 pixels high. Place the graphic file in the main project directory in Eclipse. (For this example, you can also drag and drop the icon.png file onto the package named com.wiley.hme.ch4 in the Package Explorer, and Eclipse will copy it to the right place.) To set the title for the application, add the highlighted line shown in the following code with the name of the application: public class Example1Ch4 extends Application { public final static String TITLE = “Hello World Example”; . . . }

If you run the application now and check out the Music, Photos, & More menu, you will see the name and icon (Figure 4-6).

Figure 4-6

55

Chapter 4 How It Works When the TiVo box loads the Music, Photos, & More menu, the TiVo box knows of the applications that are running because of the MDNS announcements the application makes. The MDNS announcements are made by the hosting environment, which uses the string TITLE for the name of the application that is announced. The TiVo box then asks each application for which it has received an announcement for the file icon.png. The TiVo box then uses this file as the icon displayed in the Music, Photos, & More menu.

Handling Events How would the “Hello World” application be modified to handle HME events and exit gracefully? All the key press events that come from the TiVo box to the application are handled in the handleKeyPress() method. The following code shows how to handle a “left key” event from the TiVo box: package com.wiley.hme.ch4; import java.awt.Color; import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View;

public class Example1Ch4 extends Application { public final static String TITLE = “Hello World Example”; public void init(IContext arg0) throws Exception { super.init(arg0); View root = getRoot(); Resource text = createText(“default-36.font”, Color.red, root.setResource( text );

“Hello World”);

} public boolean handleKeyPress(int code, long rawcode) { if (code == KEY_LEFT) { this.setActive(false); return true; } return super.handleKeyPress(code, rawcode); } }

You added the method handleKeyPress(), which has been overridden from the HmeObject class. The first line determines if the key code is the key that matches the one you wish to react to, in this case the left key. When the left key is pressed (either on your remote, if you’re running this from your TiVo, or on your keyboard, if running in the Simulator), you set the application to inactive mode and return true to indicate that you handled the event.

56

Your First TiVo HME Application All other events that do not match KEY_LEFT are passed along. Although passing events along doesn’t matter in this case, as more views and objects are added to the display, passing events along so that another object can handle them becomes increasingly important. Exiting the application with setActive(false) may seem an unintuitive way to exit an application, but this exit isn’t quite the same as quitting a normal program. In this case, the instance of the application that is communicating with the TiVo box is shut down, but it can be run again from the Music, Photos, & More menu — exiting the application on the TiVo box does not quit it on the PC desktop. You can find a complete list of the keys you can watch for in handleKeyPress() in the HME documentation. See hme-devguide.pdf in the doc directory of the HME SDK and search for “KEY_LEFT.”

Application Lifecycle By way of examining how the “Hello World” application runs and handles events, you have started to look at the application lifecycle. The lifecycle is really just a description of how the process of starting an application, communicating with the TiVo box, reacting to events, and exiting the application takes place.

Startup In any HME application, there are really two major stages involved in starting an application on the TiVo box. First, the host system must be running the application that will communicate with the TiVo box. After the host is running the application, the URL of the application will be broadcast to the TiVo box. This informs the TiVo box of how to locate the application. When a TiVo receiver accesses the application, the Factory for the application creates a new instance of the application. After the application instance has been created, the init() method is called. As shown in the “Hello World” example, the superclass’s (Application’s) init() method should be called to make sure any initialization in the superclass is performed correctly.

Running Events When an HME application is running, it is responsible for handling events from the TiVo receiver and sending commands to the receiver. Events are first processed using the dispatchEvent(HmeEvent event) method of the Application. This method will determine which HmeObject the event is for, and will call the handleEvent(HmeEvent event) method for the HmeObject. Events that should be handled in the Application’s handleEvent handler are events such as the idle event, an event indicating a key press has not been sent to the application for a period of time. In the “Hello World” application, the specific handler for key press events, handleKeyPress(), is used.

57

Chapter 4 Specific handlers are the best way to handle key press events. The specific handlers are ❑

handleKeyPress



handleKeyRelease



handleKeyRepeat

For only handling key events, the specific handlers are the proper way to handle these events. If the key events are unhandled, the handleEvent() method in Application will eventually receive the event. In “Hello World,” the key press event could have been processed in handleEvent(); however, the correct way to process key presses is via one of the specific handlers.

Errors Errors that are not fatal that occur while the HME application is running are sent to the application using the handler handleApplicationError(). These errors can include problems loading resources or warnings from the receiver.

Shutdown Application shutdown can really take place in two ways. Either it can be initiated by the user of the application as in the “Hello World” example, where the left key is handled via the handleKeyPress() method and the application is cleanly exited. In this case, the application exits itself by calling setActive(false). The lifecycle method handleActive(boolean active) is called, followed by the destroy() method to notify the application to completely clean up any resources being held (that is, Threads and so on). The other method of exiting an application occurs when the user uses a “warp key” (a key that immediately brings the user to another screen without any event handling by the HME application), the handleActive(boolean active) method will not be called, and only the destroy() method will be called. Therefore, to ensure that the application’s resources are always cleaned up, any thread or resource cleanup should be handled in destroy. Later, in the discussion on storing user preferences, you will see that you use the Context object. The context is created and destroyed by the Factory and is still available to the HME application when the destroy() method is called; in other words, it is still possible to store user preferences at this point.

Summar y This chapter started with a sample TiVo HME application for displaying simple text on a TiVo box. This simple example illustrated the lifecycle of an HME application and how to process events from an application. The detailed information about the application lifecycle will be important in upcoming chapters as well as for managing and cleaning up the resources your application uses.

58

Your First TiVo HME Application This chapter also covered details in Eclipse in terms of running an HME application as well as using the Simulator included with the SDK to test changes quickly without testing on a TiVo box.

Questions 1. 2. 3.

How does an application respond to a key press? What are the methods called when exiting an application? Are these always called? How do you set a custom icon and name for an application?

59

5 Displaying Resources In this chapter, you create an application that collects weather information based on a geographical location and display it on a TiVo box. The chapter provides a solid understanding of how your applications will use resources to present and organize information on the screen and also how sounds can be used throughout your applications. Resources are, in short, any graphic, text, or sound that your application displays or plays. Everything that is displayed to the user is transmitted to the TiVo box as a Resource object.

Understanding Views Views are the primary building block for laying out the graphics, text, and other drawing items that can be displayed in an HME application. Everything that is displayed in an HME application is contained in a View, and the placement on the screen is defined by the coordinate system used with Views.

Introduction to Views The View class extends the HmeObject class, inheriting the ability to create resources and to handle HME events. The View class also implements the IHmeProtocol interface and the IHmeEvent Handler interface. The IHmeProtocol interface is just a set of constants that are used in the HME protocol. The example in the previous chapter used the constant KEY_LEFT when processing events from the TiVo box. These constants and others are part of the IHmeProtocol. The IHmeEvent Handler is the interface that is a hook into the event-processing chain. The events that an HME application can receive and the chain of events are covered in more detail in the next chapter.

View Hierarchy Views are arranged in a hierarchy. A view is always contained by another view, and may be the parent of other views. When creating views, the View constructor takes as its first argument another View object, which will be the parent of the new View. When an HME application starts

Chapter 5 up, the Application class (which all applications extend) will create the root view — the top-level view that can act as a parent to views. The first few views created in an application, therefore, may look like this: View view1 = new View(this.getRoot(), 50, 50, 300, 300); View view2 = new View(view1, 50, 50, 100, 100);

The first view, view1, is created with the root view as its parent view. The next four parameters specify the x and y coordinates and the width and height, respectively. The second view is created with view1 as the parent. This makes all the coordinates specified when creating view2 relative to the 0,0 coordinate system defined in the parent view, view1. So even though view1 and view2 contain the same x and y coordinates for the top/left placement of the box, the coordinates are always relative to the parent view. The root view derives its size from the maximum possible visible screen on a standard definition television. The root view is 640 pixels wide by 480 pixels high. Views may have coordinates that are beyond the viewable area of the root view, however, the views will not be visible. Visit www.wrox.com to view example Ch5-01, which contains a working application that draws these two views. The views created in the preceding code would appear on the TiVo box as depicted in the following diagram (Figure 5-1).

Figure 5-1

62

Displaying Resources Drawing Order and Hiding Views Views are drawn based on where they lie in the view hierarchy. The root view is drawn first, then the children of the root view, then the children of the children of the root view, and so on. If a view contains multiple children, the children will be painted in the order in which they were created. If views contain no resources, there is nothing to draw, so they are omitted until a Resource is set for the view. Drawing can be turned off for a view by setting the view to be invisible: view2.setVisible(false);

This will in turn hide any views that have view2 as their parent view. Painting of a view can also be suspended. Suspending painting will not hide the view as setVisible(false) will, but will pause updates to the view until painting is resumed. The following code suspends painting, changes the color of a view, waits ten seconds, and then resumes painting: view1 = new View(this.getRoot(), 50, 50, 300, 300); view2 = new View(view1, 50, 50, 100, 100); view1.setResource(Color.red); view2.setResource(Color.gray); new Thread() { public void run() {

// // // //

view2.setPainting(false); view2.setResource(Color.blue); the flush is necessary because these instructions are in a separate thread than normal event processing. This flush forces updates to be transmitted to the TiVo Box, showing that the box color is not updated until painting is turned back on. flush(); try { sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } view2.setPainting(true); flush(); } }.start();

The full code for this application is Ch5, example 2, and is available on the web site for the book at www.wrox.com.

63

Chapter 5 Properties of Views The x and y coordinates along with the width and height determine the size of the View that is displayed in the application. Although these must be initially set in the constructor, along with the parent view, these parameters may be altered after the view has been created using the following calls: Method

Description

setLocation(int x, int y)

Sets the x and y coordinate of where a View should draw, relative to its parent View. The changes take place immediately.

setLocation(int x, int y, Resource animation)

Sets the x and y coordinate of where a View should draw, relative to its parent View. Changes take place over the period of time specified in the animation. Animations are covered in Chapter 12.

setSize(int width, int height)

Sets the width and height of the View; changes take place immediately.

setSize(int width, int height, Resource aninimation)

Sets the width and height of the view. Changes take place over the period of time specified in the animation.

setBounds(int x, int y, int width, int height)

Sets the x and y location of the View and the width and height. All changes take place immediately.

setBounds(int x, int y, int width, int height, Resource animation)

Sets the x and y location of the View and the width and height. Changes take place over the period of time specified in the animation. Animations are covered in Chapter 12.

getLocation()

Retrieves the location of the view.

getSize()

Retrieves the size of the view.

getBounds()

Retrieves the bounds of the view.

getX()

Retrieves the x coordinate of the view.

getY()

Retrieves the y coordinate of the view.

getHeight()

Retrieves the height of the view.

getWidth()

Retrieves the width of the view.

All measurements are in pixels for these methods, and the location is always set relative to the parent view.

Translation Translation of a view will move the contents of the view an amount relative to the x and y coordinates that define where a view is drawn onscreen. The difference between translation and merely changing the location of the view is that a translated view will move the contents of the view.

64

Displaying Resources The parameters for setting the translation of a view are relative to the current translated location, instead of absolute values, which they would be when changing the bounds. The translate methods would be useful, for instance, when moving a cursor around the screen. Instead of recalculating the position of the cursor each time, the translate method could be used to move it a defined distance. The translate methods, however, do not move the view itself, only the contents of the view. If there is a view that is 100px by 100px and my_view.translate(200,200) is called, the contents of the view will be translated outside the viewable area, so they will seem to have disappeared. The contents have only been translated outside the bounds of the view, and can be translated back again by calling my_view.translate(-200,-200). Method

Description

translate(int xAmount, int yAmount) setTranslation(int xAmount, int yAmount)

Both of these methods set the amounts in the x and y directions that the view should move.

translate(int xAmount, int yAmount, Resource animation) setTranslation(int xAmount, int yAmount, Resource animation)

Both of these methods set the amounts in the x and y directions that the view should move. Changes take place over the period of time specified in the animation. Animations are covered in Chapter 12.

getTranslation()

Gets the currently set translation of the View.

getTranslationX()

Gets the x value of the currently set translation of the View.

getTranslationY()

Gets the y value of the currently set translation of the View.

Scaling Views can also be scaled relative to the bounds set for a view. Scaling a view will also scale all the child views and resources of all child views. Method

Description

setScale(float xAmount, float yAmount)

This method sets the scaling factor for the view. Ch anges take place immediately.

setScale (float xAmount, float yAmount, Resource animation)

This method sets the scaling factor for the view. Changes take place over the period of time specified in the animation. Animations are covered in Chapter 12. Animation with scaling should probably not be used because it causes performance problems when rendering on the TiVo box.

getScaleX()

Gets the x scaling factor for this view.

getScaleY()

Gets the y scaling factor for this view.

65

Chapter 5 Visibility, Transparency, and Focus Visibility has many uses in HME application development. From hiding certain elements at different times in the application lifecycle to showing different views based on events, view visibility is probably one of the more frequent actions taken on a view after it has been created. Turning off painting (as you saw earlier) can be used to “queue” several updates to a view without some of the update commands displaying a view before all the updates have been made.

66

Method

Description

setVisible(boolean visible)

This method sets the visibility for the view. Changes take place immediately.

setVisible(boolean visible, Resource animation)

This method sets the visibility for the view. Changes take place over the period of time specified in the animation.

setPainting(boolean painting)

This method sets the flag indicating that updates should be suspended or enabled for the view. Changes take place immediately.

getVisible()

Determines if this view is currently visible.

getPainting()

Determines if painting has been turned off for this view.

Method

Description

setTransparency(float transparency)

This method sets the transparency for the view. Changes take place immediately. 0.0 is opaque, 1.0 is fully transparent.

setTransparency(float transparency, Resource animation)

This method sets the transparency for the view. Changes take place over the period of time specified in the animation.

getTransparency()

Gets the currently set transparency for this view.

Method

Description

setFocus()

This method sets the view on which it is called as having focus.

hasFocus()

Determines if this view has focus or not.

Displaying Resources

Extending Views The View class works great by itself for placing items on the screen and moving them, even for animating objects onscreen. Subclassing views is required if the view needs to process events. Events will eventually propagate to the Application class if they are not handled by the individual views, but processing all events in the application leads quickly to unmanageable code, as well as very tightly coupled objects. The following example subclasses View in order to receive events for the view: package com.wiley.hme.ch5; import java.awt.Color; import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.View;

public class TwoViews extends Application { myView view1; myView view2; myView focusedView; public void init(IContext context) throws Exception { super.init(context); view1 = new myView(this.getRoot(), 10, 10, 150, 150); view2 = new myView(view1, 10, 10, 50, 50); view1.setFocus(); focusedView = view1; view1.setResource(Color.red); view2.setResource(Color.gray); } public boolean handleKeyPress(int code, long rawcode) { // // This code is to cleanly exit the application // switch(code) { case KEY_LEFT: this.setActive(false); return true; case KEY_RIGHT: if (focusedView == view1) {

67

Chapter 5 view2.setFocus(); } else { view1.setFocus(); } return true; } // keypresses that we don’t handle, we pass along. return super.handleKeyPress(code, rawcode); }

public class myView extends View { String name; public myView(View parent, int x, int y, int w, int h) { super(parent, x,y,w,h); } public myView(View arg0, int arg1, int arg2, int arg3, int arg4, boolean arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); } public boolean handleKeyPress(int key, long rawcode) { switch (key) { case IHmeProtocol.KEY_SELECT: this.setResource(Color.blue); return true; case IHmeProtocol.KEY_PLAY: this.setResource(Color.cyan); return true; } return super.handleKeyPress(key, rawcode); } } }

In this example, a new class, myView, extends the View class and overrides the handleKeyPress() method in order to receive key press events from the TiVo box. The Application class also handles a few keys to “switch” focus between the views. To see this in action, press the Select key when running this application on your TiVo (or Enter on the Simulator), the Right key, and the Play key (or “p” on the simulator). When the focus is switched, the View on which setFocus() was last called will be the View in the event-processing path. The code for this example is in Ch5-03.

68

Displaying Resources

Code Example The following code is a simple layout of an application to show the current weather. In this example, the views have been set up on the screen. In the coming sections, this application will be enhanced with graphics, text, and sound. package com.wiley.hme.ch5; import java.awt.Color; import com.tivo.hme.interfaces.IContext; import com.tivo.hme.sdk.Application; import com.tivo.hme.sdk.View; public class WeatherApplication extends Application { View View View View View View

dayView; weatherIconView; hiView; lowView; currentTempView; forcastView;

public static final String TITLE=”Weather”; public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(Color.white); int dvWidth=250, dvHeight=150, wivWidth=250, wivHeight=200, hlcvWidth=200, hlcvHeight=60, fvWidth=250, fvHeight=120; dayView weatherIconView hiView lowView currentTempView forcastView

= = = = = =

new new new new new new

View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(),

0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0,

0); 0); 0); 0); 0); 0);

// set up the location of the views dayView.setLocation( SAFE_TITLE_H, weatherIconView.setLocation( SAFE_TITLE_H+dvWidth+10,

SAFE_TITLE_V); SAFE_TITLE_V);

69

Chapter 5 hiView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10); lowView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10+hlcvHeight+10); currentTempView .setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10+(hlcvHeight+10)*2); forcastView.setLocation( SAFE_TITLE_H+10+wivWidth, SAFE_TITLE_V+wivHeight+10); // set up the width and height of the views dayView.setSize( dvWidth, dvHeight); weatherIconView.setSize( wivWidth, wivHeight); hiView.setSize( hlcvWidth, hlcvHeight); lowView.setSize( hlcvWidth, hlcvHeight); currentTempView.setSize( hlcvWidth, hlcvHeight); forcastView.setSize( fvWidth, fvHeight); dayView.setResource( Color.black); weatherIconView.setResource( Color.black); hiView.setResource( Color.black); lowView.setResource( Color.black); currentTempView.setResource( Color.black); forcastView.setResource( Color.black);

} public boolean handleKeyPress(int key, long longcode) { switch (key) { case KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(key, longcode); } }

In this example, you use SAFE_TITLE_V and SAFE_TITLE_H to place the views on the screen. These constants define the safe area that will display on most televisions. Although the root view is 640px by 480px, most televisions will not be able to display the full 640 x 480 image, and will cut off pixels from the outer edges. The constants define buffers on the sides and top so that views and resources can be placed so that they will appear as intended.

70

Constant

Description

SAFE_TITLE_V

The recommended vertical buffer for any text to be displayed onscreen.

SAFE_TITLE_H

The recommended horizontal buffer for any text to be displayed onscreen.

Displaying Resources Constant

Description

SAFE_ACTION_V

The recommended vertical buffer for any active item on the screen. Items using this buffer may be clipped on some televisions.

SAFE_ACTION_H

The recommended horizontal buffer for any active item on the screen. Items using this buffer may be clipped on some televisions.

Running the preceding application in the Simulator would generate a display as seen in Figure 5-2. It seems like there is a large amount of space on the edges of the screen, but the Simulator shows all 640 by 480 pixels. Selecting File ➪ Show Safe Action in the Simulator will show the application with the clipping of borders like a TV would display the application (Figure 5-2).

Figure 5-2

71

Chapter 5

Text Text resources are one of the major components of any application. All text that is displayed onscreen must be made into a resource and assigned to a view in order to be displayed.

Creating Text Resources Whereas views define the placement of Resources in the application, and sit in the path of events, resources are the actual items displayed onscreen for the application. Text is the simplest resource to create because the TiVo box is capable of rendering text quickly. Considerations that apply to images which would affect performance of the application on the TiVo don’t apply to text, so it is a good place to begin learning about resources. The TiVo HME SDK also supports font resources, which can be used to display text in TrueType fonts. TrueType fonts, like images, do require resources on the TiVo box. The default and system fonts, however, are already provided on the TiVo, so additional memory is not taken on the TiVo box when using the default or system fonts.

Try It Out The following example uses the default font to display a message on the TiVo box (Figure 5-3).

Figure 5-3

72

Displaying Resources package com.wiley.hme.ch5; import java.awt.Color; import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View;

public class Fonts extends Application { public void init(IContext arg0) throws Exception { super.init(arg0); getRoot().setResource(Color.darkGray); View view1 = new View( getRoot(), SAFE_TITLE_H, SAFE_TITLE_V, 200, 200); Resource text = createText(“default-24.font”, Color.white, “Learning About Text...”); view1.setResource(text); view1.setVisible(true); } public boolean handleKeyPress(int code, long rawcode) { switch(code) { case KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(code, rawcode); } }

How It Works In the init() method, first you create a view. Resources can’t be placed directly on the screen. As discussed in the first section of this chapter, to be placed on the screen, resources must be assigned to views, because views define the placement, size, and visibility of Resources. After creating the view, you create the Resource. The resource is then assigned to the view to place it onscreen in the application, and the view is set to visible. To create the resource, you use the helper method createText(...). The parameters given to createText() are described in the following table. The example uses the default font in size 24 (default-24.font) in white (using the java.awt.Color class). The text to display is the first parameter to createText(). This method is part of the HMEObject class. Because the Application class extends HMEObject, and the application, Fonts, extends Application, all the methods of HMEObject are available for the application to use. HMEObject contains the helper methods to create all the types of resources in the HME SDK.

73

Chapter 5 The createText() method takes the following parameters: Method: createText Parameter 1

Object

font

The font to use when displaying the resource. The font can be specified as [font]-[size].font if either default or system fonts are being used, for example: default-24.font (as used in the preceding

example). Parameter 2

Object

color

The color to use when displaying the resource.

Parameter 3

String

text

The text that will be displayed.

What is unusual about this method is that it takes an Object for the font and an Object for the color. What this means is that there are a few different ways to correctly call the createText() method. In the preceding example, you created the text resource by passing createText() a String describing the font to use, a Color (from java.awt) object to indicate the color, and the String parameter that is the text to display. You could have also called createText() with the following parameters and achieved the same result: // here we use the String “0xFFFFFF”, the hex RGB code for // white instead of Color.white Resource text = createText(“default-56.font”, “0xFFFFFF”, “Learning About Text...”); // Here we first create a font resource, then pass that as the // first parameter to createText() Resource font = createFont(“default.ttf”, Resource.FONT_PLAIN, 56); Resource text = createText(font, Color.white, “Learning About Text...”);

In this example, you create a new type of resource, a font resource, and use this font when creating the text resource for display on the screen. Notice what the view does with the text when it’s too large for the View — it first tries to squeeze the characters closer together, and then clips the text if necessary. Creating this font resource also allows for specifying the font style and size separately. The parameters createFont() takes are listed in the following table: Method: createFont Parameter 1

String

Font Family

The font to use when displaying the resource. This will typically be the name of the font to display. The built-in fonts are default.ttf and system.ttf

74

Displaying Resources Method: createFont Parameter 2

int

Style

This is an integer. The constants FONT_PLAIN FONT_BOLD FONT_ITALIC FONT_BOLDITALIC

from IHmeProtocol are the valid flags that can be passed to createFont() for this parameter. Parameter 3

int

size

This is the size of the font in points.

In addition to the default.ttf and system.ttf fonts that may be specified, any TrueType font may be used as long as it is in the classpath for the application. The following example uses a custom TrueType font along with the system and default fonts (Figure 5-4).

Figure 5-4 package com.wiley.hme.ch5; import java.awt.Color; import com.tivo.hme.interfaces.IContext;

75

Chapter 5 import com.tivo.hme.sdk.Application; import com.tivo.hme.sdk.Resource; import com.tivo.hme.sdk.View; public class Fonts extends Application { public void init(IContext arg0) throws Exception { super.init(arg0); getRoot().setResource(Color.darkGray); View view1 = new View( getRoot(), SAFE_TITLE_H, SAFE_TITLE_V, 640(2*SAFE_TITLE_H), 200); View view2 = new View( getRoot(), SAFE_TITLE_H, SAFE_TITLE_V+50, 640(2*SAFE_TITLE_H), 200); View view3 = new View( getRoot(), SAFE_TITLE_H, SAFE_TITLE_V+100, 640(2*SAFE_TITLE_H), 200); Resource systemFont = createFont(“system.ttf”, FONT_PLAIN, 30); Resource defaultFont = createFont(“default.ttf”, FONT_PLAIN, 30); Resource customFont = createFont(“geodesic.ttf”, FONT_PLAIN, 30); Resource text = createText(systemFont, Color.white, “Learning About Text!”); Resource text2 = createText(defaultFont, Color.white, “Learning About Text!”); Resource text3 = createText(customFont, Color.white, “Learning About Text!”); view3.setResource(text3, RSRC_HALIGN_RIGHT); view3.setVisible(true); view2.setResource(text2, RSRC_HALIGN_LEFT); view2.setVisible(true); view1.setResource( text ); view1.setVisible(true); } public boolean handleKeyPress(int code, long rawcode) { switch(code) { case KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(code, rawcode); } }

The custom TrueType font that is created in the third createFont() call is in a file named geodesic.ttf, which is in the top-level directory of the application. The geodesic TrueType font used in this example comes from http://grsites.com/fonts, which offers a free font archive. As you can see in the screen shot of the preceding code running, justification (left, center, right) has also been set for the text. Actually, if you examine the code, you’ll see we didn’t set the justification of the text; the text was placed within the view with the justification. Because the view controls the size of the area that will be drawing the resource, the alignment is set when doing a setResource() with the text resource. This same method of setting alignment applies to images as well.

76

Displaying Resources The full list of alignment flags that can be set are listed in the following table: Flag

Description

RSRC_HALIGN_RIGHT

Right-aligned text within the view

RSRC_HALIGN_LEFT

Left-aligned text within the view

RSRC_HALIGN_CENTER

Horizontally centered text within the view

RSRC_VALIGN_TOP

Vertically aligned text along the top of the view

RSRC_VALIGN_BOTTOM

Vertically aligned text along the bottom of the view

RSRC_VALIGN_CENTER

Vertically centered text within the view

Try It Out

Updating the Weather Application with Text

In the first part of this chapter, the weather application is simply a layout for the data. Now, with a good understanding of text and font resources, adding data to the application should be easy. package com.wiley.hme.ch5; import java.awt.Color; import import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View;

public class WeatherApplication extends Application { View View View View View View

dayView; weatherIconView; hiView; lowView; currentTempView; forcastView;

WeatherModel data; private Resource dayText; private Resource tempText; private Resource tempFont; private Resource hiText; private Resource lowText; public static final String TITLE=”Weather”;

public void init(IContext context) throws Exception { super.init(context);

77

Chapter 5 getRoot().setResource(Color.white); data = new WeatherModel(); int dvWidth=250, dvHeight=150, wivWidth=250, wivHeight=200, hlcvWidth=200, hlcvHeight=60, fvWidth=250, fvHeight=120; dayView weatherIconView hiView lowView currentTempView forcastView

= = = = = =

new new new new new new

View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(),

0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0,

0); 0); 0); 0); 0); 0);

// set up the location of the views dayView.setLocation( SAFE_TITLE_H, SAFE_TITLE_V); weatherIconView.setLocation( SAFE_TITLE_H+dvWidth+10, SAFE_TITLE_V); hiView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10); lowView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10+hlcvHeight+10); currentTempView .setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10+(hlcvHeight+10)*2); forcastView.setLocation( SAFE_TITLE_H+10+wivWidth, SAFE_TITLE_V+wivHeight+10); // set up the width and height of the dayView.setSize( dvWidth, weatherIconView.setSize( wivWidth, hiView.setSize( hlcvWidth, lowView.setSize( hlcvWidth, currentTempView.setSize( hlcvWidth, forcastView.setSize( fvWidth,

views dvHeight); wivHeight); hlcvHeight); hlcvHeight); hlcvHeight); fvHeight);

tempFont = createFont(“default.ttf”, IHmeProtocol.FONT_PLAIN, 30); dayText = createText(“system-36.font”, Color.black, data.getShortDayName()); tempText = createText(tempFont, Color.black, “Cur. Temp: “ + data.getTemperature()); hiText = createText(tempFont, Color.black, “Hi Temp: “ + data.getHigh()); lowText = createText(tempFont, Color.black, “Low Temp: “ + data.getLow());

dayView.setResource( dayText ); weatherIconView.setResource( Color.black); hiView.setResource( hiText ); lowView.setResource( lowText ); currentTempView.setResource( tempText );

78

Displaying Resources forcastView.setResource( Color.black);

} public boolean handleKeyPress(int key, long longcode) { switch (key) { case KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(key, longcode); } }

How It Works A helper class for gathering the weather information was added separately, so only the code important for the TiVo application is shown. All the source code is provided along with the book and can be found in the example Ch5-06. The data field uses the WeatherModel class to fetch data from the Internet to display in the application. Text and font resources are created using the createText() methods from HmeObject, and the data is added to the display by calling the setResource() method on the View objects created in the previous chapter. The setResource(Color.black) from the previous chapter was replaced with the text resource to be displayed. The application contains real data now, and is starting to look a bit better (Figure 5-5).

Figure 5-5

79

Chapter 5 In the next section, the application will gain images and will start to look like a real HME application. Although text will always be important to HME applications, it is the graphical elements that, from a user perspective, truly distinguish HME applications from older TiVo HMO applications.

Image Resources Similar to text resources, image resources are created and then assigned to views in order to display.

Supported Graphic Formats The HME SDK supports the major graphic formats: ❑

PNG



GIF



Animated GIF



JPEG

When using GIFs or PNGs, HME will display the image with the alpha settings of the image. Transparency and layering images does have an impact on the performance of the application, however. Chapter 9 covers resource restrictions and strategies for making the most of the resources on the TiVo box.

Creating Image Resources Unlike text resources, which are represented by the Resource class, image resources are represented by the ImageResource class, which is a subclass of Resource. This means that although a different type of resource is created for images, the same setResource() methods can be used when assigning the images to a view. The following example creates an image, and then assigns it to a view. When creating the view, the ImageResource that is returned from creating the image is used to help position the view in the center of the screen. To test this example, take an image called “dog.jpg” and drop it on the “com.wiley.hme.ch5” package in your Eclipse project for this example. This will copy the image into the correct place and your app will be able to find it. package com.wiley.hme.ch5; import import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.View;

public class Images extends Application { public void init(IContext arg0) throws Exception {

80

Displaying Resources ImageResource picture = createImage(“dog.jpg”); View picView = new View(getRoot(), (640/2) - (picture.getWidth()/2), (480/2) - (picture.getHeight()/2), picture.getWidth(), picture.getHeight()); picView.setResource(picture);

} public boolean handleKeyPress(int arg0, long arg1) { switch (arg0) { case IHmeProtocol.KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(arg0, arg1); } }

The result of this application can be seen in Figure 5-6.

Figure 5-6

81

Chapter 5 In the application, you provide the string “dog.jpg” as a file name so that the image can be located. The image is located in one of two ways:

1. 2.

Using the java.awt.Toolkit default toolkit Using the Factory’s getStream() method

The first method will locate the file in the current java classpath if it is a file that already exists. In the preceding example, the image dog.jpg is located at the root of one of the paths in the classpath. Examining the example directories shows this (Figure 5-7).

Figure 5-7

The second method allows intervention of the application to determine where the resource to be loaded is located. The getStream() method in the Factory will locate resources that are available on the web as URLs or inside jar files that the application may be bundled into.

82

Displaying Resources In addition, the getStream() method in the Factory class can be overridden to provide custom resource loading strategies. For example, there may be a temp directory (or the system temp directory) where some files are stored during program execution that isn’t on the classpath, but should be searched for resources if they cannot be located with the classpath method. The preceding example could also be written as follows: package com.wiley.hme.ch5; import import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.View;

public class Images extends Application { public void init(IContext arg0) throws Exception { ImageResource picture = createImage(“http://www.digitaldroplet.net/hmebook/dog.jpg”); View picView = new View(getRoot(), (640/2) - (picture.getWidth()/2), (480/2) - (picture.getHeight()/2), picture.getWidth(), picture.getHeight()); picView.setResource(picture);

} public boolean handleKeyPress(int arg0, long arg1) { . . . } }

In this case, the image is located on a web site, and the Factory’s getStream() method will be used to locate the file. The application will appear the same, only the resource is being loaded from a remote site on the web. This image is still, however, not loaded directly by the TiVo; it is loaded by the application, and then sent to the TiVo box. When using image resources, the only connection that the TiVo box makes when running an application is to the application itself — all resources that are used will be retrieved by the application, then sent to the TiVo box using the HME Protocol. A different kind of resource, a streaming resource, will not be sent along the single connection to the TiVo box, but will be requested by the TiVo box when it is needed. These types of resources, and reasons for using them, are discussed in Chapter 9.

83

Chapter 5 There are four versions of createImage() that can be used to create images from internal and external data. The first version, as you have seen, takes as a parameter a String, which provides the location of the file that is to be used for the resource. Method: createImage Parameter 1

String

Image Name

Creating an ImageResource using this method will locate images either on the classpath, within jar files on the classpath, or on the Internet if the String is a valid URL.

An image object

This form of createImage takes an Image object (from java.awt.Image).

Method: createImage Parameter 1

Image

This assumes that the program has already read the image into memory, and that the parameter contains the image. This is a useful method if the application has some processing of an image before displaying it (such as rotating it from the original orientation).

Method: createImage Parameter 1

byte[]

An image in a byte array

This form of createImage is useful if there is already an image in byte[] format, or if the image is the result of a calculation on bytes. It could be used to pull an image from a stream of data (such as an MP3 ID3 header).

Method: createImage Parameter 1

byte[]

An image in a byte array

This form of createImage is useful if there is already an image in byte[] format, or if the image is the result of a calculation on bytes. It could be used to pull an image from a stream of data (such as an MP3 ID3 header).

84

Parameter 2

int

offset

The offset into the byte array to begin reading the image.

Parameter 3

int

length

Because the buffer does not contain only the image to be displayed, this is the length to read in the buffer.

Displaying Resources The following example creates one image using each of the createImage variants. Choosing the right one to use will depend mostly on the source of the images that are being incorporated into the application. The highlighted portions are the new code for using the other createImage variants. To run this example from Eclipse, replace the init() routine in the previous code with the code that follows. You’ll also need to take “dog.jpg” and drop it on the root of your Eclipse project — this will copy it to the correct place in your project. Note the difference in location for ImageIcon() and FileInputStream() in the following code versus createImage() in the previous code; createImage() looks in the classpath, whereas the other two use a relative filesystem reference to locate the file (Figure 5-8).

Figure 5-8 package com.wiley.hme.ch5; import import import import import

java.awt.Image; java.io.BufferedReader; java.io.FileInputStream; java.io.FileReader; java.util.Arrays;

import javax.swing.ImageIcon; import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.ImageResource;

85

Chapter 5 import com.tivo.hme.sdk.View; public class Images extends Application { public void init(IContext arg0) throws Exception { byte[] byteImg = new byte[5000000]; ImageResource picture = createImage(“http://www.digitaldroplet.net/hmebook/dog.jpg”); Image img = new ImageIcon(“dog.jpg”).getImage(); FileInputStream fis = new FileInputStream(“dog.jpg”); int i = fis.read(byteImg); byte[] realImg = new byte[i]; System.arraycopy(byteImg, 0, realImg, 0, i); ImageResource pic2 = createImage(img); ImageResource pic3 = createImage(realImg); ImageResource pic4 = createImage(realImg, 0, realImg.length); View picView = new View(getRoot(), 50, 50, picture.getWidth(), picture.getHeight()); View picView2 = new View(getRoot(), 50, picture.getHeight() + 60, pic2.getWidth(), pic2.getHeight()); View picView3 = new View(getRoot(), 50 + picture.getWidth(), 50, pic3.getWidth(), pic3.getHeight()); View picView4 = new View(getRoot(), 50 + picture.getWidth(), 50 + picture.getHeight(), pic4.getWidth(), pic4.getHeight());

picView.setResource(picture); picView2.setResource(pic2); picView3.setResource(pic3); picView4.setResource(pic4); } public boolean handleKeyPress(int arg0, long arg1) { switch (arg0) {

86

Displaying Resources case IHmeProtocol.KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(arg0, arg1); } }

Size, Scaling, and Alignment Much like setting the alignment of text when assigning the text resource to a view, ImageResources may also be altered in terms of how they display in the view to which they are being assigned (Figure 5-9).

Figure 5-9

The following code will show four of the dog images in a grid: ImageResource picture = createImage(“dog.jpg”); View View View View

picView = new View(getRoot(), 100, 100, 100, 100); picView2 = new View(getRoot(), 210, 100, 100, 100); picView3 = new View(getRoot(), 100, 210, 100, 100); picView4 = new View(getRoot(), 210, 210, 100, 100);

picView.setResource(picture);

87

Chapter 5 picView2.setResource(picture); picView3.setResource(picture); picView4.setResource(picture);

The problem with this example is that each image is clipped (Figure 5-9). The image isn’t scaled to the size of the view. The solution is to pass a flag to indicate that the View should resize the resource: picView.setResource(picture, RSRC_IMAGE_BESTFIT);

Changing all the images to best fit within the view will appear as in Figure 5-10.

Figure 5-10

If the image was smaller than the view, this would have scaled it up to the best fit inside the view. Other scaling options are listed in the following table:

88

Flag

Description

RSRC_IMAGE_HFIT

Uses the horizontal size of the image and horizontal size of the view to determine the scaling factor. Scaling is proportional.

RSRC_IMAGE_VFIT

Uses the vertical size of the image and vertical size of the view to determine the scaling factor. Scaling is proportional.

RSRC_IMAGE_BESTFIT

Uses both horizontal and vertical sizes of the image and view to determine a scaling factor such that the entire image is scaled to the size of the view. Scaling is proportional.

Displaying Resources If the view is larger than the image resource, and you do not wish to scale it, the same alignment flags that are used to justify text can be used to place the image within the view. The full list of alignment flags that can be set are as follows: Flag

Description

RSRC_HALIGN_RIGHT

Right-aligned image within the view

RSRC_HALIGN_LEFT

Left-aligned image within the view

RSRC_HALIGN_CENTER

Horizontally centered image within the view

RSRC_VALIGN_TOP

Vertically aligned image along the top of the view

RSRC_VALIGN_BOTTOM

Vertically aligned image along the bottom of the view

RSRC_VALIGN_CENTER

Vertically centered image within the view

Updating the Weather Application with Graphics Previously, in the weather application, there was a placeholder for an icon describing the current weather. The icon to be added is provided, along with the weather data, from the NOAA’s web service for retrieving forecast information. The code to access the weather service and extract the data has been provided. To get the weather information, the longitude and latitude of the location must be provided. The full code is available on the book’s web site at www.wrox.com. package com.wiley.hme.ch5; import java.awt.Color; import java.math.BigDecimal; import import import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View;

public class WeatherApplication extends Application { View View View View View View

dayView; weatherIconView; hiView; lowView; currentTempView; forcastView;

WeatherModel data; private Resource dayText; private Resource tempText; private Resource tempFont;

89

Chapter 5 private private private private

Object hiText; Resource lowText; Resource forcastText; ImageResource weatherIcon;

public static final String TITLE=”Weather”;

public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(Color.white); data = new WeatherModel( new BigDecimal(42.350861), new BigDecimal(-71.54335)); int dvWidth=250, dvHeight=150, wivWidth=250, wivHeight=200, hlcvWidth=200, hlcvHeight=60, fvWidth=250, fvHeight=120; dayView weatherIconView hiView lowView forcastView

= = = = =

new new new new new

View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(), View(getRoot(),

0, 0, 0, 0, 0,

0, 0, 0, 0, 0,

0, 0, 0, 0, 0,

0); 0); 0); 0); 0);

// set up the location of the views dayView.setLocation( SAFE_TITLE_H, SAFE_TITLE_V); weatherIconView.setLocation( SAFE_TITLE_H+dvWidth+10, SAFE_TITLE_V); hiView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10); lowView.setLocation( SAFE_TITLE_H+20, SAFE_TITLE_V+dvHeight+10+hlcvHeight+10); forcastView.setLocation( SAFE_TITLE_H+10+wivWidth, SAFE_TITLE_V+wivHeight+10); // set up the width and height of the dayView.setSize( dvWidth, weatherIconView.setSize( wivWidth, hiView.setSize( hlcvWidth, lowView.setSize( hlcvWidth, forcastView.setSize( fvWidth,

views dvHeight); wivHeight); hlcvHeight); hlcvHeight); fvHeight);

tempFont = createFont(“default.ttf”, IHmeProtocol.FONT_PLAIN, 30); dayText = createText(“system-36.font”, Color.black, data.getShortDayName()); tempText = createText(tempFont, Color.black, “Cur. Temp: “ + data.getTemperature()); forcastText = createText(tempFont, Color.black, data.getForcast()); hiText = createText(tempFont, Color.black, “Hi Temp: “ + data.getHigh());

90

Displaying Resources lowText = createText(tempFont, Color.black, “Low Temp: “ + data.getLow()); weatherIcon = createImage(data.getIcon()); dayView.setResource( dayText ); weatherIconView.setResource( weatherIcon , RSRC_IMAGE_BESTFIT); hiView.setResource( hiText ); lowView.setResource( lowText ); forcastView.setResource( forcastText );

} public boolean handleKeyPress(int key, long longcode) { switch (key) { case KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(key, longcode); } }

When run, the application now includes a graphic with an icon describing the current weather. Figure 5-11 is an example of a particularly warm evening in the authors’ hometown.

Figure 5-11

91

Chapter 5

Sounds The final component to discuss in resources is sound resources. One of the hallmarks of the TiVo interface is the aural feedback that the interface provides to the user.

Creating Sound Resources Sound resources, like text and image resources, are created using a helper method from the HMEObject class. The method is, predictably, called createSound(). Sound resources in HME are designed to play the short sound clips that are responses to user actions. The sounds must be 8,000 Hz signed 16-bit little endian mono PCM format. The standard TiVo sounds are available in much the same way the standard fonts are available. To play the TiVo left button noise and a custom sound: package com.wiley.hme.ch5; import java.awt.Color; import com.tivo.hme.interfaces.IContext; import com.tivo.hme.sdk.Application; import com.tivo.hme.sdk.SoundResource; public class Sounds extends Application { public void init(IContext arg0) throws Exception { getRoot().setResource(createText(“default-50.font”, Color.blue, “testing sound...”)); SoundResource snd = createSound(“Song.wav”); snd.play(); play(“left.snd”); } public boolean handleKeyPress(int arg0, long arg1) { switch (arg0) { case KEY_LEFT: setActive(false); return true; } return super.handleKeyPress(arg0, arg1); } }

You probably noticed that there is no setResource() used for sounds. There really is no need to attach sounds to views, because the parameters that views govern and manage have no meaning for sounds. Instead the SoundResource object, the object returned from createSound(), has a play() method.

92

Displaying Resources In the preceding example, the built-in sound left.snd is also played, but using a different call. The default sounds are already built into the resource map that is loaded, so there is no need to create a resource as is required for the custom sound. HMEObject has a method play(), which takes a String representing the name of the resource in the resource hash. All the built-in sounds are accessed using the resource hash (createSound() will fail if it is called with one of the default sounds as a parameter), so the play() method is particularly useful for playing these sounds.

Built-in Sounds The built-in TiVo sounds are as follows: ❑

alert.snd



bonk.snd



deselect.snd



error.snd



left.snd



pagedown.snd



pageup.snd



right.snd



select.snd



slowdown1.snd



speedup1.snd



speedup2.snd



speedup3.snd



thumbsdown.snd



thumbsup.snd



tivo.snd



updown.snd

These should all sound pretty familiar from the TiVo interface. Using the built-in sounds is a good way to keep the TiVo user interface feel, even when in an HME application.

Summar y Knowledge of how to create and use Resource objects in HME applications is one of the key skills needed to build HME applications. The entire user interface is made up of images and text, and all the objects are transmitted to the TiVo box as Resource objects. The Application class itself subclasses Resource. In short, Resource class and events comprise most of the interaction between HME applications and the user.

93

Chapter 5 In this chapter, you learned: ❑

Resources and views are the basic tools needed to build applications in HME.



Everything that is displayed in an HME application is contained within a view defined by an x/y coordinate system with a viewable area of 640 x 480 pixels.



Views are organized in a hierarchy by providing views with a parent when they are created. The hierarchy governs the order in which they are drawn, and the order in which events are sent to the view.



Resources are displayed by assigning them to views using the setResource() method.



Sounds are played using the resource’s play() method.

Questions 1. 2. 3.

94

How do you set the color of text? Does a View or Resource determine the alignment of text? Why? What is the difference between playing a custom sound and a built-in sound?

6 Events The applications so far have been geared toward displaying information on the TiVo box. Although the HME SDK allows great flexibility in creating a custom display, the interactive features of HME are truly what sets it apart from just displaying images on the screen. Events provide the input to TiVo HME applications, information on the TiVo box running the application, and messages about the status of resources in use by the application. Just like a desktop application would have buttons and text fields that provide data to the application, HME uses events to send data back from the TiVo box to the application. Events also provide status from the TiVo box running an HME application that describes the TiVo box running the application, the state of the application being run, and events that describe resource usage in the application. Errors from the application may also be returned in events. By the end of this chapter, you will be able to ❑

Process user key action events



Process TiVo box events



Process HME Focus events



Use the Ticker to process timed events

Types of Events The different types of events are handled differently in HME, and each type of event is filtered and sent to the item it was intended for. All events are sent to the subclass of Application if another object the event was destined for processes the event.

Chapter 6 The different types of events and the object that they are sent to are shown in the following table: Event Type

Destination

Method Called in Destination

Notes

Device Info

Application

handleEvent

This event predictably contains information about the TiVo box sending the event.

Init Info

Application

handleEvent

Application Info

Application

handleEvent handleActive handleError handlePing

The event is first sent to the Application’s handleEvent method. handleEvent then calls handleActive, handleError, or handlePing if the event contains relevant data.

Idle Info

Application

handleEvent handleIdle

The event is first sent to the Application’s handleEvent method. handleIdle is called if the event contains idle event data.

Key Event

The View with focus

handleEvent handleKeyPress handleKeyRepeat handleKeyRelease [via HMEObject .handleEvent]

Font Info

The Resource/ Listeners of the Resource

Listeners

The Resource/ Listeners of the Resource

Listeners postEvent

Resource Info

postEvent

Device Info The device info event is represented by the HmeEvent.DeviceInfo class in the SDK. The device info event contains a Map (from java.util) that holds the following information:

96

Key

Value

brand

TiVo

platform

Series2

Events Key

Value

host

TiVo Name

version

Software version on the TiVo box

The Hme DeviceInfo event is sent when an application is started or resumed on a TiVo. The device info event is represented in the SDK by the HmeEvent.DeviceInfo class. This event information relates to the device the application is running on.

Init Info The init info is sent when data is available for initializing the application and is represented by the HmeEvent.InitInfo class. The data may be retrieved using the getMemento() and the getParams() methods of the HmeEvent.InitInfo class. Mementos are used when transitioning from one HME application to another. On the transition back to the starting application, getMemento() returns a byte[] with data stored by the first application before the transition. For more information, see the section on Calling Other Applications in Chapter 10. This event is generally sent only on startup or on transition. If the application supports transitioning, it should check this event on startup. The Init info event is a way to pass small amounts of state information between applications. With version 1.4 of the HME SDK, the ability to start HME applications from within other HME applications was introduced, and this event facilitates passing initialization data or restoration data while starting and resuming HME applications.

Application Info The application info event is sent when the application is launched or when there are errors. As shown in the table earlier, these events are translated automatically into the handleError() and handleActive() methods in the Application class.

Idle Info The idle event is a special event that indicates a timeout on the TiVo box. This is the timeout that a TiVo box would generally wait before returning to live TV. Indeed, if an application does not handle the idle event (none of the applications written so far have), the TiVo box will suspend the application and show live TV. The reason for the idle event is primarily to prevent burn-in on televisions by applications that display unchanging data for a long period of time. The event should only be handled by the application if it is capable of taking some action to prevent burn-in on the television set.

97

Chapter 6

Key Event Handling key events is the way HME applications retrieve user input. The handleEvent() method in HmeObject will call the handleKeyPress(), handleKeyRelease(), or handleKeyRepeat() methods, depending on what action the user of the application has taken. Using these handlers is generally preferred, although it is possible to extract the data by overriding the handleEvent() method as well. The handler methods are called with a code corresponding to the key pressed and the rawcode, which is the raw IR code that the TiVo has received. In the event that a remote control key press is not recognized by the TiVo, the raw IR code is sent to the HME application for additional processing.

Font Info The FontInfo event provides information about fonts used on the TiVo to the user. The size of the characters can be retrieved from the event. The font info events can be useful when determining how many characters are able to fit into a view, or how large a view must be to fit a text resource.

Event Flow As shown in the table in the beginning of the chapter, Events flow first to Resources, then to the views that contain them, then to the application. Events are posted using the IHmeEventHandler interface call. Views first process events by calling HmeObject’s handleEvent(...) method. This method splits events into the three specific handleKey event handlers: handleKeyPress(), handleKeyRepeat(), and handleKeyRelease().

Key Events Key events are the most varied types of events that are received by an HME application. In addition, because they are the primary means of input by the user, going into detail of how to use key events is important. The keys used by the HME SDK are as follows:

98

Constant in IHmeInterface

Code

Description

KEY_UNKNOWN

0

The key is unknown by the HME engine

KEY_TIVO*

1

The TiVo key This key is reserved, and will exit any HME application

KEY_UP

2

The Up key

KEY_DOWN

3

The Down key

Events Constant in IHmeInterface

Code

Description

KEY_LEFT

4

The Left key

KEY_RIGHT

5

The Right key

KEY_SELECT

6

The Select key

KEY_PLAY

7

The Play key

KEY_PAUSE

8

The Pause key

KEY_SLOW

9

The Slow key

KEY_REVERSE

10

The Reverse (rewind) key

KEY_FORWARD

11

The Forward key

KEY_REPLAY

12

The Replay/skip back key

KEY_ADVANCE

13

The Skip forward key

KEY_THUMBSUP

14

Thumbs Up key

KEY_THUMBSDOWN

15

Thumbs Down key

KEY_VOLUMEUP

16

The Volume Up key

KEY_VOLUMEDOWN

17

The Volume Down key

KEY_CHANNELUP

18

The Channel Up key

KEY_CHANNELDOWN

19

the Channel Down key

KEY_MUTE

20

The Mute key

KEY_RECORD

21

The Record key

KEY_LIVETV*

23

The Live TV key This key is reserved, and will exit any HME application

KEY_INFO

25

The Info key

KEY_DISPLAY

25 (Same as

The Display key

KEY_INFO) KEY_CLEAR

28

The Clear key

KEY_ENTER

29

The Enter key

KEY_NUM0

40

0

KEY_NUM1

41

1

KEY_NUM2

42

2

KEY_NUM3

43

3

KEY_NUM4

44

4 Table continued on following page

99

Chapter 6 Constant in IHmeInterface

Code

Description

KEY_NUM5

45

5

KEY_NUM6

46

6

KEY_NUM7

47

7

KEY_NUM8

48

8

KEY_NUM9

49

9

Optional Keys There are also optional keys on the TiVo brand remote control that may not be on other TiVo boxes that are not produced by TiVo. These keys will produce events, but cannot be relied on to be on all models of TiVo boxes. These optional keys have constants that are prefaced by KEY_OPT_* instead of KEY_* like the ones in the preceding table.

100

Constant in IHmeInterface

Code

Description

KEY_OPT_WINDOW

22

The key is unknown by the HME engine

KEY_OPT_ASPECT

KEY_OPT _WINDOW

The Aspect button

KEY_OPT_PIP

KEY_OPT _WINDOW

The Picture in Picture button

KEY_OPT_EXIT

24

The Exit button This key is reserved and will exit any HME application.

KEY_OPT_LIST

26

The Now Playing List button This key is reserved and will exit any HME application.

KEY_OPT_GUIDE

27

The Guide button This key is reserved and will exit any HME application.

KEY_OPT_STOP

51

The Stop button on DVD box

KEY_OPT_MENU

52

The DVD Menu key on DVD box

KEY_OPT_TOP_MENU

53

The Top Menu button on DVD box

KEY_OPT_ANGLE

54

The Angle key on DVD box

KEY_OPT_DVD

55

The DVD key on DVD box

Events

Events Example The following code displays the different types of events. The handleEvent() method in the Application class will be passed to all events that come to the application. The application will take the events and display them onscreen. This example uses the geodesic.ttf font that was used in the previous chapter. To use that font in this example, drag the font file into the project and Eclipse will copy it to the main directory of the project. package com.wiley.hme.ch6; import java.awt.Color; import import import import import import import import import import import

com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.HmeEvent; com.tivo.hme.sdk.Resource; com.tivo.hme.sdk.View; com.tivo.hme.sdk.HmeEvent.ApplicationInfo; com.tivo.hme.sdk.HmeEvent.DeviceInfo; com.tivo.hme.sdk.HmeEvent.FontInfo; com.tivo.hme.sdk.HmeEvent.InitInfo; com.tivo.hme.sdk.HmeEvent.Key; com.tivo.hme.sdk.HmeEvent.ResourceInfo;

public class EventLister extends Application {

public class TitledView extends View { View titleView; public TitledView(String title, View arg0, int arg1, int arg2, int arg3, int arg4) { super(arg0, arg1, arg2, arg3, arg4); titleView = new View(this, 0, 0, arg3, 15); titleView.setResource(createText(“default-15.font”, Color.blue, title)); } } private static final String NEW_LINE = “\n”; View eView; Resource text; View View View View View

DeviceInfoView; InitInfoView; AppInfoView; FontInfoView; ResourceView;

public boolean handleEvent(HmeEvent event) { Class eventType = event.getClass(); if (eventType == HmeEvent.Key.class) { HmeEvent.Key keypress = (Key) event;

101

Chapter 6 eView.setResource(createText(“default-15.font”, Color.black, “EVENT: “ + HmeEvent.Key.actionToString( keypress.getAction() ) + “: “ + HmeEvent.Key.codeToString(keypress.getCode() ))); } else if (eventType == HmeEvent.ApplicationInfo.class) { HmeEvent.ApplicationInfo appinfo = (ApplicationInfo) event; AppInfoView.setResource(createText(“default-15.font”, Color.black, lineWrap(“APP_EVENT: “ + appinfo.toString(), 15))); } else if (eventType == HmeEvent.ResourceInfo.class) { HmeEvent.ResourceInfo resourceevent = (ResourceInfo) event; text = createText(“default-15.font”, Color.black, “RSRC_EVENT: “ +resourceevent.toString()); } else if (eventType == HmeEvent.InitInfo.class) { HmeEvent.InitInfo initInfo = (InitInfo) event; InitInfoView.setResource(createText(“default-15.font”, Color.black, “InitInfo: “ + lineWrap(initInfo.toString(), 15))); } else if (eventType == HmeEvent.DeviceInfo.class) { HmeEvent.DeviceInfo devinfo = (DeviceInfo) event; DeviceInfoView.setResource(createText(“default-15.font”, Color.black, “DeviceInfo: “ + lineWrap(devinfo.getMap().toString(),20) )); } else if (eventType == HmeEvent.FontInfo.class) { HmeEvent.FontInfo fontinfo = (FontInfo) event; this.FontInfoView.setResource(createText(“default-15.font”, Color.black, “fontInfo: “ + fontinfo.getAscent() + “ “ + fontinfo.getDescent() + “ “ + fontinfo.getHeight() + “ “ + fontinfo.getGlyphInfo(‘A’).getBoundingWidth()) ); } else if (eventType == HmeEvent.ResourceInfo.class) { HmeEvent.ResourceInfo resinfo = (ResourceInfo) event; ResourceView.setResource(createText(“default-15.font”, Color.black, “ResInfo: “ + resinfo.getMap().toString())); } return super.handleEvent(event); } private int int int

String lineWrap(String string, int i) { length = string.length(); segments = length/i; sliceSize = length/segments;

StringBuffer strBuff = new StringBuffer(length + length/i + 5); for (int slices=0; slices= this.keyCounter) { play(“thumbsup.snd”); play(“thumbsup.snd”); play(“thumbsup.snd”); keyCounter++;

109

Chapter 6 //this.displayPlay(strContinue); replayKeyCounter=0; currentKeyCounter=0; setPlacement(HIDDEN); mode = PLAY_MODE; displayMode(strWatch); Ticker.master.add(this, System.currentTimeMillis()+2000, null); } } else { play(“thumbsdown.snd”); } return true; } return super.handleKeyPress(keyCode, rawCode); } public long tick(long tm, Object arg) { if (!displayNow) { setPlacement(HIDDEN); flush(); displayNow=!displayNow; if (currentKeyCounter < keyCounter ) { return System.currentTimeMillis()+500; } else { mode = LISTEN_MODE; return System.currentTimeMillis()+500; } } if (mode == LISTEN_MODE) { //displayPlay(strPlay); setPlacement(HIDDEN); displayMode(this.strRepeat); flush(); return -1; } if (isApplicationClosing()) { return -1l; } int key = rand.nextInt(); if (currentKeyCounter 0) return (BScreen) ((StackFrame)myStack.lastElement()).screen; else return null;

130

Going Bananas } public int getStackDepth() { return myStack.size(); }

If you examine the BApplication source code, you will see that the stack actually stores a bit more information than just the BScreens in the order they were put onscreen. The transition is stored along with the screen. The BApplication uses an object called StackFrame to store information on the stack. The implementation in BApplication works well, but subclasses do not have access to it, so in adding the custom transition, this can be copied to the BApplication subclass. Though all this re-implementation sounds complicated, it is relatively straightforward, only requiring a few methods to be re-implemented. The following is a fully implemented BApplication class with a custom transition for a left to right wipe. The pop implementation for the reversal of the transition has also been implemented. package com.wiley.hme.ch7; import java.util.Vector; import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BEvent; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class CustomTransitions extends BApplication { public static final int TRANSITION_WIPE = 22; public Vector myStack; public void init(IContext arg0) throws Exception { super.init(arg0); myStack = new Vector(); push(new ImageScreen(this, 1), TRANSITION_FADE); } public void pop(Object arg) { if (getStackDepth() 0) return (BScreen) ((StackFrame)myStack.lastElement()).screen; else return null;

132

Going Bananas } public int getStackDepth() { return myStack.size(); } public void push(BScreen screen, int transition, Object arg) { getRoot().setPainting(false); try { // // exit old screen // StackFrame previous = null; if (myStack.size() > 0) { previous = (StackFrame)myStack.lastElement(); previous.doExit(); } // // enter new screen // StackFrame next = new StackFrame(screen, transition); myStack.addElement(next); next.doEnter(arg, false); // // perform the transition. for the new screen, always adjust: // location // transparency switch (transition) { case TRANSITION_WIPE: screen.setLocation(-getNormal().getTranslationX(), getNormal().getTranslationY()); screen.setSize(0, getNormal().getHeight()); previous.screen.setTranslation(-getNormal().getWidth(), 0, getResource(FADE_ANIM)); previous.screen.setLocation(getNormal().getWidth(), 0, getResource(FADE_ANIM)); previous.screen.setSize(0, getNormal().getHeight(), getResource(FADE_ANIM)); screen.setSize(getNormal().getWidth(), getNormal().getHeight(), getResource(FADE_ANIM)); screen.setTransparency(0); break; case TRANSITION_NONE: // the rest of this code is in the accompanying example break; case TRANSITION_FADE: // the rest of this code is in the accompanying example

133

Chapter 7 break; case TRANSITION_LEFT: // the rest of this code is in the accompanying example break; } screen.setVisible(true); // By playing the sound below, BApplication will also be stopped from // playing the error sound. // screenChanged = true; play(“pageup.snd”); } finally { getRoot().setPainting(true); } } // The remainder of the source code accompanies the text. . . .

This application re-implements pop(), push(), and all the methods that interact with the StackFrame from BApplication. This must be done because the StackFrame is not accessible to subclasses of BApplication, so the StackFrame must be completely replaced by a local version. The TRANSITION_WIPE, the new transition effect, must be added to the push() and pop() methods to draw the new transition. The interdependence between BScreens and the BApplication class, which manages the BScreens, requires careful consideration when designing an application. Both BApplication and BScreen must be extended to create a functional Bananas application. Note that the full code can be found on the book’s web site at www.wrox.com.

BView BViews are the Bananas equivalent of HME View objects. In fact, they extend the HME View class from the HME SDK. The BView class fulfills the same role in Bananas as the View class in the HME SDK, allowing for placement of resources on the screen. In addition to the normal functionality of the View class, BView also hooks into the advanced features of Bananas:

134



For allowing a view to be used by the focus manager



For allowing for the use of highlights (different state when the view has focus)



As the basis for the other Bananas widgets

Going Bananas Try It Out The following example is the same example as from Chapter 5, converted to using BApplication and BView (see Figure 7-5): package com.wiley.hme.ch7;

import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.Application; com.tivo.hme.sdk.IHmeProtocol; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.View;

public class Images extends BApplication { public void init(IContext context) throws Exception { super.init(context); ImageResource picture = createImage(“dog.jpg”); BView BView BView BView

picView picView2 picView3 picView4

= = = =

new new new new

BView(getNormal(), BView(getNormal(), BView(getNormal(), BView(getNormal(),

100, 210, 100, 210,

100, 100, 210, 210,

100, 100, 100, 100,

100, 100, 100, 100,

true); true); true); true);

picView.setResource(picture, RSRC_IMAGE_BESTFIT); picView2.setResource(picture, RSRC_IMAGE_BESTFIT); picView3.setResource(picture, RSRC_IMAGE_BESTFIT); picView4.setResource(picture, RSRC_IMAGE_BESTFIT); picView.setResource(picture); picView2.setResource(picture); picView3.setResource(picture); picView4.setResource(picture); } public boolean handleKeyPress(int arg0, long arg1) { switch (arg0) { case IHmeProtocol.KEY_LEFT: this.setActive(false); return true; } return super.handleKeyPress(arg0, arg1); } }

135

Chapter 7

Figure 7-5

How It Works BView is used in this example the same way that View was used in Chapter 5. In Bananas, BView is mainly used to contain images and as the base class for the other widgets. Because BView extends the View class, the same methods such as setResource(), covered in Chapter 5, still apply.

BList BList is the first of the widgets in the Bananas toolkit. This widget helps build lists that have the look and feel of lists in the TiVo standard interface. BLists manage much of the events and processing that would be required to create a list, and so implementing a list is made far easier because of this class. The following examples both use BList to create the lists that are displayed. Figure 7-6 is from the Bananas sample applications.

136

Going Bananas

Figure 7-6

Figure 7-7 is from the AudioFaucet application (written by the authors).

Figure 7-7

137

Chapter 7

Using BLists BLists are used very differently than the other widgets in the Bananas toolkit. The other widgets, which are discussed in the upcoming sections, can be created and used in BScreens. BList, however, is an abstract class. Abstract classes cannot be instantiated directly; the abstract designation means that the class has one or more methods that are declared, but not implemented. When instantiating a class that implements BList, you provide as parameters the containing (parent) BView, the bounding box for the List (x/y/w/h), and a “row height.” It is helpful to make the height of the bounding box a multiple of the row height. For example, if the row height is 35, making the height of the BList 350 will allow 10 rows to be displayed on the screen at the same time. If you add more rows than can visibly fit, the BList will automatically take care of adding them and scrolling the list properly when the user presses the appropriate key on the remote. BList contains one abstract method: protected abstract void createRow(BView parent, int index);

In order to use BLists, this method must be overridden in a subclass, and the subclass may then be used in a BScreen. createRow() is called for each index that must be added to the list. The list of objects to be represented in the list is stored by BList as a java.util.Vector because, at least in Java 1.4, Vector does not possess information as to what type of object is stored in the Vector, forcing the user to re-implement BList to extract the proper type from the Vector and add a row to the list. This is nice, though, because it allows your BLists to contain anything you want — simple text items, or more complex, custom objects you define yourself. Your BList row could contain an object with a number of fields (stock information, for example, with price, change, and high and low values). To activate the selection pointer in the list, the screen that contains the list must give the list focus using the setFocusDefault() method. BLists automatically handle the KEY_UP, KEY_DOWN, KEY_CHANNELUP, and KEY_CHANNELDOWN keys to move around the list.

Styling the List BLists automatically generate the highlight bar when focus is set on one of the rows. The highlights on the rows are styled using the setBarAndArrows() method in BList. The selection bar can have rounded edges on one or both sides of the bar. Normally setting the bar drawing options would be done in the BList subclass constructor. The options that can be set for rounding or hanging (extending the bar all the way to the edge of the screen) have constants that can be used. The constants (from IBananas) are BAR_HANG and BAR_DEFAULT.

BLists Must Be Used in a BScreen Some of the examples early in this chapter used BViews directly in a BApplication. Trying to use a BList (a class derived from BList, that is) directly in the BApplication, and attaching it to the normal layer, causes a NullPointerException. This is because the BList code has an internal class that implements the IHightlightsLayout interface, which requires a BScreen.

138

Going Bananas The setBarAndArrows() call parameters are as follows: Parameter

Type

Description

Left bar hang

Int

Whether the left side of the bar should hang offscreen (BAR_HANG) or be rounded (BAR_DEFAULT)

Right bar hang

Int

Whether the right side of the bar should hang offscreen or be rounded

Action for KEY_LEFT

Object

The action to send (actions are like Bananas events) when KEY_LEFT is received

Action for KEY_RIGHT

Object

The action to send when KEY_RIGHT is received

Managing the List BList contains several add and remove methods for adding items to the list and for removing them. The add methods can add the following: ❑

A single element



An array of elements



A Vector of elements

There are two versions of each method, one for adding the elements to the end of the list, and one for adding them at a specific point in the list. There are two remove() methods in BList. One removes an item based on the index in the list, and one takes an Object and removes that object from the list, if it is in the list.

BList Example The following example is the minimum code needed to create a list and display it on a screen: package com.wiley.hme.ch7; import java.awt.Color; import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class BListExample1 extends BApplication { String listItems[] = {“one”, “two”, “three”, “four” }; public void init(IContext context) throws Exception {

139

Chapter 7 super.init(context); getRoot().setResource(Color.white); push(new simpleScreen(this), TRANSITION_LEFT); } public boolean handleKeyPress(int arg0, long arg1) { // TODO Auto-generated method stub return super.handleKeyPress(arg0, arg1); }

public class SimpleBList extends BList { public SimpleBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); this.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “left”, “right”); } protected void createRow(BView parentView, int index) { if (get(index) != null) { BText text = new BText(parentView, 0 , 0 , parentView.getWidth(), parentView.getHeight()); text.setValue(get(index).toString()); } } } public class simpleScreen extends BScreen { public simpleScreen(BApplication app) { super(app); BList list = new SimpleBList(getNormal(), 100, 100, 400, 300, 30); list.add(listItems); list.setVisible(true); setFocusDefault(list); } } }

This example has two inner classes: one extending BScreen, because BLists must live inside a BScreen, and one extending BList to implement createRow() and draw the row (see Figure 7-8).

Figure 7-8

140

Going Bananas The following example uses images as the contents of rows to illustrate how to use and store other data in a list, and how createRow() would change to accommodate that data: package com.wiley.hme.ch7; import java.awt.Color; import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.Resource;

public class BListExample2 extends BApplication {

public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(Color.white); push(new simpleScreen(this), TRANSITION_LEFT); } public boolean handleAction(BView view, Object action) { if (action.toString().equals(“pop”)) { setActive(false); return true; } return super.handleAction(view, action); }

public boolean handleKeyPress(int arg0, long arg1) { // TODO Auto-generated method stub return super.handleKeyPress(arg0, arg1); }

public class SimpleBList extends BList { public SimpleBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); this.setBarAndArrows(BAR_DEFAULT, BAR_DEFAULT, “left”, “right”); } protected void createRow(BView parentView, int index) { if (get(index) != null) { //BText text = new BText(parentView, 0 , 0 , parentView.getWidth(), parentView.getHeight()); //text.setValue(get(index).toString());

141

Chapter 7 BView image = new BView(parentView, 0, 0, parentView.getWidth(), parentView.getHeight()); image.setResource( (Resource) get(index)); } } } public class simpleScreen extends BScreen { ImageResource listItems[]; public simpleScreen(BApplication app) { super(app); listItems = new ImageResource[5]; listItems[0] listItems[1] listItems[2] listItems[3] listItems[4]

= = = = =

createImage(“1.jpg”); createImage(“2.jpg”); createImage(“3.jpg”); createImage(“4.jpg”); createImage(“5.jpg”);

BList list = new SimpleBList(getNormal(), 100, 100, 120, 300, 100); list.add(listItems); list.setVisible(true); setFocusDefault(list); }

} }

BList Methods BList contains several methods for retrieving information from the list, and for interacting with the list. Some of the important methods are listed in the following table. Notice that there are two add() methods; if you have a lot of items to add, you should first add them to an array, then add the whole array at once, rather than one by one, for performance reasons.

142

Returns

Method

Parameters

Description

void

add

int index Object element

Adds an item to the list at the given index.

void

add

int index Object[] a

Adds an array of items at the given index. The whole array is added at the index specified.

void

add

int index Vector v

Adds a Vector of items at the given index. The whole array is added at the index specified.

void

add

Object o

Adds this object to the end of the list.

void

add

Object[] a

Adds the array of Objects to the end of the list.

Going Bananas Returns

Method

Parameters

Description

void

add

Vector v

Adds the Vector to the end of the list.

void

clear

boolean

contains

Object o

Returns true if the list contains the object passed in.

java.lang.Object

get

int index

Gets the item at the provided index.

int

getFocus

Gets the index of the currently selected row.

int

getNVisible Rows

Given the size of the BList onscreen, gets how many rows are visible.

BView

getRow

int

getRow Height

Gets the row height.

int

getTop

Gets the index of the row that is currently at the top of the screen.

boolean

handle Focus

Removes all items from the list.

int index

boolean isGained BView gained

Gets the BView containing the row at the provided index.

Handles focus movement.

BView lost int

indexOf

Object o

Finds an object in the list.

int

lastIndexOf Object o

Finds an object in the list, starting at the end.

void

refresh

If necessary, scrolls the list to show the currently focused row and creates new row views to wrap the elements that are currently visible.

java.lang.Object

remove

int index

Removes an element.

boolean

remove

Object o

Removes an object from the list. Returns true if the object was found and removed.

java.lang.Object

set

int index

Sets an object in the list.

Object element void

setBarAnd Arrows

int bar_left int bar_right

Sets up the hanging bars and the actions to send on the left and right keys. Actions are discussed in the next chapter.

Object action_left Object action_right Table continued on following page

143

Chapter 7 Returns

Method

Parameters

Description

void

setFocus

int index

Sets the focus to a particular row.

boolean animate int

size

Returns the number of elements in the list.

Focus Focus can be used in a list to change the display of other information onscreen — for instance, having a pane on the right side of the screen with more information about the selected item. Like the examples in Chapter 6, notification that focus has changed is sent via the handleFocus() callback method. Implementing handleFocus() in a BList subclass, therefore, is a good way to display different information onscreen depending on which item in the list is selected. The handleFocus() method indicates that the focus has changed, but does not give an index into the list. A BList subclass can obtain this information by calling getFocus() to get the index and get(index) to retrieve the object at that index.

Try It Out

handleFocus()

The following example displays the image that is named by the current item in the list: package com.wiley.hme.ch7; import java.awt.Color; import import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext; com.tivo.hme.sdk.ImageResource; com.tivo.hme.sdk.Resource;

public class BListExample3 extends BApplication { BView imageView; public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(“0x001166”); push(new simpleScreen(this), TRANSITION_LEFT); } public boolean handleAction(BView view, Object action) { if (action.toString().equals(“pop”)) { setActive(false); return true; }

144

Going Bananas return super.handleAction(view, action); }

public class SimpleBList extends BList { public SimpleBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); this.setBarAndArrows(BAR_DEFAULT, BAR_DEFAULT, “pop”, “push”); } protected void createRow(BView parentView, int index) { if (get(index) != null) { BText text = new BText(parentView, 0 , 0 , parentView.getWidth(), parentView.getHeight()); text.setValue(get(index).toString()); text.setColor(Color.white); text.setFont(“default-20.font”); } } public boolean handleFocus(boolean isGained, BView gained, BView lost) { if (isGained) { String name = get(getFocus()).toString(); imageView.setResource(getResource(name), RSRC_IMAGE_BESTFIT); } return super.handleFocus(isGained, gained, lost); } } public class simpleScreen extends BScreen { ImageResource listItems[]; public simpleScreen(BApplication app) { super(app); imageView = new BView(getBelow(),250,100, 200,200); String listItems[] = { “1.jpg”, “2.jpg”, “3.jpg”, “4.jpg”, “5.jpg” }; BList list = new SimpleBList(getNormal(), 100, 100, 120, 300, 36); list.add(listItems); list.setVisible(true); setFocusDefault(list); } } }

145

Chapter 7 How It Works The SimpleList class in the example has a handleFocus() method. This is the event handler for focus events. Because the handler is in the SimpleList class, it will be notified when the focus in the SimpleList class changes. In the case of this application, that occurs when the user moves to another item in the list. The image is then changed to reflect the new selection. This technique is widely used in HME applications that TiVo makes available, and is an extremely useful method of displaying greater amounts of information in a single screen.

BText The BText widget is a widget for displaying text. In Chapter 5, when covering how to create and use text resources, you saw that for every text resource being displayed, a View must be created, the text resource must be created, and then the resource must be assigned to the view. The process was always the same, and encapsulating the view and resource creation inside a single object seemed like an obvious choice. BText does this encapsulation, and also provides text shadows and easier-to-use setter methods for configuring the text to be displayed. The following example sets up a BText with a shadow (see Figure 7-9): package com.wiley.hme.ch7; import java.awt.Color; import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.interfaces.IContext;

public class BTextExample extends BApplication { public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(“0x001166”); push(new TextScreen(this), TRANSITION_FADE); }

public class TextScreen extends BScreen { public TextScreen(BApplication app) { super(app); BText testText = new BText(this, 100,100,400,200); //set the font testText.setFont(“default-50.font”); testText.setValue(“Example Text”); testText.setColor(Color.white); testText.setShadow(“0x888888”, 2); testText.setVisible(true); } } }

146

Going Bananas

Figure 7-9

BButton The BButton class is designed for creating a button object. Buttons participate in the focus manager that Bananas provides, so moving between buttons is mostly automatic.

Using BButtons BButtons are created like most other BViews, with a parent view and the dimensions of the button: BButton myButton = new BButton(this, 100, 100, 200, 50);

BButton objects possess an internal view that stores the label for the BButton. The view is accessed using setResource() the same way as in Chapter 5 when assigning resources to views. Because the BButton object is a descendant of BView, BButton can also be used as a parent view for other widgets. In particular, BText can use a BButton as a parent view in order to provide shadows and other text styling in the button. After creating the button and assigning a label to the button, calling setBarAndArrows() is required to allow the buttons to have some sort of behavior. There are several variants of setBarAndArrows(). The one used in the next example sets up the following:

147

Chapter 7 ❑

Button hanging style



Actions for the up/down/left/right key presses while the button is active



The placement for the “hint” arrows

The button hanging style is set the same way as the BList hanging style: BAR_DEFAULT for a rounded end and BAR_HANG for a button that hangs all the way offscreen. The first two parameters to setBarAndArrows are the left and right styles, respectively. The next four parameters indicate the actions that will be taken when the left, right, up, and down keys are pressed. Four constants exist that indicate that the press should be destined for the focus manager, which will automatically navigate to the next button closest in the direction of the button press. In the following example, the three buttons are placed in a vertical column, and the focus manager will manage traversing the set of buttons because the focus manager constants have been specified for the up and down keys. The focus manager constants are as follows: ❑

H_UP



H_DOWN



H_RIGHT



H_LEFT

In the example, the action “pop” is used in the left action field. Actions are discussed further in the next chapter, but you will see in the screen’s handleAction() method that the application exits when the string “pop” is received as an action. package com.wiley.hme.ch7; import java.awt.Color; import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BButton; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class BButtonExample extends BApplication { public void init(IContext arg0) throws Exception { super.init(arg0); push(new ExampleScreen(this), TRANSITION_FADE); getRoot().setResource(Color.blue); } public class ExampleScreen extends BScreen { public boolean handleAction(BView arg0, Object arg1) { if (“pop”.equals(arg1.toString())) {

148

Going Bananas getBApp().setActive(false); getBApp().play(“thumbsup.snd”); } return super.handleAction(arg0, arg1); } public ExampleScreen(BApplication arg0) { super(arg0); BButton myButton = new BButton(this, 100, 100, 200, 50, true); myButton.setResource(createText(“default-20.font”, “0xFFFFFF”, “Test Button”)); myButton.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “pop”, null, null, H_DOWN, false); BButton myButton2 = new BButton(this, 100, 200, 200, 50, true); myButton2.setResource(createText(“default-20.font”, “0xFFFFFF”, “Test Button”)); myButton2.setBarAndArrows( BAR_DEFAULT, BAR_DEFAULT, “pop”, null, H_UP, H_DOWN, true); BButton myButton3 = new BButton(this, 100, 300, 200, 50, true); myButton3.setBarAndArrows( BAR_HANG, BAR_DEFAULT, “pop”, null, H_UP, null, true); BText text = new BText(myButton3, 0, 0, myButton3.getWidth(), myButton3.getHeight()); text.setShadow(“0x666666”, 2); text.setValue(“text 3”); text.setFont(“default-20.font”); setFocusDefault(myButton); } } }

BKeyboard The keyboard widget that comes with Bananas is probably the most advanced widget in the toolkit, and simplifies retrieving data from the user that is not based on menus or buttons. There are two basic types of keyboards built into the keyboard widget: the plain keyboard and the email keyboard. Figure 7-10 shows an example of a plain keyboard, and Figure 7-11 shows an example of an email keyboard.

149

Chapter 7

Figure 7-10

Figure 7-11

150

Going Bananas

Using the Keyboard Widget The keyboard is used like the button widget; there is no extension of classes required, and a new BKeyboard widget can be placed on a BScreen just like a button. The BKeyboard is created using one of the BKeyboard constructors: new BKeyboard(BView parent, int x, int y, int width, int height) new BKeyboard(BView parent, int x, int y, int width, int height, BKeyboard.Keyboard keyboard, boolean tips, int textEntryWidth, boolean visible) new BKeyboard(BView parent, int x, int y, int width, int height, int keyboardType, boolean tips)

The first constructor takes the parent view (getNormal() on the BScreen containing the keyboard), the coordinates for the keyboard, and the width and height for the keyboard. The second constructor also takes the same parameters as the first, and also additional parameters that indicate which Keyboard type to use, whether or not to show a tips area, the width of the text entry bar, and the visibility of the widget. The final constructor takes an integer instead of the BKeyboard.Keyboard type, but essentially performs the same task. The following example sets up a keyboard and a button below the keyboard to exit the application. Like buttons, the whole keyboard widget participates in the focus manager. package com.wiley.hme.ch7; import java.awt.Color; import java.awt.Point; import import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BButton; com.tivo.hme.bananas.BEvent; com.tivo.hme.bananas.BKeyboard; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class ExampleKeyboard extends BApplication {

public class BSelectButton extends BButton { private String selectAction; public BSelectButton(BView arg0, int arg1, int arg2, int arg3, int arg4) { super(arg0, arg1, arg2, arg3, arg4); } public void setSelectAction(String action) { this.selectAction = action; } public boolean handleKeyPress(int key, long arg1) {

151

Chapter 7 if (key == KEY_SELECT) { getParent().postEvent(new BEvent.Action(this, selectAction)); } return super.handleKeyPress(key, arg1); }

} public void init(IContext context) throws Exception { super.init(context); push ( new KeyboardScreen(this), TRANSITION_FADE); } public class KeyboardScreen extends BScreen {

private BKeyboard kb; public boolean handleAction(BView arg0, Object arg1) { if (“pop”.equals(arg1.toString())) { getBApp().setActive(false); } else if (“msg”.equals(arg1)) { getBApp().push(new MessageScreen(getBApp(), kb.getValue()), TRANSITION_LEFT); } return super.handleAction(arg0, arg1); } public KeyboardScreen(BApplication arg0) { super(arg0); Point p = BKeyboard.getKeyboardSize(BKeyboard.PLAIN_KEYBOARD, true); kb = new BKeyboard(getNormal(), 100, 100, p.x, p.y, BKeyboard.PLAIN_KEYBOARD, true); kb.setFocusable(true); setFocusDefault(kb); BSelectButton b = new BSelectButton(getNormal(), 100, p.y+150, 100, 50); b.setSelectAction(“pop”); b.setResource(createText(“default-20.font”, “0xFFFFFF”, “Quit”)); b.setBarAndArrows(BAR_HANG, BAR_DEFAULT, “pop”, H_RIGHT, H_UP, null, true); BSelectButton b2 = new BSelectButton(getNormal(), 400, p.y+150, 100, 50); b2.setSelectAction(“msg”); b2.setResource(createText(“default-20.font”, “0xFFFFFF”, “Okay”)); b2.setBarAndArrows(BAR_DEFAULT,BAR_HANG, H_LEFT, “msg”, H_UP, null, true); }

152

Going Bananas } public class MessageScreen extends BScreen { public boolean handleAction(BView arg0, Object arg1) { if (“pop”.equals(arg1)) { getBApp().pop(); } return super.handleAction(arg0, arg1); } public MessageScreen(BApplication arg0, String message) { super(arg0); BText bt = new BText(getNormal(), 100, 100, 400, 300); bt.setValue(message); bt.setFont(“default-50.font”); bt.setColor(Color.white); BSelectButton b = new BSelectButton(getNormal(), 100, 400, 100, 50); b.setSelectAction(“pop”); b.setResource(createText(“default-20.font”, “0xFFFFFF”, “Back”)); b.setBarAndArrows(BAR_HANG, BAR_DEFAULT, “pop”, null, H_UP, null, true); setFocusDefault(b); } } }

In this example, the width of the widget is provided by the widget itself. The getKeyboardSize() call is a static method that provides the width and height of the keyboard widget. The dimensions are then used to create the widget in the next line of the sample code.

Try It Out

Use the Email Keyboard

How would you update the preceding example to use the email keyboard? Both the plain keyboard and email keyboard are the same widget, essentially, only with a different type. Changing to the email keyboard would require changing the references from BKeyboard.PLAIN_KEYBOARD to BKeyboard.EMAIL_KEYBOARD. Changing the lines Point p = BKeyboard.getKeyboardSize(BKeyboard.PLAIN_KEYBOARD, true); kb = new BKeyboard(getNormal(), 100, 100, p.x, p.y, BKeyboard.PLAIN_KEYBOARD, true);

153

Chapter 7 to Point p = BKeyboard.getKeyboardSize(BKeyboard.EMAIL_KEYBOARD, true); kb = new BKeyboard(getNormal(), 100, 100, p.x, p.y, BKeyboard.EMAIL_KEYBOARD, true);

will use the email keyboard instead.

BSkin Bananas widgets are styled with a very TiVo UI look and feel. Of course, not all applications will want to have the exact look and feel of the TiVo user interface. The authors’ application, AudioFaucet (Figure 7-12), for example, uses the Bananas toolkit but has custom graphics for all of the widgets it uses. Although this does create a somewhat different feel to the application, in this case, that was the intent. The TiVo user interface is highly usable, but applications that are specific to a particular domain, or that have a style of their own, may want to override the default images with buttons or lists that match an established brand or user interface style.

Figure 7-12

Bananas uses a class called BSkin to manage the graphics used for all the widgets, and it provides three different ways to override the default skin in order to customize an application. The widgets are all constructed of a few simple images:

154

Going Bananas Image File Name

Size of Image (pixels )

bar.png

640 Wide x 48 High

down.png

20 Wide x 7 High

left.png

8 Wide x 20 High

pagedown.png

14 Wide x 26 High

pageup.png

14 Wide x 26 High

right.png

8 Wide x 20 High

up.png

20 Wide x 7 High

The first task in creating a new skin is to create images with the file names listed in this table and the proper dimensions. There are three different BSkin subclasses. All these classes provide the same functionality, differing only in how the files that are used for the skin are located.

BDirSkin BDirSkin uses a directory of images to locate the files for displaying the Bananas widget. The second argument in the constructor is the directory to find the skin files in: BSkin skin = new BDirSkin(this, “skin/”);

BZipSkin BZipSkin uses a ZIP file of images to locate the files for displaying the Bananas widget. The second argument in the constructor is the ZIP file that contains the skin files: BSkin skin = new BZipSkin(this, “skinFile.zip”);

BResSkin BResSkin uses the classpath to locate the files for displaying the Bananas widget. The second argument in the constructor is the path in the classpath to look for images. The images can either be inside a jar file or outside a jar file. BSkin skin = new BResSkin(this, “com/wiley/hme/ch7/”);

Example The following shows how to set a skin for a user with Bananas. This example is using BResSkin. This example assumes that the required graphics listed in the preceding table — bar.png, up.png, and so on — reside in the com/wiley/hme/ch7 directory. You can find an example set of these graphics in the samples/skin-charcoal directory of the Bananas toolkit (see Figure 7-13).

155

Chapter 7 package com.wiley.hme.ch7; import java.awt.Color; import import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BResSkin; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BSkin; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class BSkinExample extends BApplication { String listItems[] = {“one”, “two”, “three”, “four” }; public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(Color.black); BSkin skin = new BResSkin(this, “com/wiley/hme/ch7/”); this.setSkin(skin); push(new simpleScreen(this), TRANSITION_LEFT); } public boolean handleKeyPress(int arg0, long arg1) { // TODO Auto-generated method stub return super.handleKeyPress(arg0, arg1); }

public class SimpleBList extends BList { public SimpleBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); this.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “left”, “right”); } protected void createRow(BView parentView, int index) { if (get(index) != null) { BText text = new BText(parentView, 0 , 0 , parentView.getWidth(), parentView.getHeight()); text.setValue(get(index).toString()); } } } public class simpleScreen extends BScreen { public simpleScreen(BApplication app) { super(app); BList list = new SimpleBList(getNormal(), 100, 100, 400, 300, 48);

156

Going Bananas list.add(listItems); list.setVisible(true); setFocusDefault(list); } } }

Figure 7-13

Summar y The Bananas widget toolkit provides the basic widget for imparting a TiVo look and feel on your application and inheriting key behaviors. The Bananas toolkit, like the base HME SDK, requires extension from the classes included in the library. Lists, buttons, and the keyboard widget provide enough basic functionality to create a high-quality interface, and the skinning capabilities allow for a custom look on top of the Bananas widgets. Custom widgets may be built on top of the Bananas library, allowing for greater flexibility in developing an application with a unique user interface. Bananas has a slightly different event model, using actions for processing much of the interaction with the widgets. Bananas events and actions are the subject of the next chapter, which delves deeper into how to hook the widgets up to a functioning application.

157

Chapter 7

Questions 1.

What is wrong with the following code?

BList myList = new BList(getNormal(), 100, 100, 300, 400);

2. 3.

158

Should the BApplication’s subclass call super.init(context)? When? Why? How do BButtons know which of the left, right, up, and down keys can be used to move from the button to other items?

8 Using Bananas Events Many of the examples in the previous chapter made use of Bananas event handling. Making HME applications is really all about interacting with the user, bringing data and an innovative interface to the television to allow for more complex tasks to be done from the living room or to extend the reach of a current application. Key to the success of all these types of applications is interaction with the user. Just as HME events made the applications from Chapter 6 more interesting than the static ones from Chapter 5, learning how events are processed in Bananas will greatly expand the range and level of complexity a Bananas application can handle and allow for more powerful user interaction. The Bananas toolkit does not alter the underlying event processing system. If you recall from Chapter 6, events are sent by the TiVo and are processed by the application, which would normally take some sort of action, changing the display on the TiVo or playing a sound. The HME SDK contains the events for handling key presses, application events, and resource events. Bananas adds a few events for processing Bananas information using the HME event system. At the end of Chapter 6, there was an example of creating custom events in HME. This is precisely how Bananas manages to add events to the base set of HME events. By the end of this chapter, you will learn ❑

The difference between HME events and Bananas actions



How Bananas widgets send event data



How to hook into the Bananas events flow

Event Model The new Bananas classes introduce a different event model to handle the events that are introduced with Bananas. Event processing is still largely based on the event flow from Chapter 6. Some initial processing is done by the new BApplication class; BView relies heavily on the View subclass for event flow as well.

Chapter 8 The event flow in Bananas is shown in Figure 8-1. TiVo Box

handleChunk()

BApplication’s dispatchEvent()

Is Key event

No

Application’s dispatchEvent()

Yes

Yes

Done

No

Does a view in the current screen have focus?

Yes

View.postEvent()

Parent View’s postEvent()

Current Screen is Null?

Parent View’s postEvent()

BApplication’s dispatchEvent() (HmeEvent.Key)

If not handled

If not handled

BView::handleAction()

No

BView::handleFocus()

BScreen.handleEvent()

ScreenEnter

BScreen::handleEnter()

FocusEvent

ScreenEnter

BScreen::handleExit()

ActionEvent

BView.handleEvent()

If View is BKeyboard and event is KeyBoard Event

Update textfield

160

Figure 8-1

Using Bananas Events

New Events in Bananas The events that Bananas adds are all encapsulated in the BEvent class. BEvent contains four static inner classes. The four inner classes are the three events Bananas uses to superimpose additional events on the HME event structure. The four BEvent inner classes are ❑

ScreenEnter



ScreenExit



Focus



Action

All of these BEvents have corresponding handlers in the classes that can handle them. The ScreenEnter and ScreenExit events are only sent to BScreen subclasses. The handlers are called when the screen is pushed or popped to or from the BScreen stack. HandleEnter is called either when a BScreen is first pushed, or when another screen has been popped, resulting in a “return” to this BScreen. HandleEnter is called with two arguments, an Object and a boolean, which indicates if the screen is being pushed for the first time or if this is a return to a screen that was already pushed. The boolean is true if the screen is being “returned to” and false if the screen has been newly added to the stack. The Object argument to handleEnter() is passed along from the push(BScreen,int,Object) call to push a screen. If this version of push() is called, the Object passed in this push() call is sent along to the handleEnter() call. If the push(BScreen,int) form of push is used, the Object value will be null. The handleExit() call takes no parameters, and is called when a screen is exiting. handleExit() is also called when a new screen is pushed over the current screen. The following example uses the handleEnter() event handler in BScreen to change the look and feel of the screen, depending on whether or not the screen is first in the screen stack: package com.wiley.hme.ch8; import java.awt.Color; import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BButton; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class EnterExitExample extends BApplication {

public void init(IContext arg0) throws Exception { super.init(arg0);

161

Chapter 8 push(new ExampleScreen(this), TRANSITION_FADE); }

public class ExampleScreen extends BScreen { private BText data; private BButton button; public ExampleScreen(BApplication arg0) { super(arg0); data = new BText(this, 100, 100, 200, 100); data.setColor(Color.blue); data.setFont(“default-30.font”); button = new BButton(getNormal(), 100, 400, 250, 30); } public boolean handleAction(BView arg0, Object arg1) { // quit application if we are leaving the last screen on the stack if (“pop”.equals(arg1)) { if (getBApp().getStackDepth() == 1) { getBApp().setActive(false); } else { getBApp().pop(); } } if (“push”.equals(arg1)) { getBApp().push(new ExampleScreen(getBApp()), TRANSITION_LEFT); } return super.handleAction(arg0, arg1); } public boolean handleEnter(Object arg0, boolean arg1) { System.out.println(“handleEnter() for screen “ + getBApp().getStackDepth()); if (getBApp().getStackDepth() == 1) { button.setBarAndArrows(BAR_HANG, BAR_DEFAULT, “pop”, “push”, null, null, true); button.setResource(createText(“default-20.font”, Color.white, “L to Quit, R to Continue”)); } else { button.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “pop”, “push”, null, null, true); button.setResource(createText(“default-20.font”, Color.white, “L to Quit, R to Continue”)); } data.setValue(“Screen: “ + getBApp().getStackDepth()); setFocusDefault(button); return super.handleEnter(arg0, arg1); } public boolean handleExit() {

162

Using Bananas Events System.out.println(“handleExit() for screen “ + getBApp().getStackDepth()); return super.handleExit(); } } }

The handleExit() handler in this case just prints out that the screen was exited. The handleExit() method is a good place to clean up any threads, sockets, or other resources that are used by a screen. The output generated by the preceding application when going from screen 1 to 4 will be: LOG: added factory MDNS: http://192.168.1.103:7288/ch8/ RUNNING: http://192.168.1.103:7288/ch8/ handleEnter() for screen 1 LOG: HME receiver connected handleExit() for screen 1 handleEnter() for screen 2 handleExit() for screen 2 handleEnter() for screen 3 handleExit() for screen 3 handleEnter() for screen 4

In the output, you can see that handleEnter() is called for screen 1 when it is pushed, and when screen 2 is pushed, handleEnter() is called for screen 2 and handleExit() is called for screen 1, because the application is “leaving” screen 1 (Figure 8-2).

Figure 8-2

163

Chapter 8

Using Actions Actions are represented by the BEvent.Action class. Actions are subclasses of BEvent and pair a BView with an Object that represents data that is attached to the action. The Action class is used with the button and list widgets. As you saw in the previous chapter, the setBarAndArrows() method to set up the actions that the button and list widget can perform set up the actions that are sent via events. All action events are handled with the handleAction() method. In the previous example, handleAction is defined as: public boolean handleAction(BView arg0, Object arg1) { // quit application if we are leaving the last screen on the stack if (“pop”.equals(arg1)) { if (getBApp().getStackDepth() == 1) { getBApp().setActive(false); } else { getBApp().pop(); } } if (“push”.equals(arg1)) { getBApp().push(new ExampleScreen(getBApp()), TRANSITION_LEFT); } return super.handleAction(arg0, arg1); }

In this example, arg0 is the BView that generated the action which now must be handled, and the Object passed is the result of ba.getAction() where ba is an object of type BEvent.Action. The static internal classes that subclass BEvent are somewhat confusing, but after using actions a few times, they become clearer. The handleAction() shown in the preceding code is in the BScreen. Actions are really just custom HME events, as discussed in Chapter 6, and can be sent in just the same way. Bananas tends to use postEvent() rather than sendEvent() because actions do not require an animation, and using postEvent() avoids the round trip to the TiVo box that sendEvent() would require. In the preceding example, the action is passed to the super.handleAction() event after action has been taken by this handleAction() method. This is done because other Objects in the Bananas action flow may also want to key off the “push” or “pop” actions. In some cases, returning true from handleAction() to signal that the action processing should be stopped is the correct course of action. In other cases, continuing processing of actions may be useful so that other objects can perform additional work based on the actions.

Custom Actions Actions are very powerful events in Bananas. As you have seen, they are the basis for the actions taken from buttons and lists and are used to manage moving focus around a screen.

164

Using Bananas Events Try It Out There are several keyboard keys that do not map to actions, however. Most notably is probably the BButton class not handling “select.” The following code processes a KEY_SELECT button in the handleKeyPress() handler, and posts an Action event with the Object “select”. The handleAction() method then plays the thumbsup.snd sound. package com.wiley.hme.ch8; import java.awt.Color; import import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BButton; com.tivo.hme.bananas.BEvent; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class CustomAction extends BApplication { public void init(IContext arg0) throws Exception { super.init(arg0); push(new CustomActionScreen(this), TRANSITION_FADE); } public class CustomActionScreen extends BScreen { BButton b; BText bt; BText actionText; public CustomActionScreen(BApplication app) { super(app); b = new BButton(getNormal(), 100, 100, 200, 30); b.setBarAndArrows(BAR_HANG, BAR_DEFAULT, “pop”, “push”, “up”, “down”, true); b.setResource(createText(“default-20.font”, Color.white, “Button!”)); bt = new BText(getNormal(), 200, 100, 300, 400); bt.setColor(Color.white); bt.setFont(“default-20.font”); bt.setValue(“The text area above will change to show the action that was \n” + “triggered. Up/down/right/select keys will produce actions.\n” + “Left will produce an action causing the application to quit.\n”); bt.setVisible(true); actionText = new BText(getNormal(), 350, 50, 200, 100); actionText.setColor(Color.blue); actionText.setFont(“default-30.font”); actionText.setVisible(true); this.setFocusDefault(b);

165

Chapter 8 } public boolean handleAction(BView arg0, Object arg1) { System.out.println(arg1.toString()); actionText.setValue(arg1.toString()); if (“select”.equals(arg1)) { getBApp().play(“thumbsup.snd”); } if (“pop”.equals(arg1)) { getBApp().setActive(false); } return super.handleAction(arg0, arg1); } public boolean handleKeyPress(int arg0, long arg1) { if (this.getFocus() != null && this.getFocus().equals(b)) { if (arg0 == KEY_SELECT) { postEvent(new BEvent.Action(this.getFocus(), “select”)); } } return super.handleKeyPress(arg0, arg1); } } }

How It Works Although Bananas uses String objects to pass data around for actions, any Object can be used. This can allow great flexibility for passing data around while still adhering to the HME event system. In this example, the action “select” (a String object) is sent when the select button is received via that handleKeyPress() event handler.

Custom Widgets Now that you can tie into the actions handling in Bananas, you have all the tools for writing custom widgets. The example here creates a set of radio buttons using the BList widget, and sends custom action BEvents called “select” when a radio button is selected: package com.wiley.hme.ch8; import import import import

com.tivo.hme.bananas.BEvent; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView;

public class BRadioButtonGroup extends BView { int selectedIndex = -1; BView normal; BView below;

166

Using Bananas Events RadBList options; public BRadioButtonGroup(BView parent, int x, int y, int width, int height, int rowHeight) { super(parent, x,y,width,height); below = getBApp().getBelow(); normal = new BView(this, 0,0,width, height); BView topLeftBV = new BView(below,x,y-15,width/2,26); BView topRightBV = new BView(below,x+width/2,y-15,width/2,26); BView bodyBV = new BView(below, x, y+11, width, height); topLeftBV.setResource(getResource(“radioBoxTop.png”), RSRC_HALIGN_LEFT); topRightBV.setResource(getResource(“radioBoxTop.png”), RSRC_HALIGN_RIGHT); topLeftBV.setVisible(true); topRightBV.setVisible(true); bodyBV.setResource(getResource(“radioBox.png”), RSRC_VALIGN_TOP); options = new RadBList(normal, setFocusable(true);

10,

0,

width-20, height, rowHeight);

} public void add(Object arg0) { options.add(new OptionItem(arg0.toString())); } public String getSelection() { if (selectedIndex < 0) return “”; return options.get(selectedIndex).toString(); } public boolean handleAction(BView view, Object action) { if (“select”.equals(action)) { getBApp().getCurrentScreen().setPainting(false); OptionItem o = (OptionItem) options.get(options.getFocus()); if(selectedIndex >= 0) { OptionItem o_last = (OptionItem) options.get(selectedIndex); o_last.getButton().setResource(getResource(“radiobuttonOff.png”)); } o.getButton().setResource(getResource(“radiobuttonOn.png”)); selectedIndex = options.getFocus(); } return super.handleAction(view, action); } public RadBList getOptions() { return options; } public void setBarAndArrows(int arg0, int arg1, Object arg2, Object arg3) { options.setBarAndArrows(arg0, arg1, arg2, arg3);

167

Chapter 8 } public class RadBList extends BList { public RadBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); } protected void createRow(BView parent, int index) { if (get(index) != null) { BText t = new BText(parent, 32, 0, parent.getWidth()-47, parent.getHeight()); t.setValue(get(index).toString()); BView button = new BView(parent, 15, parent.getHeight()/2-(32/2) ,32,32); button.setResource(getResource(“radiobuttonOff.png”)); ((OptionItem)get(index)).setButton(button); } } public boolean handleKeyPress(int code, long rawcode) { if (code == KEY_SELECT) { postEvent(new BEvent.Action(this, “select”)); } return super.handleKeyPress(code, rawcode); } } public class OptionItem { BView button; String option; public OptionItem(String option) { this.option = option; } public void setButton(BView button) { this.button = button; } public BView getButton() { return button; } public String toString() { return option; } } }

The OptionItem class keeps track of the selected and unselected state of the button, and is used as the Object in the list.

168

Using Bananas Events The RadioButtonGroup is a subclass of BView, creates the background for the options list, and delegates some functionality to the BList (see Figure 8-3). The application is driven by a very simple BApplication and BScreen subclass that demonstrates the action events that are sent by the custom widget: package com.wiley.hme.ch8; import java.awt.Color; import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BResSkin; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

public class CustomWidgetApp extends BApplication { public class WidgetScreen extends BScreen { BRadioButtonGroup rad; BText text; public WidgetScreen(BApplication arg0) { super(arg0); text = new BText(getNormal(), 400, 100, 100, 100); text.setColor(Color.white); text.setFont(“default-20.font”);

rad = new BRadioButtonGroup(getNormal(), 100, 100, 300, 400, 48); rad.add(“test1”); rad.add(“test2”); rad.add(“test3”); rad.add(“test4”); rad.setBarAndArrows(BAR_DEFAULT, BAR_DEFAULT, “pop”, H_RIGHT); } public boolean handleEnter(Object arg, boolean isReturn) { setFocusDefault(rad.getOptions()); return super.handleEnter(arg, isReturn); } public boolean handleAction(BView view, Object action) { if (“select”.equals(action)) { text.setValue(rad.getSelection()); } if (“pop”.equals(action)) { getBApp().setActive(false); } return super.handleAction(view, action); }

169

Chapter 8 } public void init(IContext arg0) throws Exception { super.init(arg0); this.setSkin(new BResSkin(this, “com/wiley/hme/ch8/”)); push(new WidgetScreen(this), TRANSITION_FADE); } }

Figure 8-3

Weather Application Example The following example is an update of the weather application from Chapter 5. This application has been written as a more traditional Java application with separate source files for each class.

Try It Out

Weather Application

The examples in this and other chapters typically use a single class to illustrate the feature being discussed; however, in real-world applications, classes will likely be spread over different class files. The application itself is driven by a small BApplication subclass that pushes the initial screen of the application.

170

Using Bananas Events BWeatherApp.java package com.wiley.hme.ch8; import java.awt.Color; import com.tivo.hme.bananas.BApplication; import com.tivo.hme.bananas.BView; import com.tivo.hme.interfaces.IContext; public class BWeatherApp extends BApplication { public static String A_QUIT = “quit”; public boolean handleAction(BView view, Object action) { if (A_QUIT.equals(action)) { setActive(false); } return super.handleAction(view, action); } public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(Color.white); push(new ZipScreen(this), TRANSITION_FADE); } }

The BWeatherApp class’s main purpose is to set up the application and process the action “quit” to close the application. The screen that is first pushed is the ZipScreen. ZipScreen is again a simple screen that is designed to capture Zip code information from the user in order to look up weather. ZipScreen.java package com.wiley.hme.ch8; import java.awt.Color; import java.awt.Point; import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BButton; com.tivo.hme.bananas.BKeyboard; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView;

public class ZipScreen extends BScreen { private BKeyboard keyb; public ZipScreen(BApplication app) { super(app);

171

Chapter 8 Point p = BKeyboard.getKeyboardSize(BKeyboard.PLAIN_KEYBOARD, false); keyb = new BKeyboard(getNormal(), 100, 100, p.x, p.y, BKeyboard.PLAIN_KEYBOARD, true); keyb.setFocusable(true); BText text = new BText(getNormal(), SAFE_TITLE_V, 0, 640, 50); text.setColor(Color.black); text.setFont(“default-30.font”); text.setValue(“Enter Zip Code:”); BButton button = new BButton(getNormal(), 300, 400, 250, 48); button.setVisible(true); button.setResource(createText(“default-20.font”, “0xFFFFFF”, “Continue”)); button.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “quit”, “getweather”, H_UP, null, false); setFocusDefault(keyb); } public boolean handleAction(BView view, Object action) { if (“getweather”.equals(action)) { getBApp().push(new WeatherScreen(getBApp(), keyb.getValue()), TRANSITION_LEFT); return true; } return super.handleAction(view, action); } }

The ZipScreen collects the Zip code information using a standard BKeyboard widget, and when the right key is pressed when the button is selected, a WeatherScreen is pushed with information about the weather for the Zip code entered (Figure 8-4).

172

Figure 8-4

Using Bananas Events The ZipScreen BButton button sends the “quit” action when the left key is pressed on the button. Because this screen does not handle the “quit” action, it will be propagated to the application, which handles it by exiting, as shown in BWeatherApp.java. The final screen, WeatherScreen, retrieves the weather information and displays it on the TiVo box. WeatherScreen has a few helper methods to assist in styling BText objects and parsing data. WeatherScreen.java package com.wiley.hme.ch8; import java.awt.Color; import java.io.IOException; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Vector; import com.sun.syndication.io.FeedException; import com.tivo.hme.bananas.*; public class WeatherScreen extends BScreen { BText title; BText forcast; BText currently; BView icon; String zip; private WeatherFeedReader feed; public WeatherScreen(BApplication app, String zip) { super(app); this.zip = zip; try { feed = new WeatherFeedReader(zip); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (FeedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } feed.parse(); title = setupBText (title ,getNormal(), 0, SAFE_TITLE_V, 640, 40,Color.black,”default-36.font”, RSRC_HALIGN_CENTER); forcast = setupBText(forcast, getNormal(), SAFE_TITLE_H, title.getY()+60, 200, 200, Color.blue, “default-15.font”, RSRC_HALIGN_LEFT); currently = setupBText(currently, getNormal(), SAFE_TITLE_H, forcast.getY()+150, 100, 100, Color.DARK_GRAY, “default-20.font”, RSRC_HALIGN_LEFT); icon = new BView(getNormal(), 300, title.getY()+150, 150, 150); } public boolean handleKeyPress(int code, long rawcode) {

173

Chapter 8 if (code == KEY_LEFT) { getBApp().pop(); return true; } return super.handleKeyPress(code, rawcode); }

public boolean handleEnter(Object arg, boolean isReturn) { String titleStr = feed.getTitle(); String forcastStr = join (feed.getForcast(), “\n”); String currentlyStr = join (feed.getCurrentConditions(), “\n”); title.setValue(titleStr); forcast.setValue(forcastStr); currently.setValue(currentlyStr); icon.setResource(getResource(feed.getImageUrl()), RSRC_IMAGE_BESTFIT); return super.handleEnter(arg, isReturn); } public static BText setupBText(BText bt, BView view, int x, int y, int w, int h, Color color, String font, int flags) { bt = new BText(view, x,y,w,h); bt.setColor(color); bt.setFont(font); bt.setFlags(flags); return bt; } private String join(String[] string_array, String delim) { String joined = “”; for (String s : string_array) { joined = joined + s + delim; } return joined; } }

The WeatherScreen makes use of another helper class, WeatherFeedReader, to retrieve the weather information. WeatherScreen uses handleEnter() to signal when to set up the visible screen and handleKeyPress() to listen for a KEY_LEFT event, at which point WeatherScreen exits this screen. Some Java 5 syntax is used in the preceding code. As noted early on, HME, and in turn Bananas, require Java 1.4, but work quite well with Java 5 as well. The abbreviated for loop syntax in the example code will work only with Java 5. To enable Java 5 within Eclipse, select your project, then select Project ➪ Properties. In the Java Compiler section, check the box next to “Enable project specific settings,” and then set the Compiler compliance level to 5.0 (Figure 8-5).

174

Using Bananas Events

Figure 8-5

The WeatherFeedReader that the WeatherScreen relies on to retrieve and parse the information from the Internet uses two outside libraries, Rome (https://rome.dev.java.net/) and HTMLParser (http://htmlparser.sourceforge.net/). The weather information is retrieved from a Yahoo RSS feed, and the HTML data returned in the feed is parsed for relevant information using HTMLParser. The jars required for the WeatherFeedReader class are rome-0.8.jar, jdom.jar, thumbelina.jar, htmlparser.jar, htmllexer.jar, and filterbuilder.jar. These are all included in the downloads for HTMLParser and the Rome RSS parser. To add the jars to your project, drag them to the project folder in Eclipse. Eclipse will copy the jar files to the project, and pass them to the build path. WeatherFeedReader.java package com.wiley.hme.ch8; import import import import import import

java.io.IOException; java.net.MalformedURLException; java.net.URL; java.util.Iterator; java.util.List; java.util.Vector;

import import import import import

org.htmlparser.Node; org.htmlparser.Parser; org.htmlparser.util.NodeList; org.htmlparser.util.ParserException; org.htmlparser.util.SimpleNodeIterator;

import import import import import import import

com.sun.syndication.feed.synd.SyndContent; com.sun.syndication.feed.synd.SyndEntry; com.sun.syndication.feed.synd.SyndEntryImpl; com.sun.syndication.feed.synd.SyndFeed; com.sun.syndication.io.FeedException; com.sun.syndication.io.SyndFeedInput; com.sun.syndication.io.XmlReader;

public class WeatherFeedReader { private SyndFeed feed;

175

Chapter 8 private URL url; static String url_base=”http://xml.weather.yahoo.com/forecastrss?p=”; private String imageString; private Vector currVec; private Vector forVec; public WeatherFeedReader(String urlString) throws IllegalArgumentException, FeedException, IOException { url = new URL(url_base+urlString); SyndFeedInput input = new SyndFeedInput(); feed = input.build(new XmlReader(url)); } public String getTitle() { return feed.getTitle(); } public List getEntries() { return feed.getEntries(); } public void parse() { List l = getEntries(); Iterator iter = l.iterator(); String data = ((SyndContent)((SyndEntry)iter.next()).getContents().iterator().next()).getValue(); Parser parser = Parser.createParser(data, “UTF-8”); NodeList list = null; try { parser.setFeedback(Parser.STDOUT); list = parser.parse(null); } catch (ParserException e) { e.printStackTrace(); } imageString = “”; currVec = new Vector(); forVec = new Vector(); int mode = 0; SimpleNodeIterator nodeIter = list.elements(); while(nodeIter.hasMoreNodes()) { Node n = nodeIter.nextNode(); String pt = n.toPlainTextString(); if (pt != null && pt.startsWith(“Current Cond”)) { mode = 1; continue; } else if (pt != null && pt.startsWith(“Forecast”)) { mode = 2;

176

Using Bananas Events continue; } else if (pt != null && pt.startsWith(“Full Forecast”)) { mode = 0; continue; } pt = pt.trim(); if (pt != null && !””.equals(pt)) { if (mode == 1) { currVec.add(pt); } else if(mode == 2) { forVec.add(pt); } } String t = n.getText(); if ( t != null && t.startsWith(“img”)) { String[] tmpStrAry = t.split(“\””); for (String s : tmpStrAry) { if (s!=null && s.startsWith(“http”)) { imageString = s; } } } } } protected static String[] stringArrayFromObjectArray(Object[] o) { String[] s = new String[o.length]; for (int i=0; i

This method basically just returns the string “3”. Using Axis libraries, calls to this service can be made: try { String endpoint = “http://localhost/~john/soap/lookup.php”; Service Call

service = new Service(); call = (Call) service.createCall();

call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName(“”, “lookup”)); String ret = (String) call.invoke( new Object[] {

} );

System.out.println(“Got ‘“ + ret + “‘“); } catch (Exception e) { System.err.println(e.toString()); }

In this case, running under Mac OS X, I was running the web service locally, so the endpoint is the URL of the PHP page, and the method to call is specified in the setOperationName(). Some freely available SOAP services are available over the Internet, including a stock quote service available at http://www .incesbot.com. The stock viewer application for HME available from http://www.bitrazor.com uses this SOAP service to obtain stock information.

RSS RSS data is used in Example 8-4, accompanying the text. The WeatherFeedReader class pulls data from the Yahoo weather RSS feed, parsing out the information needed for the screen. RSS is probably one of the most commonly available structured delivery methods available today. The WeatherFeedReader uses the Rome library (https://rome.dev.java.net/) for retrieving and parsing RSS in Java. The Rome RSS parser can retrieve information about the articles in an RSS feed, as well as the feed itself. It is probably one of the best Java libraries for working with the ever-growing amount of RSS-enabled web sites and services. RSS has been used primarily for syndicating blogs, but other web sites are now providing information via RSS. One prominent example is NetFlix, which provides subscribers of the service their movie queue information via RSS. The NetFlix RSS Reader application for HME, also available from http://www .bitrazor.com, utilizes the RSS feed provided by NetFlix and the library MyJavaTools for parsing the RSS data (http://www.myjavatools.com/).

247

Chapter 13

XML Data XML data can be parsed in several different ways. SAX and DOM parsers are the two main ways of parsing XML data. The authors’ application, AudioFaucet, uses the Xerces XML parser from Apache to process XML files (http://xerces.apache.org/xerces-j/). Xerces is probably one of the most common XML parsers used in Java. Another option is XML Beans (http://xmlbeans.apache.org/), also from Apache, which can process XML files directly into Java objects, and is extremely useful when complex XML documents must be parsed. The technical reviewer for this book authored a TrafficCam Viewer application that uses JAXB extensively to parse XML and turn the XML into Java objects. This application reads XML lists of traffic cameras from more than 40 cities and cycles through them on your TiVo box. The TrafficCam application is available on http://www.bitrazor.com.

JDBC JDBC is the Java database connectivity class, and provides for access to SQL databases. SQL databases can be useful, even in small Java applications, for organizing data, providing search capability using standard SQL searching. The authors’ application, AudioFaucet, uses an internal database to quickly sort through song information from users’ music libraries, which can often be quite large in scale. JDBC connectors are available for nearly all databases available today. HSQLDB (http://www.hsqldb .org/) is the database the authors use because it can be packaged entirely into an application, whereas a database such as MySQL would require a separate installation. For internally sorting through data, and preserving data across runs of the application, HSQLDB is a lightweight, but powerful, solution.

Try It Out

Access Data in an HSQLDB Database

The following code creates and accesses a database, creating a simple BList out of the returned data: package com.wiley.hme.ch13;

248

import import import import import import

java.awt.Color; java.sql.CallableStatement; java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.SQLException;

import import import import import import

com.tivo.hme.bananas.BApplication; com.tivo.hme.bananas.BList; com.tivo.hme.bananas.BScreen; com.tivo.hme.bananas.BText; com.tivo.hme.bananas.BView; com.tivo.hme.interfaces.IContext;

Connecting to External Resources import com.tivo.hme.sdk.HmeEvent; public class DBApp extends BApplication { private Connection connection; public boolean handleEvent(HmeEvent arg0) { return super.handleEvent(arg0); } public void init(IContext arg0) throws Exception { super.init(arg0); try { Class.forName(“org.hsqldb.jdbcDriver” ); } catch (Exception e) { e.printStackTrace(); return; } connection = DriverManager.getConnection(“jdbc:hsqldb:file:tempDB”, “sa”, “”); CallableStatement cs = connection.prepareCall(“CREATE CACHED TABLE data (“ + “id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, “ + “name VARCHAR(255)” + “)”); cs.execute(); cs.close(); cs = connection.prepareCall(“INSERT INTO data (name) VALUES(‘item1’)”); cs.execute(); cs.close(); cs = connection.prepareCall(“INSERT INTO data (name) VALUES(‘item2’)”); cs.execute(); cs.close(); cs = connection.prepareCall(“INSERT INTO data (name) VALUES(‘item3’)”); cs.execute(); cs.close();

} public boolean handleActive(boolean arg0) { getRoot().setResource(Color.blue); push (new DBScreen(this), TRANSITION_NONE); return super.handleActive(arg0); } public class DBScreen extends BScreen { private SimpleBList list; public DBScreen(DBApp app) {

249

Chapter 13 super(app); } public boolean handleEnter(Object arg0, boolean arg1) { list = new SimpleBList(getNormal(), 100, 20, 400, 300, 30); CallableStatement cs = null; try { cs = connection.prepareCall(“SELECT name FROM data”); ResultSet rs; rs = cs.executeQuery(); while (rs.next()) { list.add(rs.getString(“name”)); } } catch (SQLException e) { e.printStackTrace(); } finally { try { cs.close(); } catch (SQLException e) { e.printStackTrace(); } } setFocusDefault(list); return super.handleEnter(arg0, arg1); } } public class SimpleBList extends BList { public SimpleBList(BView arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { super(arg0, arg1, arg2, arg3, arg4, arg5); this.setBarAndArrows(BAR_DEFAULT, BAR_HANG, “left”, “right”); } protected void createRow(BView parentView, int index) { if (get(index) != null) { BText text = new BText(parentView, 0 , 0 , parentView.getWidth(), parentView.getHeight()); text.setValue(get(index).toString()); } } } }

How It Works The preceding code is included in the accompanying examples as Ch13-3. In the init() method, the application initializes the database and inserts values. The values are selected from the database and used to build the BList.

250

Connecting to External Resources

Other Options There are as many different ways of accessing data as there are types of data available. Some of the highlights are noted here, along with some recommendations about how to use different data sources. For client/server communication from an HME application to a service on the Internet, the options are highly varied. Some of the more common methods of accessing remote data, in addition to the ones already discussed, include the following: ❑

J2EE/EJB: Java’s multi-tier strategy for enterprise applications



Hessian/Burlap for Spring server processes



RMI: Java remote method invocation to call methods in a remote Java process



JINI: Another Java strategy for calling remote services, and running remote downloadable code.

Summar y Though this chapter hasn’t strictly been about HME development, it does cover scenarios at which Java is particularly adept, and introduces some libraries for assisting in data acquisition and management. Throughout the book, even in the simple examples, remotely accessed data has been used to demonstrate the usefulness of the HME SDK. Certainly, the ability to bring the web and the data that the web has to offer to the TiVo box via HME is one of the most common and practical uses of the HME SDK.

Questions 1.

What would be the advantages of saving data from the web and storing it locally?

251

14 Deploying an HME Application Once you have your HME application completed, the next logical step is figuring out how you can distribute that application to your user base. Most users don’t understand the ins and outs of Java, thus you can safely assume that you need to package your application so that it is easily launched by your target user. The nice thing about Java is that it is for the most part independent of the platform that you are launching it on. Windows, Linux, and Mac OS X users will find that your application will run as is without the need for taking into consideration the platform that it is running on. This chapter covers the basics for creating a launchable form of your application and bundling your application for Windows and Mac OS X, and also gives some examples for how to easily allow your users to install the application in a natural way on their given platform.

Jar from Command Line The most common mechanism for Java is the built-in Java Archive, jar. Indeed, jars form the basis for all the Java packaging for libraries, web applications, enterprise applications, and applets. The other bundling and distribution methods in this chapter will reference the use of jars as the containing mechanism for an application. One of the primary reasons that jars have become such an important mechanism in packaging Java code is because in Java, each class that is defined must, unless it is an inner class, live in its own .java file. When compilation takes place in Java, the .java files are compiled to .class files. The .class files are the Java bytecode that is run in the Java Virtual Machine. Java compilation results in one .class file for each class defined in the application. Even inner classes that are contained in .java files when authoring the code are compiled into separate .class files. For even a moderately sized application, this can result in a large number of .class files, which is impractical for distribution.

Chapter 14 Creating a jar from a set of class files is really quite simple. The directory structure that is created when compiling the application must be mimicked in the jar archive. Practically, this means running the command to create a jar file in the top-level directory of the compiled code. For compiled code that is structured like this: . ./.classpath ./.project ./com ./com/wiley ./com/wiley/ch14 ./com/wiley/ch14/MyScreen.class ./com/wiley/ch14/UsableApp.class

the jar would be created by running the command: $ jar cvf ch14-1.jar com added manifest adding: com/(in = 0) (out= 0)(stored 0%) adding: com/wiley/(in = 0) (out= 0)(stored 0%) adding: com/wiley/ch14/(in = 0) (out= 0)(stored 0%) adding: com/wiley/ch14/MyScreen.class(in = 2593) (out= 1347)(deflated 48%) adding: com/wiley/ch14/UsableApp.class(in = 1075) (out= 601)(deflated 44%)

Make sure you don’t include the .java files in the jar (unless you want to give out the source code to your application as well). Eclipse can also export jar files of your project. Select Export from the File menu and click Jar file (as shown in Figure 14-1) to create a jar file for your HME project. The application (inside the jar) can be run from a Mac or other Unix variant using the command: $ java -classpath $HME:$HMESIM:$HMEHOST:$BANANAS:ch14-1.jar com.tivo.hme.sim.Simulator com.wiley.ch14.UsableApp

where HME points to hme.jar, HMEHOST points to hme-host-sample.jar, HMESIM points to simulator.jar, and BANANAS points to bananas.jar. This will run the application directly in the Simulator. For Windows users, the command is C:> java -classpath %HME%;%HMESIM%;%HMEHOST%;%BANANAS%;ch14-1.jar com.tivo.hme.sim.Simulator com.wiley.ch14.UsableApp

254

Deploying an HME Application

Figure 14-1

Creating a Web Star t Application Java Web Start is an application launcher that is typically associated with the web browser on a user’s computer. Web Start is associated with a descriptor file (JNLP file) that describes the resources that the Web Start launcher must download in order to run the application. Like a Java applet, the application is downloaded from a web site, but unlike an applet, the application runs as a standalone application, and is not subject to the same restrictions as an applet. Additional jar files may be used in Web Start applications, and all the libraries needed can be downloaded from the web site serving the application. Although Web Start does allow for full-fledged Java applications to be run, restrictions are still imposed on Web Start applications, so Web Start is not quite as flexible as a desktop application.

255

Chapter 14

Using Web Start with HME The restrictions, which are part of Web Start, affect TiVo HME applications deployed as Web Start applications in a few important ways, and there are a few steps to deploying a TiVo HME application with Web Start:

1. 2. 3.

The application must be packaged as a jar file.

4.

The jar file for the application and the HME jars must be signed.

A JNLP file describing how the application is to be run must be created. Changes to the hme-host-sample.jar must be made — Web Start restrictions prevent the application from starting otherwise.

Packaging the application as a jar file can be accomplished as shown above. After the jar file has been created, the JNLP file must be created to reference the JAR. For the Chapter 14 example, the JNLP file reads:



Chapter 14 Demo Application Wiley Press

Chapter 14 Demo Application A demo of the capabilities of running an HME application from WebStart









com.wiley.ch14.UsableApp

The information portion of the file provides meta-data about the application to be run. The security part of the JNLP file specifies all-permissions. This is necessary because otherwise the application will not be

256

Deploying an HME Application allowed access to the local network of the machine. For an easier method of generating a JNLP file, Duck Creek’s JNLP Wrapper software can generate the files needed to deploy a Web Start application. JNLP Wrapper is available at http://www.duckcreeksoftware.com/. The Resources section describes the jar files, the main class, and the arguments. Web Start restricts all access to resources and files that the application uses. Even in an application with all-permissions set, and which has been granted trusted status by the user (Web Start applications will prompt the user to allow the application all-permissions), the application must fetch all resources using the getResource() method call. Unfortunately, the default hme-host-sample, when locating the factory for the application that is being hosted, uses Java’s reflection mechanism and the classloader to locate the factory to be used. At line 151 in Main.java (part of the HME source code), the following line is used: createFactory(args, ClassLoader.getSystemClassLoader());

Unfortunately, using the system classloader is not permitted even by a Web Start application that has allpermissions indicated in the JNLP file, and that has been trusted by the user. Changing this line to createFactory (args, this.getClass().getClassLoader());

results in the same behavior in the hosting environment, but because the system classloader is not used, this can now be used by Web Start. A new jar file for hme-host-sample.jar must be created to replace the one with the system classloader in order to use HME applications with Web Start. Because the application is requesting all-permissions, all the jar files must be signed. Jars can be selfsigned using the Java SDK. Create a keystore to hold the keys: keytool -genkey -keystore hmekeystore -alias myself

Create a certificate to sign the jars with: keytool -selfcert -alias myself -keystore hmekeystore

To sign the jars that are part of the application, run: jarsigner -keystore hmekeystore ch14.jar myself

Run jarsigner against each of the jar files, including hme.jar, bananas.jar, hme-host-sample.jar, and any other jars that are included in the JNLP file. All the files, the jars, and the JNLP file can now be placed on the web server in the location specified in the JNLP file. A simple link in an HTML page to the JNLP file will trigger the application to be loaded:

Ch14-1

Start Application

257

Chapter 14 If the JNLP file is not automatically opened (for instance, if the web browser is configured to not open files after downloading), the user can open the saved JNLP file to start the application. The main advantage of deploying an application using Web Start is that the application comes from a web site, so updates require no actions on the part of the users — when launching the Web Start application via a link on a web page, users will always receive the current version of the application. Because the application doesn’t run on the server, but is rather downloaded and run locally on the user’s machine, using Web Start has almost all the advantages of building an application to be installed on the user’s system. Web Start uses the Java infrastructure to accomplish deploying the application. The difficulty with doing so is that the experience of using the application is probably a little foreign to many users. Most users are accustomed to installing software on their PC and running it. Creating an HME application that integrates into the native environment and expected workflow for a user can make for a better experience. The next sections discuss packaging applications for Microsoft Windows and for Mac OS X.

OS X Native App Mac OS X users for the most part do not anticipate having to use installers and uninstallers to add and remove programs from their computer. They tend to download their applications from company web sites in disk image form (DMG), which they then mount as a drive on their system and drag the resulting program file into their Applications folder for later use. When they are done with an application they simply throw it in the system trashcan and delete it like any other file they no longer want on their system.

Creating an Application Icon You may want to create an icon for the Application and also the Disk Image used to distribute your application bundle. Each application platform has its own distinct icon format requirements. Mac OS X uses icns format to store application icons. First find the image files that you would like to use as icons. The authors suggest that this image file be similar to that of your application’s “Music, Photos, and More” icon. The best choice is a PNG file with a transparent background, but any graphic file will do. Then simply convert the image to the icns format. There are many applications available to convert png graphic images to icns format. The authors prefer to use a freeware program called Iconverter, which you can find at http://www.extraneous.us. Once the icns file is created, save it in your resources folder for your application so that you can easily find it in the future and apply when necessary.

Bundler Most applications in Mac OS X are contained in what are called bundles to make installation and removal of the application a drag-and-drop affair. A bundle is simply a special folder that contains all of your application’s executables and data files. Unlike normal folders, however, the bundle presents itself to the end user as an ordinary program file with your application’s icon. The users can simply doubleclick the bundle to launch the application on their system.

258

Deploying an HME Application Preparing Your Resources Before you create your jar bundle, you want to create a folder on your system that contains all of the needed resources for your application, including your application jar file created using the earlier steps and the TiVo SDK jars that your applications make use of. If you are using any external binaries or code in your application, make sure you have the right to redistribute them before they are included with your application’s distribution. Many times you will also be required to include any licenses or other acknowledgments within your application’s documentation package as well.

Creating a Jar Bundle Apple provides a simple-to-use Jar Bundler application as part of its Xcode Developer Tools that allows you to make a double-clickable application bundle that contains all the needed jar and other resources for your application. Every Macintosh computer comes with a free copy of Xcode; however, it may not be installed on your system by default. If it is on your system, you can find the Jar Bundler application in the /Developer/Applications/Java Tools folder. If you do not have the Developer folder at the root of the hard drive on your system, you can download the latest version of the Xcode Developer Tools free from the Apple Developer Connection web page at http://connect.apple.com. Launch the Jar Bundler tool. It presents a single dialog box that has the Build Information screen highlighted. Enter the appropriate “Main Class” and “Arguments to Main” and feel free to associate the custom program icon that you may have created, which will show in the dock when your application is running, as seen in Figure 14-2.

Figure 14-2

259

Chapter 14 Select the Classpath and Files tab, and add your application’s jar file and the HME SDK jar files. This will automatically add the proper corresponding Classpath entries, as seen in Figure 14-3.

Figure 14-3

Select the Properties tab, and select “Set Working Directory to Inside Application Package.” This allows you to place all your graphical resources inside of the jar bundle and have them be located easily by your application. You can also set a Version Number, Build Number (Identifier), Bundle Name (for the About Screen), and tweak other VM options as needed, as seen in Figure 14-4. Click the Create Application... button, choose a target location for your application bundle to be deposited, and then click Create. This deposits the new application bundle in the target location.

260

Deploying an HME Application

Figure 14-4

Final Touches If you have gone through all the preceding steps and noticed that your application continuously bounces in the dock until you start the application on the TiVo box, there is a quick, albeit unintuitive, fix for this behavior. Starting a Swing or AWT window will cause the application to appear “fully started” to the Jar Bundler and will cause the application to stop bouncing. Typically the easiest way to handle this is to create a splash screen that displays on the host system. The following code is a simple splash screen: package com.wiley.hme.ch14; import java.awt.BorderLayout; import java.awt.Dimension;

261

Chapter 14 import java.awt.Toolkit; import import import import

javax.swing.ImageIcon; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JWindow;

public class SplashScreen extends JPanel { private ImageIcon m_imagecomponent1; private static JPanel jpanel1; public SplashScreen() { createPanel(); } public void display() { JWindow frame = new JWindow(); frame.setSize(600, 400); frame.setLocation(100, 100); frame.getContentPane().add(jpanel1, BorderLayout.CENTER); frame.pack(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension splashSize = new Dimension(486,309); frame.setLocation(screenSize.width/2 - (splashSize.width/2), screenSize.height/2 - (splashSize.height/2)); frame.setVisible(true); try { Thread.sleep(5000); } catch (InterruptedException e) { } frame.setVisible(false); }

public ImageIcon loadImage( String imageName ) { try { ClassLoader classloader = getClass().getClassLoader(); java.net.URL url = classloader.getResource( imageName ); if ( url != null ) { ImageIcon icon = new ImageIcon( url ); return icon; } } catch( Exception e ) {

262

Deploying an HME Application e.printStackTrace(); } throw new IllegalArgumentException( “Unable to load image: “ + imageName ); } public JPanel createPanel() { if (jpanel1 == null) { jpanel1 = new JPanel(); m_imagecomponent1 = loadImage(“welcome.jpg”); JLabel l = new JLabel(m_imagecomponent1); jpanel1.add(l,BorderLayout.CENTER); } return jpanel1; } }

Because the splash screen should be displayed when the application is started on the host system, not on the TiVo box, the splash screen should be kicked off from a custom factory: public static class UsableAppFactory extends Factory implements IFactory { public UsableAppFactory() { super(); new SplashScreen().display(); } }

This causes the application to start up and stop bouncing once the Factory has been created. It solves the problem of the never-ending dock bouncing, and displaying a splash screen is a fairly common occurrence when starting an application, and so remains in line with a user’s expectations of an application starting up.

Packaging Apple recommends that developers make use of disk images to distribute their software bundles to Mac OS X users. Creating a disk image is fairly easy. However, there are a few things you can do to make your packaging have a more professional look and feel. These include creating disk images that are compressed to save distribution bandwidth, utilizing custom background images, disk image icons, and finder views, automatically mounting the disk image when downloaded via a web browser, and also the ability to show license agreements before the image is mounted, if needed.

Creating the Disk Image The first step in creating a professional Mac OS X distribution package is the creation of the disk image (.dmg file) itself. To create a disk image, you need to make use of Disk Utility, which is provided with every version of Mac OS X and can be found in your Applications/Utilities folder. Choose the New Blank Image option from the File New menu in Disk Utility. Disk Utility opens a dialog box that asks you for the specifics needed to create your initial disk image, as seen in Figure 14-5.

263

Chapter 14

Figure 14-5

In this dialog box, set Save As to the name of your new disk image. This is the name that people will see when they mount the image on their computer, as well as the file name that the .dmg file will be saved as. In the Size drop-down list, select a file size that is large enough to hold the target application, as well as any support documents (ReadMe Files, Links to your Website, Software Licenses, Graphic background files, and so on). Setting encryption on your disk image will require that the end user enter a password in order to mount the image. It is highly recommended by the authors that this setting not be set to avoid distribution complexity. Finally, make sure that the initial disk image that you create is read/writable. Select “read/write disk image” from the Format drop-down menu and click the Create button. You will now have a new .dmg file and mounted disk image on your desktop to place all of your application and support files into.

Stylizing the Disk Image Mac OS X allows Disk Images to define how they are shown when mounted in the Finder. You can customize your Disk Image with a custom .dmg and mounted drive image, add custom graphical backdrops to the finder window, and also set the size and display properties of your folder.

264

Deploying an HME Application Custom Disk Icons The easiest modification is adding a customized icon to the .dmg disk image file and the resulting mounted drive. Doing this is fairly straightforward. Find the application Icon (ico file) that you created earlier. Rick-click the ico file and select Get Info from the resulting menu. The Get Info dialog box will open. From this screen you will see some specifics about your file including the icon itself at the top of the dialog box. Click it to give it a blue halo. This means that this file icon is selected. Then from the Edit menu choose Copy to place the image into the Mac OS X clipboard. Get Info on the .dmg file on the desktop and repeat the steps to select the disk image icon. Then from the Edit menu choose Paste to paste the icon image you have in your clipboard into place, as seen in Figure 14-6.

Figure 14-6

265

Chapter 14 To revert the change, simply click the new icon and press Delete on your keyboard. This removes your new icon resource from the file and reverts back to the default icon. Close the dialog box to save the change. Repeat the same steps for any other icons you would like to customize within your bundle.

Custom Finder View You may also want to change the look and feel of the window that opens when your disk image is mounted. You can change the view options such as the background image of the window, font size, and the layout for the icons and toolbars in the finder window. You can place an image as the background of your finder window. Before you make modifications to your finder window view, if you plan on using a background image, create one using your favorite image-editing program and create the backdrop for your folder and save it as a jpeg file. Place the file in a folder inside of your disk image; don’t worry about the visual placement of that folder for now because that folder will be ultimately hidden from the user once you are done. To change the standard view options of the window, simply open the disk image in the finder and use the View menu to hide the toolbar and finder extras around the window. Then go back into the View menu to Show View Options. This will open the View Options dialog box, as seen in Figure 14-7.

Figure 14-7

Select “This window only” to make sure you are not changing the window views for your entire system, and then customize the icon size, text size, label position, and layout of your window. Once you have your layout settled, choose the background you would like for your window. The example shown in Figure 14-7 utilizes a background.jpg file that is inside of the Background folder in my disk image. It also has a custom colored text background label around the application name; selecting the application

266

Deploying an HME Application icon and then using the Color Label option in the Finder’s File menu configures this. Closing the dialog box saves the custom settings for the disk image folders. Finally, if the configuration utilized a background image and folder, you will want to hide this from the end user. To do so, simply rename the Background folder to add a period in front of the file name. From the command prompt in Mac OS X, change the directory to the mounted volume that you just created and rename the folder. Run the command as follows:

$ cd /Volumes/My\ Super\ HME\ Application/ $ mv Background .Background Finder does not show files whose names begin with a period. The view settings will follow the file when the name of its containing directory is changed. To change the file in the future, simply go back to that directory and change the name back to Background, replace the file, and rename it again to .Background.

Compressing and Locking Down the Disk Image Once you have your disk image loaded with all the appropriate files for your application and behaving the way you intended, it is highly suggested to compress the image and lock it down to a read-only state. Return to Disk Utility and choose Convert... from the Images menu. From the following dialog box, navigate to your dmg file and click the Convert button. This opens a dialog box very similar to the one used to create the Disk Image in the first place. By default it will be set to a “Save As” name of disk1 and an “Image Format” of compressed. The file name is not important in this step; you will be converting the disk image again to read-only shortly. Click Convert to compress your disk image to a file called disk1.dmg and place it in the same folder as the source dmg file used to create the compressed image. Now that the image is compressed, you will want to make it read-only so that users cannot easily change the contents and behavior of the disk image. To do this, go back into Disk Utility and again choose Convert... from the Images menu, locate the disk1.dmg file you just created, and this time set the “Save As” file name to a recognizable and distinguishable name. Select an “Image Format” of “read only” and then click Convert to lock down the final compressed disk image for distribution. Once the image is locked down, you can always rename the file to anything you like. Often for ease of download from web sites it is better to rename the document without spaces and to include a version identifier in the file name as well. The authors adopted the naming convention of ApplicationName_ Version_Platform_YearMonthDay.dmg for distributing between downloaded versions of their program AudioFaucet. The mounted disk image will always contain the original name that was chosen when creating the initial image when mounted and opened in the Mac OS X finder.

Launching a Disk Image Automatically Upon Download Once you have your disk image locked down, you may choose to Internet-enable your disk image, meaning that the image will automatically mount itself when a user downloads it from your web page. To Internet-enable a disk image, you will have to make use of a tool provided by Apple called hdiutil.

267

Chapter 14 From the command prompt, type “hdiutil internet-enable –yes ” as follows:

$ hdiutil internet-enable -yes ~/Desktop/MySupperHMEApp_1_OSX_20060923.dmg hdiutil: internet-enable: enable succeeded You can disable the Internet-enable flag by using the same command with a “-no” argument instead. If you make any modifications to your disk image in Disk Utility after setting the Internet-enable flag, the file will revert back to being a normal DMG image and will not auto-open when downloaded from a browser.

Displaying a Software License Agreement Because most applications show a license agreement as part of the installer activities, it might be necessary for a developer to display a software license agreement to users before allowing them access to the mounted DMG image. Apple provides an SDK and instructions on how to do this as part of its free developer program. The SDK, called “Software License Agreements for UIDFs,” can be downloaded from the Apple Developer Connection web site located at http://developer.apple.com/sdk/ index.html.

Windows Native App Packaging a Java application for Windows is a complicated task. Unlike Web Start, jars, or packaging for OS X, there is no single way to approach building a Windows application. There is a vast amount of software available to create Windows native exe applications from jar files. The options covered here are the choices made by the authors when bundling their HME applications for Windows.

Creating an Application Icon You may want to create an icon for the Application and also the Installer used to distribute your application. Each application platform has its own distinct icon format requirements. Windows uses ico format to store application icons. First find the image files that you would like to use as icons. As with Mac OS X, the authors suggest that this image file be similar to that of your application’s “Music, Photos, and More” icon. The best choice is a PNG file with a transparent background, but any graphic file will do. Then simply convert the image to the ico format. Many applications are available to convert png graphic images to ico format. The authors prefer to use a freeware program called Imagicon, which can be found at http://www.deviouscodeworks.co.uk. Once the ico file is created, save it in your resources folder for your application so that you can easily find it in the future when necessary.

268

Deploying an HME Application

Bundler As for Web Start applications, first a jar file must be created with all the classes and resources needed for the application. As with Web Start, all the supporting jars must also be gathered: hme.jar, bananas.jar, hme-host-sample.jar, and any other libraries the application uses. If you are using any external binaries or code in your application, make sure you have the right to redistribute them before they are included with your application’s distribution. Many times you will also be required to include any licenses or other acknowledgments within your application’s documentation package as well. There are a few open source projects that accomplish this sort of bundling, and several commercial products. Xenoage JEStart is an open source project hosted at sourceforge (http://sourceforge.net/projects/ jestart). Xenoage is GPL licensed, so there may be restrictions against commercial use. JPackIt (http:// sourceforge.net/projects/jpackit) is another open source solution, which accomplishes the same task; it is Apache licensed, so it may be more friendly for commercial use. JavaService allows Java programs to be used as a Windows service. It is LGPL licensed, and is available from http://javaservice .objectweb.org/. All of these packagers are good, but some of the commercial packagers allow for additional flexibility. The authors use Exe4j (http://www.ej-technologies.com) for packaging AudioFaucet. Though it’s a commercial product, the exe builder has some very useful features. The exe can be created to contain all the jar files, so that no extra jar files or libraries are needed — everything is contained within the exe file. Exe4j also has options to allow “pass-through” command-line options to the Java JVM. This can be particularly useful if the application may need additional memory for large data sets, or to tweak the behavior of the application using command-line arguments. Exe4j also allows your application to be installed and run as a background Windows service if you choose. Each application has a different workflow for creating executable files for Windows, and the one you choose will likely depend on what level of flexibility is needed for your application, and the level of polish your users will expect.

Installer Most Windows applications come with an installer. Many tools are available to create installation packages. The authors’ choice for generating an installer is Advanced Installer (http://www.advanced installer.com/). Depending on the level of complexity required for the installer, there are free versions up through enterprise versions that can create installers and bundles for both Mac OS X and Windows. The features of the installer will largely be dependent on how much setup is required to be done before the application is started, but in most cases, the free version of Advanced Installer will likely be able to create an installer that can copy an application to the correct place, set up shortcuts in the Start menu, and add any registry keys that are needed. The Nullsoft Scriptable Install System (NSIS) is an open source solution to create installers, and is a powerful and free alternative. NSIS is available from http://nsis.sourceforge.net. Additional steps following the installation of an HME application on Windows will likely require opening up firewall ports so that the HME application can broadcast to the TiVo box, and to allow for the application to run on the TiVo box. David Staas has a great tutorial on setting up firewall exceptions for HME applications, which is available at http://bitrazor.com/content/tivo/hme/howtos/ windowsfirewall/wf.php.

269

Chapter 14

Packaging Normal conventions suggest that developers make use of ZIP archive files to distribute their applications to Windows users. By using a ZIP archive, your application installers will require less disk space and make for easy and quick downloads from your distribution web sites. Creating a ZIP file of the installer application is fairly easy. Windows XP has a built-in ZIP archive file creation tool called Compressed Folders. To create a ZIP archive in Windows XP, right-click the installer application of the folder that contains the application and other supporting documents and select Send To and then Compressed (zipped) Folder from the resulting menu. This will make a compressed ZIP file with a zipper icon with the same name as the file or folder you compressed with the .zip extension in the same directory as the selected contents. In other versions of Windows, you can use many tools that are available for creating ZIP archive files; WinZip is suggested by the authors.

Selling Your Application There are, of course, many options for selling an application as well. A simple PayPal donation link from your site may be all you want to use. For a more complicated sales and registration number system, the eSellerate system is excellent. eSellerate will host the application as well, which saves on bandwidth costs. Integration with Java applications is mildly difficult, but can be accomplished easily enough by using Java Native Interface (JNI) to place calls to the native DLLs or libraries, and eSellerate is available for several platforms.

Summar y Making a Java program into a native-feeling application is really the last mile to getting your application into the hands of your user. Any good application will take into account the user’s experience from downloading to running the application, and should make every effort to make the process work as the user expects. In some cases, the convenience of a Web Start application, which requires nothing to be installed on the user’s system except Java, is the best option. In other cases, an installer and full bundled application is the best route to take. Whatever your application, presenting it with polish both when it is run on the TiVo box and during the installation and startup process will make the application more usable for a wider audience, and will make for happier users.

Questions 1. 2.

270

Why does hme-host-sample.jar need to be modified for use in Web Start? Why would you create a jar for your application?

15 Tips and Troubleshooting No matter how carefully you write an application, or how many unit tests you write to make sure classes are working correctly, there will likely come a time when looking at the application variable while the application is running will be the quickest, and perhaps only, way to fix some troublesome code. Developing in Eclipse makes visual debugging of code pretty simple. Because the source code for the HME SDK and the Bananas library are available from the Sourceforge site, Eclipse can step into the SDK’s code to see how events are being processed in the HME code itself. Eclipse allows for setting break points (places to stop code execution) and for stepping through the code as it is running. To set a breakpoint, select Toggle Line Breakpoint from the Run menu, then run your application from the Run, Debug... menu; the application will stop when the point in code is reached, and allow you to examine variables and visually see the status of the code while the application is running (Figure 15-1). Debugging code is extremely useful while code is under development, and to check on behavior even after development has been completed, but other tools are useful for determining what your users are doing with your application to help sort out any problems or bugs.

Chapter 15

Figure 15-1

Logging Any application that is made available to users will likely run into problems that never happened when the application was being tested. In addition to being a Murphy’s Law scenario, the HME SDK is also sensitive to the configuration of the system it is running on. From the version of Java to network problems, there are a fair amount of unforeseen problems that HME applications come up against when running on machines other than your home system. The HME SDK’s hme-host-sample.jar includes logging classes. The Logging classes are available via the context, but unfortunately do not allow for much flexibility like most modern logging systems do.

Try It Out

Using the Built-in ILogger

The HME SDK has a built-in logging mechanism that any application can access. The messages logged are printed to standard output.

272

Tips and Troubleshooting The logger also supports “levels” that indicate the severity of the messages. ILogger log = getBApp().getContext().getLogger(); log.log(ILogger.LOG_DEBUG, “entering myscreen”);

How It Works The ILogger is created by the hosting environment, and a reference to the logger is saved in the context. Any screen can retrieve the context through the application, and get a reference to the logger object. The preceding code will output the following on the standard output: HME SDK 1.4 (TiVo, Inc.) LOG: added factory MDNS: http://192.168.1.11:7288/ch15/ LOG: 192.168.1.11 icon.png HTTP GET - to factory /ch15/ LOG: HME receiver connected LOG: entering myscreen

The built-in logging can be overridden by extending the com.tivo.hme.host.sample.Main class: package com.wiley.hme.ch15; import java.io.IOException; import com.tivo.hme.host.sample.Main; import com.tivo.hme.host.util.ArgumentList; import com.tivo.hme.interfaces.ILogger; public class AppMain extends Main implements ILogger { public AppMain(ArgumentList arg0) throws IOException { super(arg0); } public void log(int arg0, String arg1) { System.out.println(“AppLog: [“+arg0+”] :” + arg1); } public static void main(String argv[]) throws IOException { new AppMain(new ArgumentList(argv)); } }

The constructor is required to be present because Java requires it. The log() method is the method that must be overridden, and the main() method will be the new entry point into the application (com.wiley.hme.ch15.AppMain instead of the com.tivo.hme.sim.Simulator or com.tivo.hme .host.sample.Main that was previously being used). This update to the logging system will output: AppLog: [2] :added factory MDNS: http://192.168.1.11:7288/ch15/

273

Chapter 15 AppLog: AppLog: AppLog: AppLog: AppLog:

[2] [2] [1] [2] [2]

:192.168.1.11 icon.png HTTP GET - to factory /ch15/ :HME receiver connected :entering myscreen :connection to receiver closed :HME receiver disconnected

Overriding the log() method in this manner, however, can allow for the integration of much more sophisticated logging frameworks, such as Log4J, Apache Jakarta Commons Logging, or Java Logging API, which all have greater flexibility in terms of turning on or off different levels of logging, writing to files, obtaining their configuration from files, and other capabilities that are useful when attempting to get logging information from users of your application.

Common Problems Description

Suggestions

My HME Application doesn’t show up on the TiVo.

Check to see if a firewall on the system is blocking the application. Also make sure that if the system is using multiple interfaces (multiple network cards or addresses), the HME application is using the correct interface. Passing the –intf flag to the Factory with the specific interface will force the HME app to bind to a specific network interface.

The Application starts on the local machine, but says it cannot find the application.

Make sure your application class files or jar file are in the classpath when it is run. If you are running from a Web Start application, check to make sure you updated hmehost-sample.jar.

Images disappear from the TiVo box screen.

This is normally a resource problem — check to make sure you aren’t using too many images or images that are too large.

I’m using MP3 audio, and the application is slow.

MP3 audio decoding uses approximately 30% of the CPU power on the box. Optimizing the resources you are using in the application can help mitigate slowness, but it may not be entirely avoidable.

The application keeps exiting on the TiVo box.

Check the log files on the host system. If Java errors are reported, these are likely the cause. Any Java error the application reports will cause the hosting environment to kill the application. A slow network link between the TiVo box and the application may also cause failures because a constant connection is required between the TiVo box and the HME application. My list shows up onscreen, but nothing is selected, and the keys don’t do anything. Call setFocusDefault() to set the default focused item in the screen. If no default is set, the focus cannot be changed.

274

Tips and Troubleshooting

Additional Resources The TiVo HME SDK comes with a developer guide PDF file. The guide is a quick run-through of the HME environment, and is a good place to look first. The HME SDK and Bananas libraries come with a complete Java Doc documentation package. Though not 100 percent of the methods are explained in the same detail, there is good information available in the Java Doc as well as a complete listing of the classes that make up the HME SDK. The HME SDK home page is http://tivohme.sourceforge.net/, and additional TiVo developer information is posted at http://www.tivo.com/developer. The HME developer mailing list is also a good resource to bounce ideas off other HME developers, and get clarification on any questions you may have. Finally, the “HME Developers Corner” forum at http://www.tivocommunity.com is a great place to ask questions.

Summar y Having a good understanding of how the HME SDK works will assist you in tracking down problems in your application. Logging is an important consideration when developing your application — tracking down errors that a user of your application is running into is much easier when your application is able to provide a log of what is going wrong.

275

A Exercise Answers Chapter 1 1.

TiVo HMO was designed as a simple and standardized user interface for accessing music and photos stored on a personal computer within the household network or a server hosted on the Internet. Because the user interface on the TiVo itself was templates, all music and photo applications that pushed their content to the TiVo box shared the same look and feel. TiVo HME gives developers the freedom to design user interfaces, feature sets, and application display behavior to meet their specific needs.

2.

TiVo HME does not allow the overlay of information over any video content nor does it allow access specifically as part of the SDK to use or manipulate program data or recording preferences on the TiVo box.

Chapter 2 1.

The TiVo HMO and HME feature set is enabled in software for use on the Series2 and Series3 hardware references platforms. However, DirectTV has chosen to software-disable USB ports on its Series2 boxes in an attempt to protect their content; therefore, DirectTV receivers with TiVo built in cannot make use of any network-enabled applications.

2.

TiVo enables network applications with any paid TiVo service. This includes Lifetime and Monthly subscription options. TiVo does not enable network applications with the free minimized TiVo Basic service that is included by some third-party manufacturers.

3.

Music, Photos, Products, & More.

Chapter 3 1.

The hme.jar and hme-host-sample.jar are needed to run HME applications. They must be part of your Eclipse project or your CLASSPATH to be able to compile and run Java code for your HME application.

Part #: Part Title 2.

All HME applications are essentially a server program using an IP communications link to the TiVo box. Running the HME application using the correct network interface ensures that the TiVo box can see and communicate with the application.

3.

MDNS (Multicast Domain Name Resolution) is the technology that an HME application, running on a computer, utilizes to announce the availability of the application to the TiVo box. Without MDNS, the TiVo box would not display the application in the “Music, Photos, Products & More” menu.

Chapter 4 1.

An HME application responds to a key press by overriding the handleKeyPress() method to receive the message from the receiver that a remote control button was pressed.

2.

The handleActive() method and the destroy() method are called when an application is closing. The destroy() method is always called, even when a warp key is used to exit the application, whereas the handleActive() method is called only when the application is exited by calling setActive(false).

3.

A custom icon can be set by placing a PNG graphic named icon.png in the root directory of the application CLASSPATH with the dimensions 34px X 26px. A custom name for the application may be set by defining the public String TITLE in the Application class.

Chapter 5 1. 2.

The text color is set when the text resource is created.

3.

Built-in sounds are retrieved using getResource() and played using the play() method in HMEObject. Custom resources are created using createSound().

A view determines the alignment of the text. This is because the view defines where the text will be on the screen, and so is responsible for setting the alignment of its contents.

Chapter 6 1.

The sendEvent() method communicates with the TiVo box, while the Ticker callbacks run a thread on the host system.

2.

handleIdle() informs the application that the TiVo box is about to time out to live TV. The

application can take action to perform screensaver-type animation at this point.

278

3.

The application will not see any KEY_FORWARD or KEY_REVERSE events that are sent to handleKeyPress() because those events are handled, and true is returned. The application will see all other key events. Although there is code for KEY_SELECT, the handleKeyPress() method still returns false, so it too is sent to the application’s handleEvent() method.

4.

The SDK will send an event to whichever view has focus. Both views could receive the event if, for example, viewA was the parent of viewB and viewB did not handle the KEY_SELECT event, or chose to pass it to the parent view as well.

Chapter #: Chapter Title Chapter 7 1.

BList cannot be instantiated directly. It is an abstract class, so BList must be subclassed in order to be used.

2.

The BApplication subclass’s init() method should call the superclass’s init() method as the first action in the init() method. This is because the BApplication’s implementation of init() creates the layers used when setting up an application. If init() is not called, NullPointer Exceptions will likely be thrown when the application is run.

3.

The setBarAndArrows() method takes as parameters the actions the button will take for the up, down, left, and right keys. In order to be managed by the focus manager, the H_UP, H_DOWN, H_LEFT, and H_RIGHT constants indicate that focus manager should process the key to move the focus in the screen.

Chapter 8 1.

An Action is a type of BEvent used in Bananas to pass control between widgets, BViews, and BScreens.

2.

Like HME, events first enter the Bananas toolkit via the dispatchEvent() method. BApplication overrides the HME Application’s dispatchEvent() to gain access to the event stream.

3.

sendEvent() sends an event on a round trip to the TiVo box whereas postEvent() drops the

event immediately into the event processing system on the local machine without sending the event on a round trip to the TiVo box.

Chapter 9 1.

The HME runtime environment will create a new connection to retrieve streamed resources, separate from the application’s connection.

2.

The HME Simulator includes an interactive hierarchical view system to aid developers with the process of optimizing their user interfaces. There is also an HME runtime debug mode that allows a developer to see exactly which resources within their application are not being directly rendered in hardware and could possibly be causing a degradation of performance.

Chapter 10 1.

The main reasons for overriding the factory are: ❑

Changing the name of the application dynamically



Using the factory for storing shared data



Handling arguments to the application



Allowing access to files outside the classpath

279

Part #: Part Title 2.

The code will not function properly. Because the factory does not follow the naming convention Factory, and the application has no getAppFactory() method, the default factory will end up being used. The application’s init() method will receive a class cast exception when it attempts to cast the default factory to the custom factory because the custom factory could not be found and the default factory was created.

3.

A thread started in the application will run only while the application is running on the TiVo box (assuming it is terminated correctly), and a thread started in the Factory will run even after all TiVo boxes have exited the application.

4.

The HmeEvent.InitInfo event will contain the data that determines if the application was started as part of a transition or directly by the TiVo box.

Chapter 11 1.

Global preferences are a good idea if the same data is going to be shared among all instances of the application. It is not a good idea to use global preferences when deploying a server-based HME application, as any user who accesses the application could change the preference information.

2.

In general, the Factory would not be able to save or retrieve data from the SDK’s persistent data calls. The setPersistentData() and getPersistentData() methods are part of the Context object, which is not created until an application is started on the TiVo box.

Chapter 12 1.

Calling getResource(“*500,0”) will return a Resource object that represents an animation. This resource can be passed to any method that accepts an animation. The “*” part of the string indicates to getResource() that an animation resource must be generated, the 500 portion of the string indicates the animation should last for 500 milliseconds, and the 0 portion of the string tells HME that the animation will take place linearly (not accelerate or decelerate).

2.

The following properties of HME objects may be animated:

3.

280



Changing the bounds of a view



Changing the scaling factor of a view



Changing the translation of a view



Changing the transparency of a view



Changing the visibility of a view



Removing a view



Sending an event

Animated Events allows events to be sent back to your HME application after a specified period of time. These are most commonly used for chaining animations.

Exercise Answers Chapter 13 1.

Saving resources locally allows for manipulating data for use on the TiVo box. In particular, resizing images to avoid resource errors is a prime example of an advantage of saving data locally.

Chapter 14 1.

Web Start does not allow an application to use the system classloader, which is used by the com.tivo.hme.host.sample.Main class. To function with Web Start’s security restrictions, the classloader must be changed.

2.

Creating a jar file allows for more efficient bundling of all the class files and image files in your application. For downloadable Web Start applications, it will also improve download time as jars can be compressed.

281

Index

Index

Index

A above.jpg file, 124 Action class, 161, 164–166 add method, 142–143 Adobe, 7 alert.snd sound file, 93 aligning images RSRC_HALIGN_CENTER flag, 89 RSRC_HALIGN_LEFT flag, 89 RSRC_HALIGN_RIGHT flag, 89 RSRC_VALIGN_CENTER flag, 89 RSRC_VALIGN_LEFT flag, 89 RSRC_VALIGN_RIGHT flag, 89 aligning text, 76–77 animated GIF files, 80 animations applying to HME SDK objects, 234–235 chaining, 238–239 creating, 233–234 for events, 105, 238 moving views, 235, 236 overview, 233 as resources, 105, 233–235 scaling graphics, 237 transitioning between screens, 234–235 for transparency, 236–237 visibility property, 237 Ant (Java development tool), 10, 32–33 Apache Axis language, 246, 247

Apple. See also Mac OS X hdiutil tool, 267–268 iPhoto application, 244 Jar Bundler tool, 259–261 Application class. See also applications; BApplication class init method in, 48, 49 relationship of BApplication class to, 118, 122 relationship to HMEObject class, 73 applicationInfo event, 96, 97 applications. See also Hello World BWeatherApp to BTrafficApp transition example, 217–219 calling, 215–220 changing names, 206–207 creating, 47–49 creating icons for, 258 deploying, 253–270 distributing, 253–270 error handling, 58 events example, 101–104 exiting, 57, 58 lifecycle, 57–58, 202, 204 MPEG vs. JPEG example, 188–190, 192–193 obtaining ID, 228 overriding Factory class, 201, 202–211 packaging for Mac OS X, 258–268 packaging for Windows users, 268–270 per-application preferences, 227–230 per-TiVo preferences, 223–226

applications (continued) applications (continued) role of factory, 203 role of singletons, 210–211 running events, 57–58 running in HME Simulator, 50–53 selling, 270 setting TiVo-hosted icon and name for, 55 shutting down, 58 Simon Says, 106, 107–112, 187–188, 205 starting, 57, 202 starting on TiVo box, 53–56 stopping dock bouncing, 261–263 stopping threads on exit, 214–215 TiVo server-hosted, 23, 24 transitioning back, 220 transitioning to, 215–217 troubleshooting, 274 weather example, 69–71 Web Start launcher, 255–258 Apps.tv web site, 9 arc directory, 41 arguments, handling in factory, 207–208 AudioFaucet, 9, 114, 201, 210, 228, 240–242, 248 Axis language, 246, 247

B Bananas action events in, 164–166 defined, 10, 117 documentation, 275 including in applications, 117–119 mapping keyboard keys to TiVo remote control, 120–121 new events, 161–163 reasons to use, 119 relationship to HME SDK, 117, 118–119 sample application, 119–121 using events in, 159–178 bananas.jar file, 117, 118, 124 BApplication class default handling of sounds, 124–125 event handling in, 159, 160 relationship to BScreens, 125, 127, 129, 130–131, 134 relationship to HME Application class, 118, 122 and skins feature, 125 BButtons, 147–149, 165

286

BDirSkin subclass, 155 below.jpg file, 124 BEvents Action subclass, 164–166 customizing, 166–170 inner classes, 161–163 BKeyboards e-mail keyboard, 149, 150, 153–154 event handling in, 160 example, 151–153 plain keyboard, 149, 150 types of keyboards, 149–150, 153 using, 151 BLists code examples, 139–142 and focus, 144–146 hanging style, 138 and HSQLDB database, 248–250 illustrated, 137 managing lists, 139 methods, 142–144 vs. other widgets, 138 overview, 136–137 radio button example, 166–170 relationship to BScreens, 138, 140 styling, 138–139 using, 138 blue.mpg file, 184, 188–190 bonk.snd sound file, 93 bouncing, stopping, 261–263 BResSkin subclass, 155–157 BScreens event handling in, 160, 161 new methods, 126–127 overview, 125–126 popping, 127–128 pushing, 127–128 relationship of BLists to, 138, 140 relationship to BApplication class, 125, 127, 129, 130–131, 134 role of subclassing, 128 screen transitions, 129 BSkin class, 154–157 BText, 146–147 BTrafficApp application adding transitioning capabilities, 216–217 running in Eclipse, 217–218 transitioning to, 217–219

buffer, pixel and resource management, 191, 194–195 Simulator display, 70–71 build path, 52, 53 bundlers Apple Jar Bundler tool, 259–261 for Windows native applications, 269 bundles, defined, 258. See also bundlers burn-in, preventing, 97, 114 buttons. See also BButtons hanging styles, 148 selected vs. unselected, 166–170 buttonView subclass, 112–114 BViews dog.jpg example, 135–136 event handling in, 159, 160 overview, 134–136 relationship to HME View class, 134 setting bounds, 235 BWeatherApp application adding transitioning capabilities, 216 converting to use Java preferences, 229–230 custom factory for, 202–203, 205 handling arguments, 207–208 naming, 206, 207 persistent data store, 224, 226 running in Eclipse, 218–219 threads in, 212 transitioning from, 217–219 using factory for shared data, 208–210 using per-application preferences, 227–228 BWeatherApp class, defined, 171 BWeatherAppFactory class, 203, 207, 208 BWeatherAppFactory_NotFoundAutomatically class, 205 BZipSkin subclass, 155

C cable TV, 16 CableCard standard, 16 certificates, 257 chaining animations, 238–239 .class files, 253 class names, obtaining, 228 classes, creating, 48–49 classloader, 205, 257

classpath and BResSkin, 155 icon file in, 55 in ImageResource example, 82, 83, 84, 85 in overriding Factory, 205, 206, 207 overview, 31–32 troubleshooting, 274 TrueType fonts in, 75 clear method, 143 CLEAR remote control button, 196 clearResource method, 191 Clock application, running from Eclipse, 44 com directory, 42 compressing disk images, 267 com.tivo.hme.host.sample.Main class, 41, 44, 202 concurrency. See threads Console tab, Eclipse, 50, 218 contains method, 143 Context object, 58, 223 CPU, in TiVo boxes, 1, 14, 15, 197–198 createAnimation method, 233 createFont method, 74–75, 76 createImage method, 84–85, 206, 245 createResource method, 234 createSound method, 92–93 createStream method, 179–180 createText method, 73–74, 79 custom actions, 164–166 custom events, 105 custom factories, 202–203, 205 custom screen transitions, 130–134 custom widgets, 166–170

D databases, 248–250 debugging software rendering, 196–197 default font, 72, 73, 75 default sounds, 93 descriptor files, 255 deselect.snd sound file, 93 destroy method, 58 DeviceInfo event, 96–97, 186 DHCP (Dynamic Host Configuration Protocol), 21, 22 digital video recorder (DVR), TiVo as, 1 DirectTV-integrated TiVo, 15–16

287

Index

DirectTV-integrated TiVo

disk images disk images adding customized icons for, 265–266 compressing, 267 creating, 258, 263–264 customizing finder window, 266–267 displaying software license agreements, 268 Internet-enabling, 267–268 locking down, 267 naming convention, 267 renaming files, 267 stylizing, 264–267 Disk Utility compressing disk images, 267 creating custom icons, 265–266 creating disk images, 263–264 locking down disk images, 267 stylizing disk images, 264–267 dispatchEvent method, 57 DMG files. See disk images dock bouncing, stopping, 261–263 dog.jpg file, 80–82, 85, 135–136 Duck Creek, 257 DVD drives, 15 DVR (digital video recorder), TiVo as, 1 Dynamic Host Configuration Protocol (DHCP), 21, 22

text editor in, 30 viewing output, 50 workspace, defined, 41 e-mail keyboard, 149, 150, 153–154 error.snd sound file, 93 Ethernet, 2, 15, 16, 20, 21, 198 events animating, 234, 238 and Bananas, 159–178 Bananas model for handling, 159–163 chaining animations, 238–239 custom, 105 example, 101–104 focus, 112–114, 161 handling, 56–57 Idle event, 114–115 key events, 57–58, 96, 98–100 “left key,” 56–57 new in Bananas, 161–163 passing along, 57 queuing, 105 role of Ticker, 106–112 running in HME applications, 57–58 types, 95–98 extending views, 67–68 Extensible Markup Language (XML), 246, 248

E

F

Eclipse (Java development tool) adding external jars, 124 Console tab, 50, 218 creating Hello World application, 47–49 default Java development perspective, 38–39 defined, 10 importing sample applications, 41–44 installing, 34 overview, 33 running, 34–35 running BWeatherApp to BTrafficApp example, 217–219 running Hello World sample application from within, 50–52 setting up, 33–39 starting applications by clicking Debug button, 217–218 starting new projects, 35–39, 41

factories vs. Factory class, 210 handling arguments, 207–208 lifecycle, 58, 208–211 Factory class vs. factories, 210 getAppFactory method, 202, 203, 205 getStream method, 82–83, 205, 206 isActive flag, 215 overriding, 201, 202–211 role in locating files and resources, 205–206 storing application ID, 228 ways of obtaining, 202 Fandango, 9, 24 FFMPEG encoder, 182–183 FileInputStream class, 85 filterbuilder.jar file, 175 flush method, 211

288

focus events, 112–114, 161 in lists, 144–146 setting, 66, 68 FontInfo event, 96, 98 fonts default, 72, 73, 75 geodesic.ttf, 76, 101 as resource, 74–76, 79 system, 72, 75 TrueType, 72, 75–77 Fonts class, 73 formats, file animated GIF, 80 GIF, 80 JPEG, 4, 80, 182, 183, 186, 187–189 PNG, 55, 80, 182, 183, 186, 268

G Galleon, 9 games, 24 geodesic.ttf font, 76, 101 get method, 143 getAbove method, 122, 126 getAppFactory method, 202, 203, 205 getAppTitle method, 207 getBelow method, 122, 126 getBounds method, 64 getContext method, 225 getCurrentConditions method, 177 getCurrentScreen method, 122, 130 getFocus method, 126, 143 getFocusDefault method, 126 getForecast method, 177 getHeight method, 64 getImageUrl method, 177 getLocation method, 64 getMemento method, 97 getNormal method, 122, 126 getNVisibleRows method, 143 getPainting method, 66 getParams method, 97 getPersistentData method, 224, 229 getResource method, 184, 191, 233, 244, 245, 246 getRoot method, 183 getRow method, 143

getRowHeight method, 143 getScaleX method, 65 getScaleY method, 65 getSize method, 64 getSkin method, 122 getStackDepth method, 122, 130 getStream method, 82–83, 205, 206, 243 getTop method, 143 getTranslation method, 65 getTranslationX method, 65 getTranslationY method, 65 getTransparency method, 66 getValue method, 207 getVisible method, 66 getWidth method, 64 getX method, 64 getY method, 64 getZipCode method, 211 GIF files, 80 GIF images vs. MPEG images, 187–188 GPL (GNU General Public License), 2 graphics. See image resources

H hacks, TiVo, 2 handleAction method in BApplication class, 122, 126 in BButtons, 148, 209–210 in BScreens, 126 handling action events, 164, 165 in WeatherScreen class, 216 handleActive method, 58, 93, 97, 217, 225 handleApplicationError method, 58 handleEnter method in BScreens, 126, 161, 163 changing, 214, 245–246 in WeatherScreen class, 174, 209, 216 handleError method, 93, 97 handleEvent method in BScreen, 126 in BTrafficApp application, 217 for custom events, 105 in events example, 101, 103, 104 for key events, 98 in running events, 57, 58 in Simon Says application, 107

289

Index

handleEvent method

handleExit method handleExit method, 126, 161, 163 handleFocus method, 112, 114, 126, 143, 144, 146 handleIdle method, 93 handleKeyPress method in BScreens, 128 finding list of keys, 57 in focus event example, 114 in Hello World application, 56, 58 and key events, 96, 98 overriding, 68 processing KEY_SELECT button, 165, 166 in WeatherScreen class, 174 handleKeyRelease method, 58, 96, 98 handleKeyRepeat method, 58, 96, 98 handlePing method, 93 hard drive, in current generation of TiVo, 1 hasFocus method, 66, 112 Haynes, Carl, 183 HD recording, 16, 17 hdiutil tool, 267–268 Hello World creating, 47–49 exiting using TiVo remote, 54 handleKeyPress method, 58 handling HME events, 56–57 running in HME Simulator, 50–53 running on TiVo box, 53–56 Hessian/Burlap, 251 highlight bar, generating, 138 hme-host-sample.jar file, 31, 37, 124, 257, 272 HME Simulator. See Simulator hme.jar file, 31, 37, 124 HmeObject class, 56–57, 61, 73–74, 79, 92–93 HMO. See TiVo HMO Home Media Engine (HME). See TiVo HME Home Media Option (HMO). See TiVo HMO hosting environment customizing, 201 overriding Factory class, 201 saving per-TiVo preferences, 223–226 household networks adding TiVo boxes to, 2, 21–23 configuring TiVo for, 19–23 network adapters for, 20–21 wired vs. wireless, 2, 20 HSQLDB database, 248–250

290

htmllexer.jar file, 175 HTMLParser library, 175 htmlparser.jar file, 175

I IArgumentList interface, 207 ICNS files, 258 ICO files, 268 Icon application, 258, 265–266 icon.png file, 55, 56 icons creating for Hello World application, 55 creating for Mac OS X applications, 258 creating for Windows applications, 268 customizing for disk images, 265–266 IContext interface, 224 IDEA (Java development tool), 33 Idle event, 114–115 IdleInfo event, 96, 97 IHighlightsLayout interface, 138 IHmeEventHandler interface, 61 IHmeProtocol interface, 61 ILogger interface, 273 image resources aligning, 89 creating, 80–87 defined, 80 formats supported, 80 resizing, 88, 244–246 scaling, 88–89, 237 streaming, 179–180 ImageIcon class, 85, 245 ImageResource class, 80, 183 Imagicon, 268 import statements, 49, 118 indexOf method, 143 init method. See also super.init method in Application class, 48 application example, 223, 225 in BWeatherApp application, 209, 229 in creating text resources, 73 vs. handleActive method, 217 handling command-line arguments in factory, 207 and threads, 215 initFactory method, 205 InitInfo event, 96, 97, 217, 220

input system, in current generation of TiVo, 1 Installer, Windows, 269 installing Eclipse, 34 interfaces IArgumentList, 207 IContext, 224 IHighlightsLayout, 138 IHmeEventHandler, 61 IHmeProtocol, 61 ILogger, 273 IP address settings, 22–23 iPhoto application, 244 isActive flag, 215 isApplicationClosing method, 215 iTunes, 210

J J2EE/EJB, 251 jar bundles, creating, 259–261 jar files creating, 254 creating Windows applications from, 268–270 libraries for building HME applications, 31, 37 role in packaging Java code, 253–255 for running Simulator, 51, 52 signing, 257 for WeatherFeedReader class, 175 in Web Start applications, 255 Java checking Linux for SDK, 29 checking Mac OS X for SDK, 29 checking UNIX for SDK, 29 checking Windows for SDK, 28 creating Hello World application, 47–49 J2EE/EJB, 251 JDBC class, 248–250 MyJavaTools library, 247 preference system, 228–230 recommended libraries and tools for, 32–33 RMI, 251 SDK for HME, 10–11 threads in, 211–215 version issues, 174 in weather application example, 170–174 Web Start application launcher, 255–258 Java archives, 31, 253. See also jar files

.java files, 253 Java Preference API, 228 java.awt.toolkit, 82 JavaHMO, 7–8. See also Galleon JavaZoom, 180 JBuilder (Java development tool), 33 JDBC class, 248–250 JDIC (Java Desktop Integration Components), 33 jdom.jar file, 175 JEdit, 30 JINI, 251 JLayerME MP3 decoder, 180 JNLP files, 255, 256–258 JNLP Wrapper, 257 JPEG files, 4, 80, 182, 183, 186, 187–189 JRiver Media Center, 7 jukeboxes, 7 JUnit tool, 33 justifying text, 76

K key events, 57–58, 96, 98–100 KEY_ADVANCE constant, 99 keyboard example, 165–166 KEY_CHANNELDOWN constant, 99 KEY_CHANNELUP constant, 99 KEY_CLEAR constant, 99 KEY_DISPLAY constant, 99 KEY_DOWN constant, 98 KEY_ENTER constant, 99 KEY_FORWARD constant, 99 KEY_INFO constant, 99 KEY_LEFT constant, 57, 61, 99 KEY_LIVETV* constant, 99 KEY_MUTE constant, 99 KEY_NUM0 constant, 99 KEY_NUM1 constant, 99 KEY_NUM2 constant, 99 KEY_NUM3 constant, 99 KEY_NUM4 constant, 99 KEY_NUM5 constant, 100 KEY_NUM6 constant, 100 KEY_NUM7 constant, 100 KEY_NUM8 constant, 100 KEY_NUM9 constant, 100 KEY_OPT_ANGLE constant, 100

291

Index

KEY_OPT_ANGLE constant

KEY_OPT_ASPECT constant KEY_OPT_ASPECT constant, 100 KEY_OPT_DVD constant, 100 KEY_OPT_EXIT constant, 100 KEY_OPT_GUIDE constant, 100 KEY_OPT_LIST constant, 100 KEY_OPT_MENU constant, 100 KEY_OPT_PIP constant, 100 KEY_OPT_STOP constant, 100 KEY_OPT_TOP_MENU constant, 100 KEY_OPT_WINDOW constant, 100 KEY_PAUSE constant, 99 KEY_PLAY constant, 99 KEY_RECORD constant, 99 KEY_REPLAY constant, 99 KEY_REVERSE constant, 99 KEY_RIGHT constant, 99 KEY_SELECT constant, 99, 165 KEY_SLOW constant, 99 keystores, 257 KEY_THUMBSDOWN constant, 99 KEY_THUMBSUP constant, 99 KEY_TIVO constant, 98, 105, 238 KEY_UNKNOWN constant, 98 KEY_UP constant, 98 KEY_VOLUMEDOWN constant, 99 KEY_VOLUMEUP constant, 99

L lastIndexOf method, 143 layers, in BApplication class, 122–124 left.snd sound file, 93 license agreements, 268, 269 lifecycles application, 57–58 factories vs. applications, 208 Lifetime TiVo Service, 17 Linux operating system as base TiVo operating system, 2 checking for Java SDK, 29 running Bananas sample application, 119 running classpath, 31 running jar file applications, 254 runsamples.sh script file, 40–41 storing persistent data, 225 listening for focus events, 112–114 Live 365 application, 9, 24

292

locking down disk images, 267 log method, 273–274 Log4j tool, 33 logger, 272–274

M Mac OS X checking for Java SDK, 29 creating distribution packages for users, 263–268 customizing finder window, 266–267 launching Simulator applications, 51 packaging applications for, 258–268 running Bananas sample application, 119 running classpath, 31 running jar file applications, 254 runsamples.sh script file, 40–41 storing persistent data, 225 Map, device info event, 96–97 MDNS announcements, 40, 41, 50, 56 memory, pixel, 191, 194–195 MKLOOP FFMPEG wrapper, 182–183 mkloop files, 182–183 modem, in current generation of TiVo, 1 MoodLogic, 7 moving views, 235, 236 MP3 files, 4, 179, 180–181, 197 MPEG-2 Encoder/Decoder chip, in current generation of TiVo, 1 MPEG video backgrounds creating, 182–183 and DeviceInfo event, 186 GIF images vs. MPEG images, 187–188 hardware decoding, 196 vs. JPEG, 186, 187, 188–190 minimizing changes, 191 overview, 181 and root view, 190 setting, 183–184 and Simulator, 184–187 MPEG vs. JPEG application example comparing views, 188–190 viewing resource tree, 192–193 MPEGs, in Simulator, 46 MPEGs vs. JPEGs, 186, 187, 188–190, 192 Multi-Room Viewing, 3

Music, Photos, Products, & More screen, 23, 41, 54, 55, 206 music, TiVo access to, 3, 4, 6, 7, 206 MyJavaTools library, 247

N NetBeans (Java development tool), 10, 33 NetFlix, 247 network adapters and CPU resources, 197 for household networks, 20–21 wired vs. wireless, 2, 20–21 networking, 2, 16 New Music Tuesday, 7 Nikon Photo application, 7 NOAA Web site, 89 normal.jpg file, 124 Notepad, 30

O

Picasa, 7 pixel buffer, 70–71, 191, 194–195 pixel memory, 194–195 play method, 92–93, 181 PNG files, 55, 80, 182, 183, 186, 268 Podcaster, 24 pop method, 122, 127, 129, 130, 134 popping BScreens, 127–128, 129 postEvent method, 96, 104, 164 preferences Java system, 228–230 Java vs. HME SDK, 230 other methods of saving, 230–231 per-application, 227–230 per-TiVo, 223–226 processors. See CPU, in TiVo boxes ProductWatch application, 198 push method, 122, 127, 130, 134, 161, 209, 210 push transition, 234, 235 pushing BScreens, 127–128, 129 Python language, 246

OptionItem class, 168

P Package Explorer, 38, 47, 52, 55 package names, obtaining, 228 pagedown.snd sound file, 93 pageup.snd sound file, 93 painting, suspending, 63, 66 parse method, 177 pause method, 181 per-application preferences, 227–230 per-TiVo application preferences, 223–226 persistent data how it is stored, 225–226 overview, 223–224 and per-application preferences, 227–228 retrieving, 224–225 setting, 224–225 perspectives, 38, 39 phone line, circumventing, 2 photo shoebox software, 7 photocasts, 244 photos, TiVo access to, 3, 4, 6, 7, 206 PHP language, 246–247

R RadioButtonGroup class, 166, 169 reboots, system, 19, 183, 191, 196 refresh method, 143 remote control as element of TiVo hardware, 1 and key events, 98–100 left key event handling, 56–57 mapping keyboard keys to, 120–121 simulating commands in Simulator, 46 remote method invocation (RMI), 251 remove method, 143, 191 rendering best practices, 195–196 and pixel memory, 195 software debug mode, 196–197 resizing images, 88, 244–246 resource tree, 192–193 ResourceInfo event, 96 resources animations as, 105, 233–235 best practices, 195–196 caching vs. re-creating, 191

293

Index

resources

resources (continued) resources (continued) CPU and other concerns, 197–198 creating, 73–74 custom loading strategies, 83 debugging software rendering, 196–197 defined, 61 as destination of events, 96 displaying, 61–94 external, connecting to, 243–251 external, retrieving and saving locally, 244–246 images as, 80–91 managing, 191–198 MPEG video backgrounds, 191–198 network constraints, 197–198 observing limitations, 193–194 overview, 49 removing, 191 setting as URLs, 82, 84, 180, 193, 205, 243–244 Simon Says application, 112 streaming, 179–181 text as, 72–80 TiVo box limitations, 191 transparent, 196 views as, 61–71 restarting TiVo box, 19, 183, 191, 196 right.snd sound file, 93 RMI (remote method invocation), 251 Rome RSS parser, 175, 247 rome-0.8.jar file, 175 root view, 49, 62, 63, 70, 190 RSRC_HALIGN_CENTER flag, 89 RSRC_HALIGN_LEFT flag, 89 RSRC_HALIGN_RIGHT flag, 89 RSRC_IMAGE_BESTFIT flag, 88 RSRC_IMAGE_HFIT flag, 88 RSRC_IMAGE_VFIT flag, 88 RSRC_VALIGN_CENTER flag, 89 RSRC_VALIGN_LEFT flag, 89 RSRC_VALIGN_RIGHT flag, 89 RSS data, 175, 177, 205, 212, 246, 247 Ruby language, 246 Runnable interface, 212 runsamples.bat script file, 40–41 runsamples.sh script file, 40–41

294

S SAFE_ACTION_H constant, 71 SAFE_ACTION_V constant, 71 SAFE_TITLE_H constant, 70 SAFE_TITLE_V constant, 70 SameGame, 24 samples directory, 41 satellite decoder. See DirectTV-integrated TiVo saving per-TiVo preferences, 223–226. See also preferences scaling images overview, 88–89 role of animation, 237 RSRC_IMAGE_BESTFIT flag, 88 RSRC_IMAGE_HFIT flag, 88 RSRC_IMAGE_VFIT flag, 88 scaling views, 65, 237 ScreenEnter event, 161 ScreenExit event, 161 script files runsamples.bat, 40–41 runsamples.sh, 40–41 select button, 112, 127, 165, 166 select.snd sound file, 93 sendEvent method, 105, 164, 238, 239 Series1 standalone TiVo box, 14 Series2 DT (Dual Tuner) TiVo box, 15 Series2 standalone TiVo box, 15, 198 Series3 standalone TiVo box, 16–17 set method, 143 setActive method, 57 setBarAndArrows method, 138, 139, 143, 147–148, 216 setBounds method, 64, 235 setFocus method, 66, 68, 127, 144 setFocusDefault method, 127 setLocation method, 64 setPainting method, 66 setPersistentData method, 224, 227, 229 setResource method, 76, 79, 80, 92, 183, 194, 205 setScale method, 65, 237 setSize method, 64 setSkin method, 122 setSpeed method, 181 setTranslation method, 65

setTransparency method, 66, 236 setVisible method, 63, 66, 237 setZipCode method, 208 signing jars, 257 Simon Says application GIF vs. MPEG images, 187–188 ThumbsAway-on.gif image, 205 and Ticker event, 106, 107–112 Simulator accessing resource tree, 192–193 command-line arguments, 45 connecting to Bananas sample application, 119 in direct mode, 50–52 in discovery mode, 50–52 and JPEG background image, 186, 187, 188, 189 limitations, 46 mapping keyboard keys to TiVo remote control, 120–121 and MPEG video backgrounds, 184–187 overview, 44–46 running, 44–45 running Hello World sample application in, 50–53 simulating TiVo remote control commands, 46 testing TiVo HME applications, 44–45 viewing MPEG vs. JPEG application example, 192–193 simulator.jar file, 44–46, 50, 51, 52 singletons, 210–211 size method, 144 Skull & Bones game, 24 slowdown1.snd sound file, 93 SOAP (Simple Object Access Protocol), 246–247 software license agreements, 268, 269 sound resources built-in, 93 creating, 92–93 default sounds, 93 not attached to views, 92 in Simon Says application, 112 SoundResource object, 92–93 speedup1.snd sound file, 93 speedup2.snd sound file, 93 speedup3.snd sound file, 93 splash screens in AudioFaucet, 210, 240 creating, 261–263

SQL databases, 248 StackFrame object, 131, 134 stacks, 122, 123, 125, 128, 130–134, 161–163 Strangeberry, 8 streaming resources audio, 180–181 graphics, 179–180 MP3 files, 179, 180–181 overview, 179 security issues, 206 StreamResource class, 181 String object, 166, 224–225, 230 stylizing disk images, 264–267 subclassing views, 67–68 subscriptions, TiVo, 17 Subversion tool, 33 super.init method, 49, 124, 225 system font, 72, 75 system reboots, 19, 183, 191, 196

T TCP/IP settings, 21, 22–23 television sets. See TV screens text editors, for editing Java code, 30 text resources aligning, 76–77 creating, 72–80 defined, 72 justifying, 76 TextMate, 30 Thread object, 212 threads Java 4 vs. Java 5, 212–213 overview, 211 stopping on application exit, 214–215 thumbelina.jar file, 175 ThumbsAway-off.gif image, 187 ThumbsAway-off.mpg image, 187 ThumbsAway-on.gif image, 205 thumbsdown.snd sound file, 93 THUMBSUP remote control button, 196 thumbsup.snd sound file, 93, 165 tick method, 106, 112 Ticker class, 106–112, 239 timeouts, 97, 114

295

Index

timeouts

titles titles changing for applications, 206–207 setting for applications, 55 TiVo Basic service subscription, 17 TiVo boxes accessing files and resources, 205–206 adding to household networks, 2, 21–23 CPU resources, 1, 197–198 current models, 13–17 determining software version, 17–18 forcing connection to TiVo servers, 18–19 integrated, 15–16 platform overview, 1–2 running Hello World on, 53–56 saving per-TiVo preferences, 223–226 SDK for HME, 10–11 software development history, 2–8 standalone, 14, 15, 16–17 system updates, 18–19 testing and running transitions between applications, 219 timeouts, 97, 114 user interface, 2, 3, 4, 7, 11, 154, 190 TiVo Central Online, 3 TiVo Connect, 6 TiVo Desktop, 3, 4–5 TiVo HME auto discovery, 8 available applications, 8–9 and broadband Internet connection, 19 creating Hello World application, 47–49 downloading SDK, 30 event handling, 56–57 exploring SDK, 30–31, 201 history, 2 vs. HMO, 8 host environment, 44 interaction with TiVo, 11–12 limitations, 11–12 main class, 44 network access, 8 overview, 8–9 protocol documentation, 11 running SDK at command line, 31–32 sample applications, 39–44 SDK documentation, 275

296

SDK overview, 10–11 software development kit, 10–11 TiVo HMO activation fee, 2, 3 applications, 7–8 desktop applications, 7–8 history, 2, 3 protocol, 6 server-hosted applications, 7 TiVo Plus service subscription, 17 TiVo Service Number (TSN), 225–226 TiVo2Comeback, 198 TiVo2Go, 198 TiVo-branded wireless adapters, 2, 20, 21 TiVo.com, 3 tivo.snd sound file, 93 traffic application. See BTrafficApp application transitionBack method, 220 transitionForward method, 215 transitioning among applications BWeatherApp to BTrafficApp example, 217–219 from one to another, 215–217 returning to original application, 220 transitions, screen custom, creating, 130–134 TRANSITION_FADE, 129 TRANSITION_LEFT, 129 TRANSITION_NONE, 129 using animations, 234–235 translate method, 65 translating views, 64–65 transparency animating, 236–237 best practices, 196 setting, 66 troubleshooting applications, 274 TrueType fonts, 72, 75–77 TSN (TiVo Service Number), 225–226 TV screens defining viewing area, 70 preventing burn-in, 97, 114

U Uniform Resource Locators (URLs) setting resources as, 82, 84, 180, 193, 205, 243–244

updown.snd sound file, 93 USB ports in current generation of TiVo, 1 resource concerns, 197–198 in Series2 TiVo box, 15, 198

V Van Hoff, Arthur, 8 video output, in current generation of TiVo, 1 View class, 49, 61, 96, 112–114, 134 views animating transparency, 236–237 applying animations to, 234 creating, 61–62 defining TV screen area, 70–71 dog.jpg example, 80–82, 85 drawing order, 63 extending, 67–68 hiding, 63 hierarchy, 61–62, 63 maximum number, 195 moving, 235, 236 overview, 61–66 properties, 64 scaling, 65, 237 setting invisibility, 63, 66, 237 in Simon Says application, 112 specifying coordinates, 62 subclassing, 67–68 suspending painting, 63, 66 translating, 64–65 and video backgrounds, 183 in weather example, 69–71 visibility animating, 237 setting, 63, 66, 237

W warp keys, 58 weather application. See also BWeatherApp application code for, 69–71 NOAA Web site, 89 outside libraries, 175

updating with graphics, 89–91 updating with separate class files, 170–178 updating with text, 77–79 WeatherFeedReader class, 174, 175–177, 247 WeatherModel class, 79 WeatherScreen class, 173–174, 209–210, 212, 213 Web data Apps.tv web site, 9 as external resource, 243–246 NOAA Web site, 89 Web Start applications creating jar files, 269 overview, 255 using with HME, 256–258 WEP (Wired Equivalency Privacy), 20, 22 widgets, defined, 117. See also BKeyboards; BLists; BText Wi-Fi networks, 2, 20, 22 Wi-Fi Protected Access (WPA), 20, 22 Windows checking for Java SDK, 28 launching Simulator applications, 51 packaging applications for, 268–270 running Bananas sample application, 119–120 running classpath, 31–32 running jar file applications, 254 runsamples.bat script file, 40–41 storing persistent data, 225 Windows Installer, 269 Windows Media Center PC vs. TiVo platform, 1 wired connections advantages, 20 network adapters, 20–21 setting up, 21–22 Wired Equivalency Privacy (WEP), 20, 22 wireless connections network adapters, 2, 20–21 resource constraints, 197–198 setting up, 2, 22 vs. wired networks, 20 Wordsmith, 24 workspace, Eclipse, 41 World Wide Web. See Web data WPA (Wi-Fi Protected Access), 20, 22

297

Index

WPA (Wi-Fi Protected Access)

XML (Extensible Markup Language)

X

Z

XML (Extensible Markup Language), 246, 248

ZeroConf, 8 ZIP archives, for packaging applications for Windows users, 270 Zip codes, 208–211, 217, 226 ZipScreen class, 171–173, 209, 210, 226, 227, 229–230

Y Yahoo accounts, 9, 24 Yahoo! Photos, 24 Yahoo! Traffic, 24, 215 Yahoo! Weather, 24, 175, 205, 212, 247

298

Programmer to Programmer TM BROWSE BOOKS

P2P FORUM

FREE NEWSLETTER

ABOUT WROX

Get more Wrox

at Wrox.com! Special Deals

Free Chapter Excerpts

Take advantage of special offers every month

Be the first to preview chapters from the latest Wrox publications

Unlimited Access. . .

Forums, Forums, Forums

. . . to over 70 of our books in the Wrox Reference Library (see more details on-line)

Take an active role in online discussions with fellow programmers

Meet Wrox Authors! Read running commentaries from authors on their programming experiences and whatever else they want to talk about

Browse Books .NET SQL Server Java

XML Visual Basic C#/ C++

Join the community! Sign-up for our free monthly newsletter at newsletter.wrox.com